llm-beacon 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.
- llm_beacon-0.1.0/.claude/launch.json +11 -0
- llm_beacon-0.1.0/.gitattributes +6 -0
- llm_beacon-0.1.0/.github/ISSUE_TEMPLATE/bug_report.md +21 -0
- llm_beacon-0.1.0/.github/ISSUE_TEMPLATE/feature_request.md +13 -0
- llm_beacon-0.1.0/.github/pull_request_template.md +8 -0
- llm_beacon-0.1.0/.github/workflows/ci.yml +107 -0
- llm_beacon-0.1.0/.github/workflows/docs.yml +69 -0
- llm_beacon-0.1.0/.github/workflows/release.yml +69 -0
- llm_beacon-0.1.0/.gitignore +17 -0
- llm_beacon-0.1.0/CHANGELOG.md +32 -0
- llm_beacon-0.1.0/CONTRIBUTING.md +72 -0
- llm_beacon-0.1.0/Cargo.lock +342 -0
- llm_beacon-0.1.0/Cargo.toml +45 -0
- llm_beacon-0.1.0/LICENSE +21 -0
- llm_beacon-0.1.0/PKG-INFO +211 -0
- llm_beacon-0.1.0/README.md +166 -0
- llm_beacon-0.1.0/benches/determinism_overhead.py +99 -0
- llm_beacon-0.1.0/clippy.toml +3 -0
- llm_beacon-0.1.0/docs/blocks_reference.md +373 -0
- llm_beacon-0.1.0/docs/determinism_guarantees.md +119 -0
- llm_beacon-0.1.0/docs/integrations.md +144 -0
- llm_beacon-0.1.0/docs/plan.md +145 -0
- llm_beacon-0.1.0/docs/quickstart.md +94 -0
- llm_beacon-0.1.0/docs/snapshot_testing.md +130 -0
- llm_beacon-0.1.0/examples/01_basic_template.py +33 -0
- llm_beacon-0.1.0/examples/02_structured_output.py +53 -0
- llm_beacon-0.1.0/examples/03_pipeline_composition.py +65 -0
- llm_beacon-0.1.0/examples/04_langchain_rag.py +54 -0
- llm_beacon-0.1.0/examples/05_llamaindex_query.py +38 -0
- llm_beacon-0.1.0/examples/06_pydantic_ai_agent.py +40 -0
- llm_beacon-0.1.0/examples/07_dspy_optimization.py +55 -0
- llm_beacon-0.1.0/examples/08_snapshot_testing_your_app.py +76 -0
- llm_beacon-0.1.0/examples/snapshots/app/cancel.yaml +20 -0
- llm_beacon-0.1.0/examples/snapshots/app/hallucinated_intent.yaml +14 -0
- llm_beacon-0.1.0/examples/snapshots/app/prompt.yaml +3 -0
- llm_beacon-0.1.0/examples/snapshots/app/refund_in_prose.yaml +16 -0
- llm_beacon-0.1.0/examples/snapshots/app/truncated.yaml +11 -0
- llm_beacon-0.1.0/pyproject.toml +73 -0
- llm_beacon-0.1.0/python/beacon/__init__.py +92 -0
- llm_beacon-0.1.0/python/beacon/_api.py +357 -0
- llm_beacon-0.1.0/python/beacon/_beacon_native.pyi +62 -0
- llm_beacon-0.1.0/python/beacon/_blocks.py +126 -0
- llm_beacon-0.1.0/python/beacon/_yaml.py +173 -0
- llm_beacon-0.1.0/python/beacon/errors.py +211 -0
- llm_beacon-0.1.0/python/beacon/integrations/__init__.py +15 -0
- llm_beacon-0.1.0/python/beacon/integrations/_common.py +67 -0
- llm_beacon-0.1.0/python/beacon/integrations/dspy.py +142 -0
- llm_beacon-0.1.0/python/beacon/integrations/langchain.py +174 -0
- llm_beacon-0.1.0/python/beacon/integrations/llamaindex.py +61 -0
- llm_beacon-0.1.0/python/beacon/integrations/openai_sdk.py +150 -0
- llm_beacon-0.1.0/python/beacon/integrations/pydantic_ai.py +74 -0
- llm_beacon-0.1.0/python/beacon/py.typed +0 -0
- llm_beacon-0.1.0/python/beacon/pytest_plugin.py +65 -0
- llm_beacon-0.1.0/python/beacon/retry.py +207 -0
- llm_beacon-0.1.0/python/beacon/snapshots.py +312 -0
- llm_beacon-0.1.0/rustfmt.toml +2 -0
- llm_beacon-0.1.0/snapshots/extract_json/array_of_objects.yaml +12 -0
- llm_beacon-0.1.0/snapshots/extract_json/bare_array.yaml +13 -0
- llm_beacon-0.1.0/snapshots/extract_json/bare_object.yaml +11 -0
- llm_beacon-0.1.0/snapshots/extract_json/big_integer.yaml +11 -0
- llm_beacon-0.1.0/snapshots/extract_json/citations_only.yaml +11 -0
- llm_beacon-0.1.0/snapshots/extract_json/citations_then_object.yaml +11 -0
- llm_beacon-0.1.0/snapshots/extract_json/comment_in_json.yaml +13 -0
- llm_beacon-0.1.0/snapshots/extract_json/crlf_line_endings.yaml +11 -0
- llm_beacon-0.1.0/snapshots/extract_json/deeply_nested.yaml +16 -0
- llm_beacon-0.1.0/snapshots/extract_json/duplicate_keys.yaml +11 -0
- llm_beacon-0.1.0/snapshots/extract_json/empty_containers.yaml +12 -0
- llm_beacon-0.1.0/snapshots/extract_json/empty_string.yaml +8 -0
- llm_beacon-0.1.0/snapshots/extract_json/escaped_strings.yaml +15 -0
- llm_beacon-0.1.0/snapshots/extract_json/fence_and_prose_example.yaml +15 -0
- llm_beacon-0.1.0/snapshots/extract_json/floats.yaml +14 -0
- llm_beacon-0.1.0/snapshots/extract_json/indented_fence.yaml +11 -0
- llm_beacon-0.1.0/snapshots/extract_json/json_fence_with_language_suffix.yaml +14 -0
- llm_beacon-0.1.0/snapshots/extract_json/json_in_sentence_with_braces.yaml +10 -0
- llm_beacon-0.1.0/snapshots/extract_json/leading_zero.yaml +11 -0
- llm_beacon-0.1.0/snapshots/extract_json/literal_newline_in_string.yaml +13 -0
- llm_beacon-0.1.0/snapshots/extract_json/lone_surrogate.yaml +11 -0
- llm_beacon-0.1.0/snapshots/extract_json/markdown_fence_basic.yaml +17 -0
- llm_beacon-0.1.0/snapshots/extract_json/multiline_preamble.yaml +20 -0
- llm_beacon-0.1.0/snapshots/extract_json/multiple_objects.yaml +11 -0
- llm_beacon-0.1.0/snapshots/extract_json/nan_value.yaml +11 -0
- llm_beacon-0.1.0/snapshots/extract_json/nested_object.yaml +14 -0
- llm_beacon-0.1.0/snapshots/extract_json/no_json.yaml +8 -0
- llm_beacon-0.1.0/snapshots/extract_json/only_whitespace.yaml +8 -0
- llm_beacon-0.1.0/snapshots/extract_json/python_literals.yaml +11 -0
- llm_beacon-0.1.0/snapshots/extract_json/single_quotes.yaml +11 -0
- llm_beacon-0.1.0/snapshots/extract_json/template_braces_then_json.yaml +11 -0
- llm_beacon-0.1.0/snapshots/extract_json/tilde_fence.yaml +14 -0
- llm_beacon-0.1.0/snapshots/extract_json/trailing_comma.yaml +11 -0
- llm_beacon-0.1.0/snapshots/extract_json/trailing_prose_basic.yaml +12 -0
- llm_beacon-0.1.0/snapshots/extract_json/truncated_nested.yaml +11 -0
- llm_beacon-0.1.0/snapshots/extract_json/truncated_object.yaml +11 -0
- llm_beacon-0.1.0/snapshots/extract_json/two_fences.yaml +18 -0
- llm_beacon-0.1.0/snapshots/extract_json/unclosed_fence_truncated.yaml +13 -0
- llm_beacon-0.1.0/snapshots/extract_json/unclosed_fence_valid.yaml +13 -0
- llm_beacon-0.1.0/snapshots/extract_json/unicode_keys.yaml +13 -0
- llm_beacon-0.1.0/snapshots/extract_json/unlabelled_fence.yaml +15 -0
- llm_beacon-0.1.0/snapshots/extract_json/unquoted_value.yaml +11 -0
- llm_beacon-0.1.0/snapshots/hash/empty_values.yaml +6 -0
- llm_beacon-0.1.0/snapshots/hash/llm_result.yaml +6 -0
- llm_beacon-0.1.0/snapshots/hash/numbers.yaml +6 -0
- llm_beacon-0.1.0/snapshots/hash/pinned_digests.yaml +9 -0
- llm_beacon-0.1.0/snapshots/hash/unicode.yaml +6 -0
- llm_beacon-0.1.0/snapshots/integrations/langchain_callback_records.yaml +27 -0
- llm_beacon-0.1.0/snapshots/normalize/accents_lowercase.yaml +9 -0
- llm_beacon-0.1.0/snapshots/normalize/compatibility_chars.yaml +7 -0
- llm_beacon-0.1.0/snapshots/normalize/emoji_sequences.yaml +7 -0
- llm_beacon-0.1.0/snapshots/normalize/invalid_form.yaml +10 -0
- llm_beacon-0.1.0/snapshots/normalize/llm_output_spacing.yaml +7 -0
- llm_beacon-0.1.0/snapshots/normalize/no_normalization_form.yaml +8 -0
- llm_beacon-0.1.0/snapshots/normalize/paragraphs.yaml +11 -0
- llm_beacon-0.1.0/snapshots/normalize/rtl_mixed.yaml +7 -0
- llm_beacon-0.1.0/snapshots/normalize/smart_quotes_and_dashes.yaml +7 -0
- llm_beacon-0.1.0/snapshots/normalize/zero_width_soup.yaml +7 -0
- llm_beacon-0.1.0/snapshots/parse_tool_call/anthropic_tool_use.yaml +9 -0
- llm_beacon-0.1.0/snapshots/parse_tool_call/bracket_json.yaml +9 -0
- llm_beacon-0.1.0/snapshots/parse_tool_call/bracket_kv.yaml +9 -0
- llm_beacon-0.1.0/snapshots/parse_tool_call/data_not_call.yaml +8 -0
- llm_beacon-0.1.0/snapshots/parse_tool_call/hermes.yaml +12 -0
- llm_beacon-0.1.0/snapshots/parse_tool_call/hermes_truncated.yaml +11 -0
- llm_beacon-0.1.0/snapshots/parse_tool_call/hermes_two_calls.yaml +11 -0
- llm_beacon-0.1.0/snapshots/parse_tool_call/json_bad_arguments_string.yaml +11 -0
- llm_beacon-0.1.0/snapshots/parse_tool_call/json_in_fence.yaml +13 -0
- llm_beacon-0.1.0/snapshots/parse_tool_call/llama_builtin.yaml +9 -0
- llm_beacon-0.1.0/snapshots/parse_tool_call/llama_json.yaml +9 -0
- llm_beacon-0.1.0/snapshots/parse_tool_call/mistral_list.yaml +9 -0
- llm_beacon-0.1.0/snapshots/parse_tool_call/mistral_v11.yaml +9 -0
- llm_beacon-0.1.0/snapshots/parse_tool_call/openai_message_tool_calls.yaml +12 -0
- llm_beacon-0.1.0/snapshots/parse_tool_call/openai_tool_call_item.yaml +9 -0
- llm_beacon-0.1.0/snapshots/parse_tool_call/plain_answer.yaml +8 -0
- llm_beacon-0.1.0/snapshots/parse_tool_call/python_kwargs.yaml +10 -0
- llm_beacon-0.1.0/snapshots/parse_tool_call/python_nested_literals.yaml +15 -0
- llm_beacon-0.1.0/snapshots/parse_tool_call/python_no_args.yaml +8 -0
- llm_beacon-0.1.0/snapshots/parse_tool_call/python_positional.yaml +8 -0
- llm_beacon-0.1.0/snapshots/parse_tool_call/xml_invoke.yaml +16 -0
- llm_beacon-0.1.0/snapshots/pipeline/cancel_trace.yaml +18 -0
- llm_beacon-0.1.0/snapshots/redact/custom_terms.yaml +16 -0
- llm_beacon-0.1.0/snapshots/redact/jwt_and_ip.yaml +16 -0
- llm_beacon-0.1.0/snapshots/redact/log_line_with_secrets.yaml +20 -0
- llm_beacon-0.1.0/snapshots/redact/near_misses.yaml +8 -0
- llm_beacon-0.1.0/snapshots/redact/private_key_block.yaml +23 -0
- llm_beacon-0.1.0/snapshots/redact/support_ticket.yaml +24 -0
- llm_beacon-0.1.0/snapshots/redact/unicode_context.yaml +16 -0
- llm_beacon-0.1.0/snapshots/retry/backoff_schedule.yaml +30 -0
- llm_beacon-0.1.0/snapshots/retry/status_table.yaml +63 -0
- llm_beacon-0.1.0/snapshots/template/bad_spec.yaml +14 -0
- llm_beacon-0.1.0/snapshots/template/basic.yaml +9 -0
- llm_beacon-0.1.0/snapshots/template/extra.yaml +14 -0
- llm_beacon-0.1.0/snapshots/template/literal_json_skeleton.yaml +8 -0
- llm_beacon-0.1.0/snapshots/template/missing.yaml +13 -0
- llm_beacon-0.1.0/snapshots/template/multiline.yaml +15 -0
- llm_beacon-0.1.0/snapshots/template/numbers.yaml +10 -0
- llm_beacon-0.1.0/snapshots/template/raw_and_escaped.yaml +8 -0
- llm_beacon-0.1.0/snapshots/template/unicode_values.yaml +9 -0
- llm_beacon-0.1.0/snapshots/template/unmatched.yaml +13 -0
- llm_beacon-0.1.0/snapshots/template/xml_injection.yaml +8 -0
- llm_beacon-0.1.0/snapshots/test_snapshots/test_pytest_fixture.yaml +4 -0
- llm_beacon-0.1.0/snapshots/validate_schema/intent_invalid.yaml +30 -0
- llm_beacon-0.1.0/snapshots/validate_schema/intent_missing_fields.yaml +28 -0
- llm_beacon-0.1.0/snapshots/validate_schema/intent_valid.yaml +24 -0
- llm_beacon-0.1.0/snapshots/validate_schema/intent_wrong_types.yaml +30 -0
- llm_beacon-0.1.0/snapshots/validate_schema/nested_array_errors.yaml +33 -0
- llm_beacon-0.1.0/snapshots/validate_schema/one_of_ambiguous.yaml +13 -0
- llm_beacon-0.1.0/snapshots/validate_schema/optional_nested.yaml +22 -0
- llm_beacon-0.1.0/snapshots/validate_schema/strict_object.yaml +16 -0
- llm_beacon-0.1.0/snapshots/validate_schema/string_limits.yaml +16 -0
- llm_beacon-0.1.0/snapshots/validate_schema/unsupported_keyword.yaml +11 -0
- llm_beacon-0.1.0/src/convert.rs +261 -0
- llm_beacon-0.1.0/src/error.rs +143 -0
- llm_beacon-0.1.0/src/extract_json.rs +442 -0
- llm_beacon-0.1.0/src/hash.rs +201 -0
- llm_beacon-0.1.0/src/json.rs +540 -0
- llm_beacon-0.1.0/src/lib.rs +314 -0
- llm_beacon-0.1.0/src/normalize.rs +187 -0
- llm_beacon-0.1.0/src/parse_tool_call.rs +876 -0
- llm_beacon-0.1.0/src/redact.rs +421 -0
- llm_beacon-0.1.0/src/retry.rs +314 -0
- llm_beacon-0.1.0/src/template.rs +338 -0
- llm_beacon-0.1.0/src/validate_schema.rs +897 -0
- llm_beacon-0.1.0/src/value.rs +269 -0
- llm_beacon-0.1.0/tests/conftest.py +14 -0
- llm_beacon-0.1.0/tests/test_determinism.py +48 -0
- llm_beacon-0.1.0/tests/test_extract_json.py +287 -0
- llm_beacon-0.1.0/tests/test_hash.py +113 -0
- llm_beacon-0.1.0/tests/test_integration_dspy.py +72 -0
- llm_beacon-0.1.0/tests/test_integration_langchain.py +98 -0
- llm_beacon-0.1.0/tests/test_integration_llamaindex.py +53 -0
- llm_beacon-0.1.0/tests/test_integration_openai.py +140 -0
- llm_beacon-0.1.0/tests/test_integration_pydantic_ai.py +61 -0
- llm_beacon-0.1.0/tests/test_normalize.py +105 -0
- llm_beacon-0.1.0/tests/test_parse_tool_call.py +217 -0
- llm_beacon-0.1.0/tests/test_pipeline.py +101 -0
- llm_beacon-0.1.0/tests/test_redact.py +166 -0
- llm_beacon-0.1.0/tests/test_retry.py +198 -0
- llm_beacon-0.1.0/tests/test_snapshots.py +277 -0
- llm_beacon-0.1.0/tests/test_template.py +175 -0
- llm_beacon-0.1.0/tests/test_validate_schema.py +311 -0
- llm_beacon-0.1.0/website/.gitignore +5 -0
- llm_beacon-0.1.0/website/README.md +27 -0
- llm_beacon-0.1.0/website/astro.config.mjs +95 -0
- llm_beacon-0.1.0/website/package-lock.json +5185 -0
- llm_beacon-0.1.0/website/package.json +22 -0
- llm_beacon-0.1.0/website/public/beacon.wasm +0 -0
- llm_beacon-0.1.0/website/public/favicon.svg +6 -0
- llm_beacon-0.1.0/website/scripts/build-wasm.mjs +21 -0
- llm_beacon-0.1.0/website/scripts/nest-dist.mjs +17 -0
- llm_beacon-0.1.0/website/src/assets/logo.svg +5 -0
- llm_beacon-0.1.0/website/src/components/Playground.astro +826 -0
- llm_beacon-0.1.0/website/src/components/docs/SiteTitle.astro +39 -0
- llm_beacon-0.1.0/website/src/components/landing/Blocks.astro +156 -0
- llm_beacon-0.1.0/website/src/components/landing/Footer.astro +203 -0
- llm_beacon-0.1.0/website/src/components/landing/Guarantees.astro +106 -0
- llm_beacon-0.1.0/website/src/components/landing/Hero.astro +429 -0
- llm_beacon-0.1.0/website/src/components/landing/Integrations.astro +74 -0
- llm_beacon-0.1.0/website/src/components/landing/Nav.astro +157 -0
- llm_beacon-0.1.0/website/src/components/landing/Performance.astro +182 -0
- llm_beacon-0.1.0/website/src/components/landing/Problem.astro +266 -0
- llm_beacon-0.1.0/website/src/components/landing/Setup.astro +149 -0
- llm_beacon-0.1.0/website/src/components/landing/Snapshots.astro +223 -0
- llm_beacon-0.1.0/website/src/components/landing/Try.astro +58 -0
- llm_beacon-0.1.0/website/src/content/docs/blocks/extract-json.mdx +96 -0
- llm_beacon-0.1.0/website/src/content/docs/blocks/hash-content.mdx +47 -0
- llm_beacon-0.1.0/website/src/content/docs/blocks/normalize.mdx +43 -0
- llm_beacon-0.1.0/website/src/content/docs/blocks/parse-tool-call.mdx +81 -0
- llm_beacon-0.1.0/website/src/content/docs/blocks/pipelines.mdx +58 -0
- llm_beacon-0.1.0/website/src/content/docs/blocks/redact.mdx +86 -0
- llm_beacon-0.1.0/website/src/content/docs/blocks/retry.mdx +81 -0
- llm_beacon-0.1.0/website/src/content/docs/blocks/template.mdx +101 -0
- llm_beacon-0.1.0/website/src/content/docs/blocks/validate-schema.mdx +83 -0
- llm_beacon-0.1.0/website/src/content/docs/getting-started/core-concepts.mdx +89 -0
- llm_beacon-0.1.0/website/src/content/docs/getting-started/installation.mdx +93 -0
- llm_beacon-0.1.0/website/src/content/docs/getting-started/introduction.mdx +60 -0
- llm_beacon-0.1.0/website/src/content/docs/getting-started/quickstart.mdx +106 -0
- llm_beacon-0.1.0/website/src/content/docs/guarantees/determinism.mdx +86 -0
- llm_beacon-0.1.0/website/src/content/docs/guarantees/errors.mdx +90 -0
- llm_beacon-0.1.0/website/src/content/docs/integrations/dspy.mdx +57 -0
- llm_beacon-0.1.0/website/src/content/docs/integrations/langchain.mdx +78 -0
- llm_beacon-0.1.0/website/src/content/docs/integrations/llamaindex.mdx +45 -0
- llm_beacon-0.1.0/website/src/content/docs/integrations/openai.mdx +64 -0
- llm_beacon-0.1.0/website/src/content/docs/integrations/overview.mdx +26 -0
- llm_beacon-0.1.0/website/src/content/docs/integrations/pydantic-ai.mdx +48 -0
- llm_beacon-0.1.0/website/src/content/docs/reference/api.mdx +138 -0
- llm_beacon-0.1.0/website/src/content/docs/reference/changelog.mdx +28 -0
- llm_beacon-0.1.0/website/src/content/docs/reference/error-codes.mdx +78 -0
- llm_beacon-0.1.0/website/src/content/docs/snapshots/ci.mdx +64 -0
- llm_beacon-0.1.0/website/src/content/docs/snapshots/overview.mdx +95 -0
- llm_beacon-0.1.0/website/src/content/docs/snapshots/pytest.mdx +66 -0
- llm_beacon-0.1.0/website/src/content.config.ts +7 -0
- llm_beacon-0.1.0/website/src/layouts/Landing.astro +108 -0
- llm_beacon-0.1.0/website/src/middleware.ts +42 -0
- llm_beacon-0.1.0/website/src/pages/404.astro +77 -0
- llm_beacon-0.1.0/website/src/pages/index.astro +30 -0
- llm_beacon-0.1.0/website/src/pages/playground.astro +63 -0
- llm_beacon-0.1.0/website/src/scripts/playground-config.ts +301 -0
- llm_beacon-0.1.0/website/src/site.ts +17 -0
- llm_beacon-0.1.0/website/src/styles/docs.css +184 -0
- llm_beacon-0.1.0/website/src/styles/fonts.css +4 -0
- llm_beacon-0.1.0/website/src/styles/landing.css +404 -0
- llm_beacon-0.1.0/website/tsconfig.json +5 -0
- llm_beacon-0.1.0/website/vercel.json +24 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Bug report
|
|
3
|
+
about: A block returned something unexpected, or behaved differently across runs, machines or versions
|
|
4
|
+
labels: bug
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
**Block and call**
|
|
8
|
+
|
|
9
|
+
```python
|
|
10
|
+
# the exact call, with the exact input (repr() of strings helps with invisible characters)
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
**Expected output**
|
|
14
|
+
|
|
15
|
+
**Actual output** (full exception including `code` and position, if any)
|
|
16
|
+
|
|
17
|
+
**Determinism issue?** Does the output differ between runs, machines, Python versions or beacon versions? Which?
|
|
18
|
+
|
|
19
|
+
**Environment**
|
|
20
|
+
- beacon version (`beacon.__version__`):
|
|
21
|
+
- Python version / OS / CPU:
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Feature request
|
|
3
|
+
about: A new format, keyword, detector, option or integration
|
|
4
|
+
labels: enhancement
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
**What should beacon handle?** Include a real example input (e.g. an LLM response) and the output you expect.
|
|
8
|
+
|
|
9
|
+
**Which block?**
|
|
10
|
+
|
|
11
|
+
**Why can't this be done with existing options?**
|
|
12
|
+
|
|
13
|
+
Note: beacon only adds behaviour that stays deterministic and explicit. Options that "repair" malformed input are out of scope.
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
## What changed
|
|
2
|
+
|
|
3
|
+
## Determinism checklist
|
|
4
|
+
- [ ] No new hidden inputs (clock, env vars, locale, global state)
|
|
5
|
+
- [ ] No `unwrap()`/`expect()`/`panic!` outside tests
|
|
6
|
+
- [ ] Error messages / codes unchanged, or listed under "Behaviour changes" in CHANGELOG.md
|
|
7
|
+
- [ ] Snapshot diffs (if any) are intended and explained here
|
|
8
|
+
- [ ] Tests added
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
|
|
11
|
+
env:
|
|
12
|
+
CARGO_TERM_COLOR: always
|
|
13
|
+
# Snapshot tests run in "check" mode: missing or changed snapshots fail.
|
|
14
|
+
CI: "true"
|
|
15
|
+
|
|
16
|
+
jobs:
|
|
17
|
+
lint:
|
|
18
|
+
name: Python lint (ruff)
|
|
19
|
+
runs-on: ubuntu-latest
|
|
20
|
+
steps:
|
|
21
|
+
- uses: actions/checkout@v4
|
|
22
|
+
- uses: actions/setup-python@v5
|
|
23
|
+
with:
|
|
24
|
+
python-version: "3.12"
|
|
25
|
+
- run: python -m pip install ruff
|
|
26
|
+
- run: ruff check python tests examples benches
|
|
27
|
+
|
|
28
|
+
rust:
|
|
29
|
+
name: Rust (fmt, clippy, unit tests)
|
|
30
|
+
runs-on: ubuntu-latest
|
|
31
|
+
steps:
|
|
32
|
+
- uses: actions/checkout@v4
|
|
33
|
+
- uses: dtolnay/rust-toolchain@stable
|
|
34
|
+
with:
|
|
35
|
+
components: rustfmt, clippy
|
|
36
|
+
- uses: Swatinem/rust-cache@v2
|
|
37
|
+
- run: cargo fmt --check
|
|
38
|
+
- run: cargo clippy --all-targets -- -D warnings
|
|
39
|
+
- run: cargo clippy --all-targets --no-default-features -- -D warnings
|
|
40
|
+
- run: cargo test --no-default-features
|
|
41
|
+
|
|
42
|
+
python:
|
|
43
|
+
name: Python ${{ matrix.python }} on ${{ matrix.os }}
|
|
44
|
+
runs-on: ${{ matrix.os }}
|
|
45
|
+
strategy:
|
|
46
|
+
fail-fast: false
|
|
47
|
+
matrix:
|
|
48
|
+
os: [ubuntu-latest, macos-latest, windows-latest]
|
|
49
|
+
python: ["3.10", "3.11", "3.12", "3.13", "3.14"]
|
|
50
|
+
steps:
|
|
51
|
+
- uses: actions/checkout@v4
|
|
52
|
+
- uses: actions/setup-python@v5
|
|
53
|
+
with:
|
|
54
|
+
python-version: ${{ matrix.python }}
|
|
55
|
+
- uses: dtolnay/rust-toolchain@stable
|
|
56
|
+
- uses: Swatinem/rust-cache@v2
|
|
57
|
+
- name: Build and install wheel
|
|
58
|
+
shell: bash
|
|
59
|
+
run: |
|
|
60
|
+
python -m pip install --upgrade pip maturin pytest pyyaml pydantic
|
|
61
|
+
maturin build --release --out dist
|
|
62
|
+
python -m pip install dist/*.whl
|
|
63
|
+
- name: Tests (snapshots must match byte for byte on every OS)
|
|
64
|
+
run: python -m pytest -p no:cacheprovider
|
|
65
|
+
- name: Overhead benchmark (< 0.5 ms per block)
|
|
66
|
+
run: python benches/determinism_overhead.py --number 500
|
|
67
|
+
|
|
68
|
+
locale:
|
|
69
|
+
name: Locale independence (LANG=C)
|
|
70
|
+
runs-on: ubuntu-latest
|
|
71
|
+
env:
|
|
72
|
+
LANG: C
|
|
73
|
+
LC_ALL: C
|
|
74
|
+
steps:
|
|
75
|
+
- uses: actions/checkout@v4
|
|
76
|
+
- uses: actions/setup-python@v5
|
|
77
|
+
with:
|
|
78
|
+
python-version: "3.12"
|
|
79
|
+
- uses: dtolnay/rust-toolchain@stable
|
|
80
|
+
- uses: Swatinem/rust-cache@v2
|
|
81
|
+
- run: |
|
|
82
|
+
python -m pip install maturin pytest pyyaml pydantic
|
|
83
|
+
maturin build --release --out dist
|
|
84
|
+
python -m pip install dist/*.whl
|
|
85
|
+
python -X utf8 -m pytest -p no:cacheprovider
|
|
86
|
+
|
|
87
|
+
integrations:
|
|
88
|
+
name: Framework integrations
|
|
89
|
+
runs-on: ubuntu-latest
|
|
90
|
+
steps:
|
|
91
|
+
- uses: actions/checkout@v4
|
|
92
|
+
- uses: actions/setup-python@v5
|
|
93
|
+
with:
|
|
94
|
+
python-version: "3.12"
|
|
95
|
+
- uses: dtolnay/rust-toolchain@stable
|
|
96
|
+
- uses: Swatinem/rust-cache@v2
|
|
97
|
+
- run: |
|
|
98
|
+
python -m pip install maturin pytest pyyaml
|
|
99
|
+
maturin build --release --out dist
|
|
100
|
+
python -m pip install dist/*.whl "langchain-core>=1" "llama-index-core>=0.14" "pydantic-ai-slim>=2" "dspy>=3" openai
|
|
101
|
+
- run: python -m pytest -p no:cacheprovider tests/test_integration_*.py
|
|
102
|
+
- name: Examples run offline
|
|
103
|
+
env:
|
|
104
|
+
PYDANTIC_AI_NO_BANNER: "1"
|
|
105
|
+
run: |
|
|
106
|
+
for f in examples/0[1-7]_*.py; do echo "::group::$f"; python "$f"; echo "::endgroup::"; done
|
|
107
|
+
python -m pytest -p no:cacheprovider examples/08_snapshot_testing_your_app.py
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
name: Docs site
|
|
2
|
+
|
|
3
|
+
# Builds the documentation site (Astro + Starlight) and the playground's
|
|
4
|
+
# WebAssembly engine, and deploys to GitHub Pages.
|
|
5
|
+
# One-time setup: Settings → Pages → Source: "GitHub Actions".
|
|
6
|
+
|
|
7
|
+
on:
|
|
8
|
+
push:
|
|
9
|
+
branches: [main]
|
|
10
|
+
paths: ["website/**", "src/**", "Cargo.toml", "Cargo.lock", ".github/workflows/docs.yml"]
|
|
11
|
+
pull_request:
|
|
12
|
+
paths: ["website/**", "src/**"]
|
|
13
|
+
workflow_dispatch:
|
|
14
|
+
|
|
15
|
+
permissions:
|
|
16
|
+
contents: read
|
|
17
|
+
|
|
18
|
+
concurrency:
|
|
19
|
+
group: pages
|
|
20
|
+
cancel-in-progress: false
|
|
21
|
+
|
|
22
|
+
jobs:
|
|
23
|
+
build:
|
|
24
|
+
runs-on: ubuntu-latest
|
|
25
|
+
steps:
|
|
26
|
+
- uses: actions/checkout@v4
|
|
27
|
+
- uses: dtolnay/rust-toolchain@stable
|
|
28
|
+
with:
|
|
29
|
+
targets: wasm32-unknown-unknown
|
|
30
|
+
- uses: Swatinem/rust-cache@v2
|
|
31
|
+
with:
|
|
32
|
+
workspaces: website/wasm
|
|
33
|
+
- uses: actions/setup-node@v4
|
|
34
|
+
with:
|
|
35
|
+
node-version: 22
|
|
36
|
+
cache: npm
|
|
37
|
+
cache-dependency-path: website/package-lock.json
|
|
38
|
+
- id: pages
|
|
39
|
+
uses: actions/configure-pages@v5
|
|
40
|
+
- name: Install
|
|
41
|
+
working-directory: website
|
|
42
|
+
run: npm ci
|
|
43
|
+
- name: Build playground engine (Rust → WebAssembly)
|
|
44
|
+
working-directory: website
|
|
45
|
+
run: npm run wasm
|
|
46
|
+
- name: Build site
|
|
47
|
+
working-directory: website
|
|
48
|
+
env:
|
|
49
|
+
SITE_URL: ${{ steps.pages.outputs.origin }}
|
|
50
|
+
BASE_PATH: ${{ steps.pages.outputs.base_path }}
|
|
51
|
+
PUBLIC_REPO_URL: ${{ github.server_url }}/${{ github.repository }}
|
|
52
|
+
run: npm run build
|
|
53
|
+
- uses: actions/upload-pages-artifact@v3
|
|
54
|
+
with:
|
|
55
|
+
path: website/dist
|
|
56
|
+
|
|
57
|
+
deploy:
|
|
58
|
+
if: github.event_name != 'pull_request'
|
|
59
|
+
needs: build
|
|
60
|
+
runs-on: ubuntu-latest
|
|
61
|
+
permissions:
|
|
62
|
+
pages: write
|
|
63
|
+
id-token: write
|
|
64
|
+
environment:
|
|
65
|
+
name: github-pages
|
|
66
|
+
url: ${{ steps.deployment.outputs.page_url }}
|
|
67
|
+
steps:
|
|
68
|
+
- id: deployment
|
|
69
|
+
uses: actions/deploy-pages@v4
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
# Builds abi3 wheels (one per platform covers Python 3.10+) and an sdist, then
|
|
4
|
+
# publishes to PyPI with trusted publishing when a v* tag is pushed.
|
|
5
|
+
|
|
6
|
+
on:
|
|
7
|
+
push:
|
|
8
|
+
tags: ["v*"]
|
|
9
|
+
workflow_dispatch:
|
|
10
|
+
|
|
11
|
+
permissions:
|
|
12
|
+
contents: read
|
|
13
|
+
|
|
14
|
+
jobs:
|
|
15
|
+
wheels:
|
|
16
|
+
name: Wheels ${{ matrix.platform.target }} (${{ matrix.platform.os }})
|
|
17
|
+
runs-on: ${{ matrix.platform.os }}
|
|
18
|
+
strategy:
|
|
19
|
+
fail-fast: false
|
|
20
|
+
matrix:
|
|
21
|
+
platform:
|
|
22
|
+
- { os: ubuntu-latest, target: x86_64, manylinux: auto }
|
|
23
|
+
- { os: ubuntu-latest, target: aarch64, manylinux: auto }
|
|
24
|
+
- { os: ubuntu-latest, target: x86_64, manylinux: musllinux_1_2 }
|
|
25
|
+
- { os: macos-latest, target: aarch64 }
|
|
26
|
+
- { os: macos-latest, target: x86_64 }
|
|
27
|
+
- { os: windows-latest, target: x64 }
|
|
28
|
+
steps:
|
|
29
|
+
- uses: actions/checkout@v4
|
|
30
|
+
- uses: actions/setup-python@v5
|
|
31
|
+
with:
|
|
32
|
+
python-version: "3.12"
|
|
33
|
+
- uses: PyO3/maturin-action@v1
|
|
34
|
+
with:
|
|
35
|
+
target: ${{ matrix.platform.target }}
|
|
36
|
+
manylinux: ${{ matrix.platform.manylinux }}
|
|
37
|
+
args: --release --out dist
|
|
38
|
+
- uses: actions/upload-artifact@v4
|
|
39
|
+
with:
|
|
40
|
+
name: wheels-${{ matrix.platform.os }}-${{ matrix.platform.target }}-${{ strategy.job-index }}
|
|
41
|
+
path: dist
|
|
42
|
+
|
|
43
|
+
sdist:
|
|
44
|
+
runs-on: ubuntu-latest
|
|
45
|
+
steps:
|
|
46
|
+
- uses: actions/checkout@v4
|
|
47
|
+
- uses: PyO3/maturin-action@v1
|
|
48
|
+
with:
|
|
49
|
+
command: sdist
|
|
50
|
+
args: --out dist
|
|
51
|
+
- uses: actions/upload-artifact@v4
|
|
52
|
+
with:
|
|
53
|
+
name: sdist
|
|
54
|
+
path: dist
|
|
55
|
+
|
|
56
|
+
publish:
|
|
57
|
+
name: Publish to PyPI
|
|
58
|
+
needs: [wheels, sdist]
|
|
59
|
+
runs-on: ubuntu-latest
|
|
60
|
+
if: startsWith(github.ref, 'refs/tags/v')
|
|
61
|
+
environment: pypi
|
|
62
|
+
permissions:
|
|
63
|
+
id-token: write
|
|
64
|
+
steps:
|
|
65
|
+
- uses: actions/download-artifact@v4
|
|
66
|
+
with:
|
|
67
|
+
path: dist
|
|
68
|
+
merge-multiple: true
|
|
69
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to beacon are documented here. beacon follows semantic
|
|
4
|
+
versioning, with the extra compatibility rules in
|
|
5
|
+
[docs/determinism_guarantees.md](docs/determinism_guarantees.md): patch
|
|
6
|
+
releases never change block output, including error messages.
|
|
7
|
+
|
|
8
|
+
Each release lists **Behaviour changes** separately. Those are any
|
|
9
|
+
input whose output differs from the previous release.
|
|
10
|
+
|
|
11
|
+
## [0.1.0] - unreleased
|
|
12
|
+
|
|
13
|
+
First release, published on PyPI as `llm-beacon` (import name `beacon`).
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
|
|
17
|
+
- Blocks, implemented in Rust via PyO3 0.30: `template`, `template_variables`,
|
|
18
|
+
`extract_json`, `extract_json_detailed`, `parse_tool_call`,
|
|
19
|
+
`parse_tool_calls`, `validate_schema`, `schema_errors`, `normalize`,
|
|
20
|
+
`hash_content`, `redact`, `detect_pii`, `retry.classify`,
|
|
21
|
+
`retry.backoff_delay`, `retry.call`.
|
|
22
|
+
- `Pipeline` / `Block` composition with hash traces.
|
|
23
|
+
- Snapshot testing: `assert_snapshot`, pytest `snapshot` fixture,
|
|
24
|
+
`--beacon-snapshot` option, `python -m beacon.snapshots update|check`.
|
|
25
|
+
- Integrations: OpenAI SDK, LangChain, LlamaIndex, Pydantic AI, DSPy.
|
|
26
|
+
- abi3 wheels for CPython 3.10+.
|
|
27
|
+
|
|
28
|
+
### Pinned data versions
|
|
29
|
+
|
|
30
|
+
- Unicode tables: 18.0.0 (`beacon.UNICODE_VERSION`).
|
|
31
|
+
- Canonical hash encoding: v1.
|
|
32
|
+
- Snapshot file format: v1.
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# Contributing to beacon
|
|
2
|
+
|
|
3
|
+
Thanks for helping. Issues and pull requests go to
|
|
4
|
+
[IND-Anshuman/beacon](https://github.com/IND-Anshuman/beacon).
|
|
5
|
+
|
|
6
|
+
beacon's value is its contract: same input, same output, on every machine,
|
|
7
|
+
across versions. Every change is reviewed against
|
|
8
|
+
[docs/determinism_guarantees.md](docs/determinism_guarantees.md).
|
|
9
|
+
|
|
10
|
+
## Setup
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
git clone https://github.com/IND-Anshuman/beacon.git && cd beacon
|
|
14
|
+
python -m venv .venv
|
|
15
|
+
. .venv/bin/activate # Windows: .venv\Scripts\activate
|
|
16
|
+
pip install maturin pytest pyyaml pydantic
|
|
17
|
+
maturin develop # builds the Rust extension into the venv
|
|
18
|
+
pytest
|
|
19
|
+
cargo test --no-default-features # pure-Rust core, no Python needed
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Optional, for the integration tests:
|
|
23
|
+
`pip install langchain-core llama-index-core pydantic-ai-slim dspy openai`.
|
|
24
|
+
|
|
25
|
+
### Windows without Visual Studio Build Tools
|
|
26
|
+
|
|
27
|
+
The default Rust target on Windows (`x86_64-pc-windows-msvc`) needs the MSVC
|
|
28
|
+
linker. If you don't have it, the GNU toolchain works for local development:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
rustup toolchain install stable-x86_64-pc-windows-gnu
|
|
32
|
+
rustup override set stable-x86_64-pc-windows-gnu
|
|
33
|
+
# PyO3's raw-dylib linking needs binutils' `as`, which the GNU toolchain lacks;
|
|
34
|
+
# link against the Python DLL directly instead:
|
|
35
|
+
export PYO3_USE_RAW_DYLIB=0
|
|
36
|
+
export RUSTFLAGS="-L native=<path to your Python install dir containing python3.dll>"
|
|
37
|
+
maturin develop
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Rules for changes
|
|
41
|
+
|
|
42
|
+
1. **No hidden inputs.** Blocks never read the clock, environment variables,
|
|
43
|
+
the locale, files or the network, and they keep no state between calls.
|
|
44
|
+
Every option is an explicit parameter.
|
|
45
|
+
2. **No `unwrap()`/`expect()`/`panic!` in non-test Rust code.** A panic kills
|
|
46
|
+
the user's Python process. Clippy enforces this (`cargo clippy
|
|
47
|
+
--all-targets -- -D warnings`).
|
|
48
|
+
3. **Never repair input silently.** Strict parsing, explicit errors.
|
|
49
|
+
4. **Error messages are API.** Don't change a message or `code` in a patch
|
|
50
|
+
release. New errors and new messages go in a minor release, listed under
|
|
51
|
+
"Behaviour changes" in `CHANGELOG.md`, and are added to the error code
|
|
52
|
+
table in `docs/blocks_reference.md`.
|
|
53
|
+
5. **Snapshot changes need justification.** If `pytest` reports a snapshot
|
|
54
|
+
diff, read it. If the change is intended, run
|
|
55
|
+
`python -m beacon.snapshots update`, commit the updated `.yaml` files, and
|
|
56
|
+
explain the change in the PR.
|
|
57
|
+
6. **Positions are code points.** Anything reported to Python as an offset
|
|
58
|
+
counts Unicode code points, not bytes.
|
|
59
|
+
7. **Tests with every change.** Add unit tests and, for new behaviour, a
|
|
60
|
+
snapshot case in the block's corpus.
|
|
61
|
+
|
|
62
|
+
## Layout
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
src/ Rust core (pure; no pyo3 types) + src/lib.rs, src/convert.rs (bindings)
|
|
66
|
+
python/beacon/ Python package: wrappers, errors, Pipeline, snapshots, integrations
|
|
67
|
+
tests/ pytest suite (unit + snapshot corpora + integrations)
|
|
68
|
+
snapshots/ golden files, compared byte for byte in CI on Linux/macOS/Windows
|
|
69
|
+
benches/ per-block overhead benchmark (< 0.5 ms budget)
|
|
70
|
+
examples/ runnable examples (offline, fake models)
|
|
71
|
+
docs/ user documentation and the determinism contract
|
|
72
|
+
```
|