Skip to content

Commit 65b0b9c

Browse files
Merge pull request #26 from botanu-ai/developer
Docs: content capture + set_correlation API
2 parents a338422 + 122777a commit 65b0b9c

52 files changed

Lines changed: 2815 additions & 3657 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.vscode/settings.json

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
{
2+
"// PURPOSE": "Makes Cursor / VS Code show ruff + mypy warnings inline while you edit. Install the 'Ruff' and 'Python' extensions from the Cursor extension panel for full effect.",
3+
4+
"python.analysis.typeCheckingMode": "basic",
5+
"python.analysis.autoImportCompletions": true,
6+
"python.analysis.diagnosticMode": "workspace",
7+
8+
"[python]": {
9+
"editor.defaultFormatter": "charliermarsh.ruff",
10+
"editor.formatOnSave": true,
11+
"editor.codeActionsOnSave": {
12+
"source.fixAll.ruff": "explicit",
13+
"source.organizeImports.ruff": "explicit"
14+
}
15+
},
16+
17+
"ruff.enable": true,
18+
"ruff.importStrategy": "fromEnvironment",
19+
"ruff.lint.run": "onType",
20+
"ruff.nativeServer": "on",
21+
22+
"files.exclude": {
23+
"**/__pycache__": true,
24+
"**/.mypy_cache": true,
25+
"**/.ruff_cache": true,
26+
"**/.pytest_cache": true
27+
},
28+
29+
"files.associations": {
30+
"*.toml": "toml"
31+
},
32+
"cursorpyright.analysis.autoImportCompletions": true,
33+
"cursorpyright.analysis.diagnosticMode": "workspace",
34+
"cursorpyright.analysis.typeCheckingMode": "basic"
35+
}

CHANGELOG.md

Lines changed: 16 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -7,61 +7,26 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10-
### Added
11-
12-
- **Security**
13-
- OTLP bearer token is attached only when the endpoint host is botanu-owned
14-
(`*.botanu.ai`) or a local dev host, preventing tenant API-key leakage
15-
via a customer-supplied `OTEL_EXPORTER_OTLP_ENDPOINT`.
16-
- Authorization / `x-api-key` / `botanu-api-key` headers and `user:pass@`
17-
URL credentials are redacted in logs.
18-
- **Brownfield OTel coexistence**
19-
- `SampledSpanProcessor` preserves the host app's existing TracerProvider
20-
sampling ratio when botanu is bootstrapped into a project that already
21-
has OTel wired up.
22-
- `register.py` entry point for explicit opt-in without decorator-side
23-
provider mutation.
24-
- Bootstrap detects a pre-configured provider and hands off instead of
25-
overriding it.
26-
- **Content capture for eval**
27-
- Workflow-level input/output capture gated by `content_capture_rate`
28-
config and a shared `content_sampler`. Writes
29-
`botanu.eval.input_content` / `botanu.eval.output_content`.
30-
- `set_input_content()` / `set_output_content()` on `LLMTracker` with the
31-
same gate, plus matching helpers on data-tracking helpers.
32-
- **Multi-step workflows**
33-
- `@botanu_workflow(..., step=...)` parameter (stored in `RunContext`,
34-
not yet emitted to span attributes — kept backward compatible until the
35-
collector servicegraph work lands).
36-
- **Resources**
37-
- `ResourceEnricher` span processor for deployment attributes.
38-
- **Release tooling**
39-
- `scripts/pre_publish_check.py` red/green gate: builds sdist + wheel,
40-
runs `twine check`, installs into a fresh venv, validates the public
41-
API surface, runs an end-to-end decorator + `emit_outcome` smoke test.
10+
### Breaking
4211

43-
### Fixed
12+
- Primary API is now `botanu.event(...)` — works as context manager, async context manager, and decorator. The legacy `@botanu_workflow`, `workflow` alias, `run_botanu`, and `@botanu_outcome` decorators are removed.
13+
- `emit_outcome` is keyword-only and no longer accepts a `status` argument. Authoritative event outcome is resolved server-side from SoR connectors, HITL reviews, or eval verdict rollup.
14+
- Lean baggage propagation is removed. All seven baggage keys (plus any retry/deadline keys when set) always propagate. The `BOTANU_PROPAGATION_MODE` env var, the `propagation_mode` field on `BotanuConfig`, `BAGGAGE_KEYS_LEAN`, and the `lean_mode` parameter on `RunContextEnricher` / `RunContext.to_baggage_dict` are all gone.
4415

45-
- `SampledSpanProcessor.on_start` now gates on the same ratio decision as
46-
`on_end`; forwarding `on_start` unconditionally while gating `on_end`
47-
leaked span bookkeeping inside wrapped exporters (QUAL-C1).
16+
### Added
4817

49-
### Initial release contents
18+
- `botanu.event(...)` as context manager, async context manager, and decorator — a single API for marking business events.
19+
- `botanu.step(name)` for nested phase spans inside an event.
20+
- SDK initialises automatically on the first `botanu.event(...)` call. Customers no longer need to call any bootstrap function by hand.
21+
- `botanu.set_correlation(**keys)` for SoR Tier-1 correlation.
22+
- Security: OTLP bearer token is attached only when the endpoint host is botanu-owned (`*.botanu.ai`) or a local dev host, preventing tenant API-key leakage via a customer-supplied `OTEL_EXPORTER_OTLP_ENDPOINT`. Authorization / `x-api-key` / `botanu-api-key` headers and `user:pass@` URL credentials are redacted in logs.
23+
- OTel coexistence: when the host app already has the OTel SDK wired up, botanu preserves the existing sampling ratio and adds itself alongside. `register.py` module for zero-code initialisation in containers / gunicorn / process runners.
24+
- Content capture for eval, gated by `content_capture_rate`. Writes `botanu.eval.input_content` / `botanu.eval.output_content` with in-process PII scrub (regex by default; optional Microsoft Presidio via `pip install botanu[pii-nlp]`).
25+
- `ResourceEnricher` span processor for deployment attributes.
26+
- Release tooling: `scripts/pre_publish_check.py` — builds sdist + wheel, runs `twine check`, installs into a fresh venv, validates the public API surface, runs an end-to-end smoke test.
5027

51-
Carried forward from the pre-tag scaffolding (never published):
28+
### Fixed
5229

53-
- `enable()` / `disable()` bootstrap, `@botanu_workflow`,
54-
`@botanu_outcome`, `emit_outcome()`, `set_business_context()`,
55-
`RunContextEnricher` — with UUIDv7 run_ids.
56-
- LLM tracking aligned with OTel GenAI semconv: `track_llm_call()`,
57-
`track_tool_call()`, token accounting, 15+ provider normalization.
58-
- Data tracking: `track_db_operation()`, `track_storage_operation()`,
59-
`track_messaging_operation()`; 30+ system normalizations.
60-
- W3C Baggage propagation with `RunContext` (retry tracking + deadline).
61-
- Cloud resource detectors via optional extras (`aws`, `gcp`, `azure`,
62-
`container`, `cloud`).
63-
- Auto-instrumentation bundled in the base install — HTTP clients, web
64-
frameworks, databases, messaging, and GenAI providers; instrumentation
65-
packages no-op when their target library is not installed.
30+
- `SampledSpanProcessor.on_start` now gates on the same ratio decision as `on_end`; forwarding `on_start` unconditionally while gating `on_end` leaked span bookkeeping inside wrapped exporters.
6631

6732
[Unreleased]: https://github.com/botanu-ai/botanu-sdk-python/commits/main

README.md

Lines changed: 64 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,13 @@ This SDK is built on [OpenTelemetry](https://opentelemetry.io/) for event-level
88

99
## Getting Started
1010

11+
An **event** is one business transaction — resolving a support ticket, processing an order, generating a report. Each event may involve multiple **runs** (LLM calls, retries, sub-workflows) across multiple services. By correlating every run to a stable `event_id`, Botanu gives you per-event cost attribution and outcome tracking without sampling artefacts.
1112

13+
## Install
14+
15+
```bash
16+
pip install botanu
17+
```
1218

1319
An **event** is one business transaction — resolving a support ticket, processing
1420
an order, generating a report. Each event may involve multiple **runs** (LLM calls,
@@ -17,91 +23,104 @@ stable `event_id`, botanu gives you per-event cost attribution and outcome
1723
tracking without sampling artifacts.
1824

1925
```bash
20-
pip install botanu
26+
export BOTANU_API_KEY=<your-api-key>
2127
```
2228

23-
One install. Includes OTel SDK, OTLP exporter, and auto-instrumentation for
24-
50+ libraries.
29+
Wrap your agent:
2530

2631
```python
27-
from botanu import enable, botanu_workflow, emit_outcome
32+
import botanu
33+
34+
with botanu.event(event_id=ticket.id, customer_id=user.id, workflow="Support"):
35+
agent.run(ticket)
36+
```
37+
38+
That single wrap captures every LLM call, HTTP call, and DB call inside and stamps them with `event_id`, `customer_id`, and `workflow`.
2839

29-
enable() # reads config from environment variables
40+
### Decorator form
3041

31-
@botanu_workflow("my-workflow", event_id="evt-001", customer_id="cust-42")
32-
async def do_work():
33-
result = await do_something()
34-
emit_outcome("success")
35-
return result
42+
```python
43+
import botanu
44+
45+
@botanu.event(
46+
workflow="Support",
47+
event_id=lambda ticket: ticket.id,
48+
customer_id=lambda ticket: ticket.user_id,
49+
)
50+
def handle_ticket(ticket):
51+
return agent.run(ticket)
3652
```
3753

38-
Entry points use `@botanu_workflow`. Every other service only needs `enable()`.
39-
All configuration is via environment variables — zero hardcoded values in code.
54+
Works for both sync and `async def` functions.
55+
56+
### Multi-phase workflows
4057

41-
See the [Quick Start](./docs/getting-started/quickstart.md) guide for a full walkthrough.
58+
```python
59+
with botanu.event(event_id=ticket.id, customer_id=user.id, workflow="Support"):
60+
with botanu.step("retrieval"):
61+
docs = vector_db.query(ticket.query)
62+
with botanu.step("generation"):
63+
response = llm.complete(docs)
64+
```
65+
66+
See the [Quickstart](./docs/getting-started/quickstart.md) for the full five-minute walkthrough.
4267

4368
## Documentation
4469

45-
| Topic | Description |
46-
|-------|-------------|
47-
| [Installation](./docs/getting-started/installation.md) | Install and configure the SDK |
48-
| [Quick Start](./docs/getting-started/quickstart.md) | Get up and running in 5 minutes |
49-
| [Configuration](./docs/getting-started/configuration.md) | Environment variables and options |
50-
| [Core Concepts](./docs/concepts/) | Events, runs, context propagation, architecture |
51-
| [LLM Tracking](./docs/tracking/llm-tracking.md) | Track model calls and token usage |
52-
| [Data Tracking](./docs/tracking/data-tracking.md) | Database, storage, and messaging |
53-
| [Outcomes](./docs/tracking/outcomes.md) | Record business outcomes for ROI |
54-
| [Auto-Instrumentation](./docs/integration/auto-instrumentation.md) | Supported libraries and frameworks |
70+
| Topic | |
71+
| --- | --- |
72+
| [Installation](./docs/getting-started/installation.md) | Install and configure |
73+
| [Quickstart](./docs/getting-started/quickstart.md) | Zero-to-first-trace in five minutes |
74+
| [Configuration](./docs/getting-started/configuration.md) | Env vars, YAML, trusted-host auth |
75+
| [Run Context](./docs/concepts/run-context.md) | Events, runs, retries, baggage |
76+
| [Context Propagation](./docs/concepts/context-propagation.md) | Cross-service and queue propagation |
77+
| [Architecture](./docs/concepts/architecture.md) | SDK + collector split |
78+
| [LLM Tracking](./docs/tracking/llm-tracking.md) | Manual LLM instrumentation (usually not needed) |
79+
| [Data Tracking](./docs/tracking/data-tracking.md) | DB, storage, messaging (usually not needed) |
80+
| [Content Capture](./docs/tracking/content-capture.md) | Prompt/response capture for eval, with PII scrubbing |
81+
| [Outcomes](./docs/tracking/outcomes.md) | Diagnostic annotations and server-side resolution |
82+
| [Auto-Instrumentation](./docs/integration/auto-instrumentation.md) | Supported libraries |
5583
| [Kubernetes](./docs/integration/kubernetes.md) | Zero-code instrumentation at scale |
56-
| [API Reference](./docs/api/) | Decorators, tracking API, configuration |
57-
| [Best Practices](./docs/patterns/best-practices.md) | Recommended patterns |
84+
| [Existing OTel / Datadog](./docs/integration/existing-otel.md) | Brownfield coexistence |
85+
| [`event` / `step` API](./docs/api/event.md) | Primary API reference |
86+
| [Best Practices](./docs/patterns/best-practices.md) | Patterns that work |
87+
| [Anti-Patterns](./docs/patterns/anti-patterns.md) | Patterns that break cost attribution |
5888

5989
## Requirements
6090

61-
- Python 3.9+
62-
- OpenTelemetry Collector (recommended for production)
91+
- Python 3.9 or newer
92+
- An OpenTelemetry Collector (Botanu Cloud runs one for you; self-hosted is supported too)
6393

6494
## Contributing
6595

66-
We welcome contributions from the community. Please read our
67-
[Contributing Guide](./CONTRIBUTING.md) before submitting a pull request.
96+
Contributions are welcome. Read the [Contributing Guide](./CONTRIBUTING.md) before opening a pull request.
6897

69-
This project requires [DCO sign-off](https://developercertificate.org/) on all
70-
commits:
98+
All commits require [DCO sign-off](https://developercertificate.org/):
7199

72100
```bash
73101
git commit -s -m "Your commit message"
74102
```
75103

76-
Looking for a place to start? Check the
77-
[good first issues](https://github.com/botanu-ai/botanu-sdk-python/labels/good%20first%20issue).
104+
Looking for a place to start? See the [good first issues](https://github.com/botanu-ai/botanu-sdk-python/labels/good%20first%20issue).
78105

79106
## Community
80107

81108
- [GitHub Discussions](https://github.com/botanu-ai/botanu-sdk-python/discussions) — questions, ideas, show & tell
82-
- [GitHub Issues](https://github.com/botanu-ai/botanu-sdk-python/issues)bug reports and feature requests
109+
- [GitHub Issues](https://github.com/botanu-ai/botanu-sdk-python/issues)bugs and feature requests
83110

84111
## Governance
85112

86-
See [GOVERNANCE.md](./GOVERNANCE.md) for details on roles, decision-making,
87-
and the contributor ladder.
88-
89-
Current maintainers are listed in [MAINTAINERS.md](./MAINTAINERS.md).
113+
See [GOVERNANCE.md](./GOVERNANCE.md) for roles, decision-making, and the contributor ladder. Current maintainers are in [MAINTAINERS.md](./MAINTAINERS.md).
90114

91115
## Security
92116

93-
To report a security vulnerability, please use
94-
[GitHub Security Advisories](https://github.com/botanu-ai/botanu-sdk-python/security/advisories/new)
95-
or see [SECURITY.md](./SECURITY.md) for full details. **Do not file a public issue.**
117+
Report security vulnerabilities via [GitHub Security Advisories](https://github.com/botanu-ai/botanu-sdk-python/security/advisories/new) or see [SECURITY.md](./SECURITY.md). **Do not file a public issue.**
96118

97119

98120
## Code of Conduct
99121

100-
This project follows the
101-
[LF Projects Code of Conduct](https://lfprojects.org/policies/code-of-conduct/).
102-
See [CODE_OF_CONDUCT.md](./CODE_OF_CONDUCT.md).
122+
This project follows the [LF Projects Code of Conduct](https://lfprojects.org/policies/code-of-conduct/). See [CODE_OF_CONDUCT.md](./CODE_OF_CONDUCT.md).
103123

104124
## License
105125

106126
[Apache License 2.0](./LICENSE)
107-

RELEASE.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,8 +94,9 @@ python -c "import botanu; print(botanu.__version__)"
9494

9595
# Run quick test
9696
python -c "
97-
from botanu import enable, botanu_workflow
98-
enable(service_name='test')
97+
import botanu
98+
with botanu.event(event_id='smoke-1', customer_id='smoke-cust', workflow='smoke-test'):
99+
pass
99100
print('Botanu SDK loaded successfully!')
100101
"
101102
```

0 commit comments

Comments
 (0)