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.
Files changed (260) hide show
  1. llm_beacon-0.1.0/.claude/launch.json +11 -0
  2. llm_beacon-0.1.0/.gitattributes +6 -0
  3. llm_beacon-0.1.0/.github/ISSUE_TEMPLATE/bug_report.md +21 -0
  4. llm_beacon-0.1.0/.github/ISSUE_TEMPLATE/feature_request.md +13 -0
  5. llm_beacon-0.1.0/.github/pull_request_template.md +8 -0
  6. llm_beacon-0.1.0/.github/workflows/ci.yml +107 -0
  7. llm_beacon-0.1.0/.github/workflows/docs.yml +69 -0
  8. llm_beacon-0.1.0/.github/workflows/release.yml +69 -0
  9. llm_beacon-0.1.0/.gitignore +17 -0
  10. llm_beacon-0.1.0/CHANGELOG.md +32 -0
  11. llm_beacon-0.1.0/CONTRIBUTING.md +72 -0
  12. llm_beacon-0.1.0/Cargo.lock +342 -0
  13. llm_beacon-0.1.0/Cargo.toml +45 -0
  14. llm_beacon-0.1.0/LICENSE +21 -0
  15. llm_beacon-0.1.0/PKG-INFO +211 -0
  16. llm_beacon-0.1.0/README.md +166 -0
  17. llm_beacon-0.1.0/benches/determinism_overhead.py +99 -0
  18. llm_beacon-0.1.0/clippy.toml +3 -0
  19. llm_beacon-0.1.0/docs/blocks_reference.md +373 -0
  20. llm_beacon-0.1.0/docs/determinism_guarantees.md +119 -0
  21. llm_beacon-0.1.0/docs/integrations.md +144 -0
  22. llm_beacon-0.1.0/docs/plan.md +145 -0
  23. llm_beacon-0.1.0/docs/quickstart.md +94 -0
  24. llm_beacon-0.1.0/docs/snapshot_testing.md +130 -0
  25. llm_beacon-0.1.0/examples/01_basic_template.py +33 -0
  26. llm_beacon-0.1.0/examples/02_structured_output.py +53 -0
  27. llm_beacon-0.1.0/examples/03_pipeline_composition.py +65 -0
  28. llm_beacon-0.1.0/examples/04_langchain_rag.py +54 -0
  29. llm_beacon-0.1.0/examples/05_llamaindex_query.py +38 -0
  30. llm_beacon-0.1.0/examples/06_pydantic_ai_agent.py +40 -0
  31. llm_beacon-0.1.0/examples/07_dspy_optimization.py +55 -0
  32. llm_beacon-0.1.0/examples/08_snapshot_testing_your_app.py +76 -0
  33. llm_beacon-0.1.0/examples/snapshots/app/cancel.yaml +20 -0
  34. llm_beacon-0.1.0/examples/snapshots/app/hallucinated_intent.yaml +14 -0
  35. llm_beacon-0.1.0/examples/snapshots/app/prompt.yaml +3 -0
  36. llm_beacon-0.1.0/examples/snapshots/app/refund_in_prose.yaml +16 -0
  37. llm_beacon-0.1.0/examples/snapshots/app/truncated.yaml +11 -0
  38. llm_beacon-0.1.0/pyproject.toml +73 -0
  39. llm_beacon-0.1.0/python/beacon/__init__.py +92 -0
  40. llm_beacon-0.1.0/python/beacon/_api.py +357 -0
  41. llm_beacon-0.1.0/python/beacon/_beacon_native.pyi +62 -0
  42. llm_beacon-0.1.0/python/beacon/_blocks.py +126 -0
  43. llm_beacon-0.1.0/python/beacon/_yaml.py +173 -0
  44. llm_beacon-0.1.0/python/beacon/errors.py +211 -0
  45. llm_beacon-0.1.0/python/beacon/integrations/__init__.py +15 -0
  46. llm_beacon-0.1.0/python/beacon/integrations/_common.py +67 -0
  47. llm_beacon-0.1.0/python/beacon/integrations/dspy.py +142 -0
  48. llm_beacon-0.1.0/python/beacon/integrations/langchain.py +174 -0
  49. llm_beacon-0.1.0/python/beacon/integrations/llamaindex.py +61 -0
  50. llm_beacon-0.1.0/python/beacon/integrations/openai_sdk.py +150 -0
  51. llm_beacon-0.1.0/python/beacon/integrations/pydantic_ai.py +74 -0
  52. llm_beacon-0.1.0/python/beacon/py.typed +0 -0
  53. llm_beacon-0.1.0/python/beacon/pytest_plugin.py +65 -0
  54. llm_beacon-0.1.0/python/beacon/retry.py +207 -0
  55. llm_beacon-0.1.0/python/beacon/snapshots.py +312 -0
  56. llm_beacon-0.1.0/rustfmt.toml +2 -0
  57. llm_beacon-0.1.0/snapshots/extract_json/array_of_objects.yaml +12 -0
  58. llm_beacon-0.1.0/snapshots/extract_json/bare_array.yaml +13 -0
  59. llm_beacon-0.1.0/snapshots/extract_json/bare_object.yaml +11 -0
  60. llm_beacon-0.1.0/snapshots/extract_json/big_integer.yaml +11 -0
  61. llm_beacon-0.1.0/snapshots/extract_json/citations_only.yaml +11 -0
  62. llm_beacon-0.1.0/snapshots/extract_json/citations_then_object.yaml +11 -0
  63. llm_beacon-0.1.0/snapshots/extract_json/comment_in_json.yaml +13 -0
  64. llm_beacon-0.1.0/snapshots/extract_json/crlf_line_endings.yaml +11 -0
  65. llm_beacon-0.1.0/snapshots/extract_json/deeply_nested.yaml +16 -0
  66. llm_beacon-0.1.0/snapshots/extract_json/duplicate_keys.yaml +11 -0
  67. llm_beacon-0.1.0/snapshots/extract_json/empty_containers.yaml +12 -0
  68. llm_beacon-0.1.0/snapshots/extract_json/empty_string.yaml +8 -0
  69. llm_beacon-0.1.0/snapshots/extract_json/escaped_strings.yaml +15 -0
  70. llm_beacon-0.1.0/snapshots/extract_json/fence_and_prose_example.yaml +15 -0
  71. llm_beacon-0.1.0/snapshots/extract_json/floats.yaml +14 -0
  72. llm_beacon-0.1.0/snapshots/extract_json/indented_fence.yaml +11 -0
  73. llm_beacon-0.1.0/snapshots/extract_json/json_fence_with_language_suffix.yaml +14 -0
  74. llm_beacon-0.1.0/snapshots/extract_json/json_in_sentence_with_braces.yaml +10 -0
  75. llm_beacon-0.1.0/snapshots/extract_json/leading_zero.yaml +11 -0
  76. llm_beacon-0.1.0/snapshots/extract_json/literal_newline_in_string.yaml +13 -0
  77. llm_beacon-0.1.0/snapshots/extract_json/lone_surrogate.yaml +11 -0
  78. llm_beacon-0.1.0/snapshots/extract_json/markdown_fence_basic.yaml +17 -0
  79. llm_beacon-0.1.0/snapshots/extract_json/multiline_preamble.yaml +20 -0
  80. llm_beacon-0.1.0/snapshots/extract_json/multiple_objects.yaml +11 -0
  81. llm_beacon-0.1.0/snapshots/extract_json/nan_value.yaml +11 -0
  82. llm_beacon-0.1.0/snapshots/extract_json/nested_object.yaml +14 -0
  83. llm_beacon-0.1.0/snapshots/extract_json/no_json.yaml +8 -0
  84. llm_beacon-0.1.0/snapshots/extract_json/only_whitespace.yaml +8 -0
  85. llm_beacon-0.1.0/snapshots/extract_json/python_literals.yaml +11 -0
  86. llm_beacon-0.1.0/snapshots/extract_json/single_quotes.yaml +11 -0
  87. llm_beacon-0.1.0/snapshots/extract_json/template_braces_then_json.yaml +11 -0
  88. llm_beacon-0.1.0/snapshots/extract_json/tilde_fence.yaml +14 -0
  89. llm_beacon-0.1.0/snapshots/extract_json/trailing_comma.yaml +11 -0
  90. llm_beacon-0.1.0/snapshots/extract_json/trailing_prose_basic.yaml +12 -0
  91. llm_beacon-0.1.0/snapshots/extract_json/truncated_nested.yaml +11 -0
  92. llm_beacon-0.1.0/snapshots/extract_json/truncated_object.yaml +11 -0
  93. llm_beacon-0.1.0/snapshots/extract_json/two_fences.yaml +18 -0
  94. llm_beacon-0.1.0/snapshots/extract_json/unclosed_fence_truncated.yaml +13 -0
  95. llm_beacon-0.1.0/snapshots/extract_json/unclosed_fence_valid.yaml +13 -0
  96. llm_beacon-0.1.0/snapshots/extract_json/unicode_keys.yaml +13 -0
  97. llm_beacon-0.1.0/snapshots/extract_json/unlabelled_fence.yaml +15 -0
  98. llm_beacon-0.1.0/snapshots/extract_json/unquoted_value.yaml +11 -0
  99. llm_beacon-0.1.0/snapshots/hash/empty_values.yaml +6 -0
  100. llm_beacon-0.1.0/snapshots/hash/llm_result.yaml +6 -0
  101. llm_beacon-0.1.0/snapshots/hash/numbers.yaml +6 -0
  102. llm_beacon-0.1.0/snapshots/hash/pinned_digests.yaml +9 -0
  103. llm_beacon-0.1.0/snapshots/hash/unicode.yaml +6 -0
  104. llm_beacon-0.1.0/snapshots/integrations/langchain_callback_records.yaml +27 -0
  105. llm_beacon-0.1.0/snapshots/normalize/accents_lowercase.yaml +9 -0
  106. llm_beacon-0.1.0/snapshots/normalize/compatibility_chars.yaml +7 -0
  107. llm_beacon-0.1.0/snapshots/normalize/emoji_sequences.yaml +7 -0
  108. llm_beacon-0.1.0/snapshots/normalize/invalid_form.yaml +10 -0
  109. llm_beacon-0.1.0/snapshots/normalize/llm_output_spacing.yaml +7 -0
  110. llm_beacon-0.1.0/snapshots/normalize/no_normalization_form.yaml +8 -0
  111. llm_beacon-0.1.0/snapshots/normalize/paragraphs.yaml +11 -0
  112. llm_beacon-0.1.0/snapshots/normalize/rtl_mixed.yaml +7 -0
  113. llm_beacon-0.1.0/snapshots/normalize/smart_quotes_and_dashes.yaml +7 -0
  114. llm_beacon-0.1.0/snapshots/normalize/zero_width_soup.yaml +7 -0
  115. llm_beacon-0.1.0/snapshots/parse_tool_call/anthropic_tool_use.yaml +9 -0
  116. llm_beacon-0.1.0/snapshots/parse_tool_call/bracket_json.yaml +9 -0
  117. llm_beacon-0.1.0/snapshots/parse_tool_call/bracket_kv.yaml +9 -0
  118. llm_beacon-0.1.0/snapshots/parse_tool_call/data_not_call.yaml +8 -0
  119. llm_beacon-0.1.0/snapshots/parse_tool_call/hermes.yaml +12 -0
  120. llm_beacon-0.1.0/snapshots/parse_tool_call/hermes_truncated.yaml +11 -0
  121. llm_beacon-0.1.0/snapshots/parse_tool_call/hermes_two_calls.yaml +11 -0
  122. llm_beacon-0.1.0/snapshots/parse_tool_call/json_bad_arguments_string.yaml +11 -0
  123. llm_beacon-0.1.0/snapshots/parse_tool_call/json_in_fence.yaml +13 -0
  124. llm_beacon-0.1.0/snapshots/parse_tool_call/llama_builtin.yaml +9 -0
  125. llm_beacon-0.1.0/snapshots/parse_tool_call/llama_json.yaml +9 -0
  126. llm_beacon-0.1.0/snapshots/parse_tool_call/mistral_list.yaml +9 -0
  127. llm_beacon-0.1.0/snapshots/parse_tool_call/mistral_v11.yaml +9 -0
  128. llm_beacon-0.1.0/snapshots/parse_tool_call/openai_message_tool_calls.yaml +12 -0
  129. llm_beacon-0.1.0/snapshots/parse_tool_call/openai_tool_call_item.yaml +9 -0
  130. llm_beacon-0.1.0/snapshots/parse_tool_call/plain_answer.yaml +8 -0
  131. llm_beacon-0.1.0/snapshots/parse_tool_call/python_kwargs.yaml +10 -0
  132. llm_beacon-0.1.0/snapshots/parse_tool_call/python_nested_literals.yaml +15 -0
  133. llm_beacon-0.1.0/snapshots/parse_tool_call/python_no_args.yaml +8 -0
  134. llm_beacon-0.1.0/snapshots/parse_tool_call/python_positional.yaml +8 -0
  135. llm_beacon-0.1.0/snapshots/parse_tool_call/xml_invoke.yaml +16 -0
  136. llm_beacon-0.1.0/snapshots/pipeline/cancel_trace.yaml +18 -0
  137. llm_beacon-0.1.0/snapshots/redact/custom_terms.yaml +16 -0
  138. llm_beacon-0.1.0/snapshots/redact/jwt_and_ip.yaml +16 -0
  139. llm_beacon-0.1.0/snapshots/redact/log_line_with_secrets.yaml +20 -0
  140. llm_beacon-0.1.0/snapshots/redact/near_misses.yaml +8 -0
  141. llm_beacon-0.1.0/snapshots/redact/private_key_block.yaml +23 -0
  142. llm_beacon-0.1.0/snapshots/redact/support_ticket.yaml +24 -0
  143. llm_beacon-0.1.0/snapshots/redact/unicode_context.yaml +16 -0
  144. llm_beacon-0.1.0/snapshots/retry/backoff_schedule.yaml +30 -0
  145. llm_beacon-0.1.0/snapshots/retry/status_table.yaml +63 -0
  146. llm_beacon-0.1.0/snapshots/template/bad_spec.yaml +14 -0
  147. llm_beacon-0.1.0/snapshots/template/basic.yaml +9 -0
  148. llm_beacon-0.1.0/snapshots/template/extra.yaml +14 -0
  149. llm_beacon-0.1.0/snapshots/template/literal_json_skeleton.yaml +8 -0
  150. llm_beacon-0.1.0/snapshots/template/missing.yaml +13 -0
  151. llm_beacon-0.1.0/snapshots/template/multiline.yaml +15 -0
  152. llm_beacon-0.1.0/snapshots/template/numbers.yaml +10 -0
  153. llm_beacon-0.1.0/snapshots/template/raw_and_escaped.yaml +8 -0
  154. llm_beacon-0.1.0/snapshots/template/unicode_values.yaml +9 -0
  155. llm_beacon-0.1.0/snapshots/template/unmatched.yaml +13 -0
  156. llm_beacon-0.1.0/snapshots/template/xml_injection.yaml +8 -0
  157. llm_beacon-0.1.0/snapshots/test_snapshots/test_pytest_fixture.yaml +4 -0
  158. llm_beacon-0.1.0/snapshots/validate_schema/intent_invalid.yaml +30 -0
  159. llm_beacon-0.1.0/snapshots/validate_schema/intent_missing_fields.yaml +28 -0
  160. llm_beacon-0.1.0/snapshots/validate_schema/intent_valid.yaml +24 -0
  161. llm_beacon-0.1.0/snapshots/validate_schema/intent_wrong_types.yaml +30 -0
  162. llm_beacon-0.1.0/snapshots/validate_schema/nested_array_errors.yaml +33 -0
  163. llm_beacon-0.1.0/snapshots/validate_schema/one_of_ambiguous.yaml +13 -0
  164. llm_beacon-0.1.0/snapshots/validate_schema/optional_nested.yaml +22 -0
  165. llm_beacon-0.1.0/snapshots/validate_schema/strict_object.yaml +16 -0
  166. llm_beacon-0.1.0/snapshots/validate_schema/string_limits.yaml +16 -0
  167. llm_beacon-0.1.0/snapshots/validate_schema/unsupported_keyword.yaml +11 -0
  168. llm_beacon-0.1.0/src/convert.rs +261 -0
  169. llm_beacon-0.1.0/src/error.rs +143 -0
  170. llm_beacon-0.1.0/src/extract_json.rs +442 -0
  171. llm_beacon-0.1.0/src/hash.rs +201 -0
  172. llm_beacon-0.1.0/src/json.rs +540 -0
  173. llm_beacon-0.1.0/src/lib.rs +314 -0
  174. llm_beacon-0.1.0/src/normalize.rs +187 -0
  175. llm_beacon-0.1.0/src/parse_tool_call.rs +876 -0
  176. llm_beacon-0.1.0/src/redact.rs +421 -0
  177. llm_beacon-0.1.0/src/retry.rs +314 -0
  178. llm_beacon-0.1.0/src/template.rs +338 -0
  179. llm_beacon-0.1.0/src/validate_schema.rs +897 -0
  180. llm_beacon-0.1.0/src/value.rs +269 -0
  181. llm_beacon-0.1.0/tests/conftest.py +14 -0
  182. llm_beacon-0.1.0/tests/test_determinism.py +48 -0
  183. llm_beacon-0.1.0/tests/test_extract_json.py +287 -0
  184. llm_beacon-0.1.0/tests/test_hash.py +113 -0
  185. llm_beacon-0.1.0/tests/test_integration_dspy.py +72 -0
  186. llm_beacon-0.1.0/tests/test_integration_langchain.py +98 -0
  187. llm_beacon-0.1.0/tests/test_integration_llamaindex.py +53 -0
  188. llm_beacon-0.1.0/tests/test_integration_openai.py +140 -0
  189. llm_beacon-0.1.0/tests/test_integration_pydantic_ai.py +61 -0
  190. llm_beacon-0.1.0/tests/test_normalize.py +105 -0
  191. llm_beacon-0.1.0/tests/test_parse_tool_call.py +217 -0
  192. llm_beacon-0.1.0/tests/test_pipeline.py +101 -0
  193. llm_beacon-0.1.0/tests/test_redact.py +166 -0
  194. llm_beacon-0.1.0/tests/test_retry.py +198 -0
  195. llm_beacon-0.1.0/tests/test_snapshots.py +277 -0
  196. llm_beacon-0.1.0/tests/test_template.py +175 -0
  197. llm_beacon-0.1.0/tests/test_validate_schema.py +311 -0
  198. llm_beacon-0.1.0/website/.gitignore +5 -0
  199. llm_beacon-0.1.0/website/README.md +27 -0
  200. llm_beacon-0.1.0/website/astro.config.mjs +95 -0
  201. llm_beacon-0.1.0/website/package-lock.json +5185 -0
  202. llm_beacon-0.1.0/website/package.json +22 -0
  203. llm_beacon-0.1.0/website/public/beacon.wasm +0 -0
  204. llm_beacon-0.1.0/website/public/favicon.svg +6 -0
  205. llm_beacon-0.1.0/website/scripts/build-wasm.mjs +21 -0
  206. llm_beacon-0.1.0/website/scripts/nest-dist.mjs +17 -0
  207. llm_beacon-0.1.0/website/src/assets/logo.svg +5 -0
  208. llm_beacon-0.1.0/website/src/components/Playground.astro +826 -0
  209. llm_beacon-0.1.0/website/src/components/docs/SiteTitle.astro +39 -0
  210. llm_beacon-0.1.0/website/src/components/landing/Blocks.astro +156 -0
  211. llm_beacon-0.1.0/website/src/components/landing/Footer.astro +203 -0
  212. llm_beacon-0.1.0/website/src/components/landing/Guarantees.astro +106 -0
  213. llm_beacon-0.1.0/website/src/components/landing/Hero.astro +429 -0
  214. llm_beacon-0.1.0/website/src/components/landing/Integrations.astro +74 -0
  215. llm_beacon-0.1.0/website/src/components/landing/Nav.astro +157 -0
  216. llm_beacon-0.1.0/website/src/components/landing/Performance.astro +182 -0
  217. llm_beacon-0.1.0/website/src/components/landing/Problem.astro +266 -0
  218. llm_beacon-0.1.0/website/src/components/landing/Setup.astro +149 -0
  219. llm_beacon-0.1.0/website/src/components/landing/Snapshots.astro +223 -0
  220. llm_beacon-0.1.0/website/src/components/landing/Try.astro +58 -0
  221. llm_beacon-0.1.0/website/src/content/docs/blocks/extract-json.mdx +96 -0
  222. llm_beacon-0.1.0/website/src/content/docs/blocks/hash-content.mdx +47 -0
  223. llm_beacon-0.1.0/website/src/content/docs/blocks/normalize.mdx +43 -0
  224. llm_beacon-0.1.0/website/src/content/docs/blocks/parse-tool-call.mdx +81 -0
  225. llm_beacon-0.1.0/website/src/content/docs/blocks/pipelines.mdx +58 -0
  226. llm_beacon-0.1.0/website/src/content/docs/blocks/redact.mdx +86 -0
  227. llm_beacon-0.1.0/website/src/content/docs/blocks/retry.mdx +81 -0
  228. llm_beacon-0.1.0/website/src/content/docs/blocks/template.mdx +101 -0
  229. llm_beacon-0.1.0/website/src/content/docs/blocks/validate-schema.mdx +83 -0
  230. llm_beacon-0.1.0/website/src/content/docs/getting-started/core-concepts.mdx +89 -0
  231. llm_beacon-0.1.0/website/src/content/docs/getting-started/installation.mdx +93 -0
  232. llm_beacon-0.1.0/website/src/content/docs/getting-started/introduction.mdx +60 -0
  233. llm_beacon-0.1.0/website/src/content/docs/getting-started/quickstart.mdx +106 -0
  234. llm_beacon-0.1.0/website/src/content/docs/guarantees/determinism.mdx +86 -0
  235. llm_beacon-0.1.0/website/src/content/docs/guarantees/errors.mdx +90 -0
  236. llm_beacon-0.1.0/website/src/content/docs/integrations/dspy.mdx +57 -0
  237. llm_beacon-0.1.0/website/src/content/docs/integrations/langchain.mdx +78 -0
  238. llm_beacon-0.1.0/website/src/content/docs/integrations/llamaindex.mdx +45 -0
  239. llm_beacon-0.1.0/website/src/content/docs/integrations/openai.mdx +64 -0
  240. llm_beacon-0.1.0/website/src/content/docs/integrations/overview.mdx +26 -0
  241. llm_beacon-0.1.0/website/src/content/docs/integrations/pydantic-ai.mdx +48 -0
  242. llm_beacon-0.1.0/website/src/content/docs/reference/api.mdx +138 -0
  243. llm_beacon-0.1.0/website/src/content/docs/reference/changelog.mdx +28 -0
  244. llm_beacon-0.1.0/website/src/content/docs/reference/error-codes.mdx +78 -0
  245. llm_beacon-0.1.0/website/src/content/docs/snapshots/ci.mdx +64 -0
  246. llm_beacon-0.1.0/website/src/content/docs/snapshots/overview.mdx +95 -0
  247. llm_beacon-0.1.0/website/src/content/docs/snapshots/pytest.mdx +66 -0
  248. llm_beacon-0.1.0/website/src/content.config.ts +7 -0
  249. llm_beacon-0.1.0/website/src/layouts/Landing.astro +108 -0
  250. llm_beacon-0.1.0/website/src/middleware.ts +42 -0
  251. llm_beacon-0.1.0/website/src/pages/404.astro +77 -0
  252. llm_beacon-0.1.0/website/src/pages/index.astro +30 -0
  253. llm_beacon-0.1.0/website/src/pages/playground.astro +63 -0
  254. llm_beacon-0.1.0/website/src/scripts/playground-config.ts +301 -0
  255. llm_beacon-0.1.0/website/src/site.ts +17 -0
  256. llm_beacon-0.1.0/website/src/styles/docs.css +184 -0
  257. llm_beacon-0.1.0/website/src/styles/fonts.css +4 -0
  258. llm_beacon-0.1.0/website/src/styles/landing.css +404 -0
  259. llm_beacon-0.1.0/website/tsconfig.json +5 -0
  260. llm_beacon-0.1.0/website/vercel.json +24 -0
@@ -0,0 +1,11 @@
1
+ {
2
+ "version": "0.0.1",
3
+ "configurations": [
4
+ {
5
+ "name": "docs",
6
+ "runtimeExecutable": "npm",
7
+ "runtimeArgs": ["--prefix", "website", "run", "dev", "--", "--port", "4321"],
8
+ "port": 4321
9
+ }
10
+ ]
11
+ }
@@ -0,0 +1,6 @@
1
+ # Snapshot files are compared byte-for-byte; never let git rewrite line endings.
2
+ snapshots/** text eol=lf
3
+ *.py text eol=lf
4
+ *.rs text eol=lf
5
+ *.md text eol=lf
6
+ *.yaml text eol=lf
@@ -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,17 @@
1
+ /target
2
+ .venv/
3
+ __pycache__/
4
+ *.py[cod]
5
+ *.so
6
+ *.pyd
7
+ *.egg-info/
8
+ .pytest_cache/
9
+ dist/
10
+ build/
11
+ .coverage
12
+
13
+ # Docs site
14
+ website/node_modules/
15
+ website/dist/
16
+ website/.astro/
17
+ website/wasm/target/
@@ -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
+ ```