rootmark 0.1.0__tar.gz → 0.1.2__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 (51) hide show
  1. rootmark-0.1.2/CHANGELOG.md +144 -0
  2. {rootmark-0.1.0 → rootmark-0.1.2}/PKG-INFO +72 -1
  3. rootmark-0.1.2/README.md +167 -0
  4. {rootmark-0.1.0 → rootmark-0.1.2}/pyproject.toml +4 -2
  5. {rootmark-0.1.0 → rootmark-0.1.2}/src/rootmark/__init__.py +300 -234
  6. {rootmark-0.1.0 → rootmark-0.1.2}/src/rootmark/config.py +267 -267
  7. {rootmark-0.1.0 → rootmark-0.1.2}/src/rootmark/core/emitter.py +219 -8
  8. rootmark-0.1.2/src/rootmark/core/lifecycle.py +94 -0
  9. rootmark-0.1.2/src/rootmark/core/step.py +72 -0
  10. {rootmark-0.1.0 → rootmark-0.1.2}/src/rootmark/patches/_bedrock_helpers.py +207 -169
  11. {rootmark-0.1.0 → rootmark-0.1.2}/src/rootmark/patches/boto3_interceptor.py +28 -4
  12. {rootmark-0.1.0 → rootmark-0.1.2}/src/rootmark/patches/crewai.py +480 -480
  13. {rootmark-0.1.0 → rootmark-0.1.2}/src/rootmark/patches/strands.py +685 -669
  14. {rootmark-0.1.0 → rootmark-0.1.2}/src/rootmark/patches/strands_multiagent.py +576 -571
  15. rootmark-0.1.2/src/rootmark/schema/trace_event.py +129 -0
  16. {rootmark-0.1.0 → rootmark-0.1.2}/tests/core/test_emitter_bind_context.py +130 -129
  17. {rootmark-0.1.0 → rootmark-0.1.2}/tests/core/test_emitter_session.py +106 -105
  18. {rootmark-0.1.0 → rootmark-0.1.2}/tests/patches/test_agentcore.py +545 -544
  19. {rootmark-0.1.0 → rootmark-0.1.2}/tests/patches/test_strands.py +300 -299
  20. {rootmark-0.1.0 → rootmark-0.1.2}/tests/test_boto3_interceptor.py +1282 -1216
  21. {rootmark-0.1.0 → rootmark-0.1.2}/tests/test_config_override.py +229 -221
  22. {rootmark-0.1.0 → rootmark-0.1.2}/tests/test_crewai_patch.py +182 -180
  23. {rootmark-0.1.0 → rootmark-0.1.2}/tests/test_langchain_handler.py +99 -98
  24. rootmark-0.1.2/tests/test_span_lifecycle.py +356 -0
  25. {rootmark-0.1.0 → rootmark-0.1.2}/tests/test_span_tags.py +218 -201
  26. rootmark-0.1.2/tests/test_step_contract.py +53 -0
  27. {rootmark-0.1.0 → rootmark-0.1.2}/tests/test_strands_agent_live.py +320 -303
  28. {rootmark-0.1.0 → rootmark-0.1.2}/tests/test_strands_multiagent.py +472 -454
  29. {rootmark-0.1.0 → rootmark-0.1.2}/tests/test_strands_multiagent_live.py +404 -387
  30. {rootmark-0.1.0 → rootmark-0.1.2}/tests/test_strands_patch.py +676 -675
  31. {rootmark-0.1.0 → rootmark-0.1.2}/tests/test_strands_session.py +307 -290
  32. {rootmark-0.1.0 → rootmark-0.1.2}/tests/test_suppress_payloads.py +202 -185
  33. {rootmark-0.1.0 → rootmark-0.1.2}/tests/test_trace_and_span.py +384 -383
  34. rootmark-0.1.0/README.md +0 -96
  35. rootmark-0.1.0/src/rootmark/schema/trace_event.py +0 -83
  36. {rootmark-0.1.0 → rootmark-0.1.2}/.gitignore +0 -0
  37. {rootmark-0.1.0 → rootmark-0.1.2}/src/rootmark/audit/__init__.py +0 -0
  38. {rootmark-0.1.0 → rootmark-0.1.2}/src/rootmark/audit/hashing.py +0 -0
  39. {rootmark-0.1.0 → rootmark-0.1.2}/src/rootmark/core/__init__.py +0 -0
  40. {rootmark-0.1.0 → rootmark-0.1.2}/src/rootmark/core/processor.py +0 -0
  41. {rootmark-0.1.0 → rootmark-0.1.2}/src/rootmark/patches/__init__.py +0 -0
  42. {rootmark-0.1.0 → rootmark-0.1.2}/src/rootmark/patches/agentcore.py +0 -0
  43. {rootmark-0.1.0 → rootmark-0.1.2}/src/rootmark/patches/langchain.py +0 -0
  44. {rootmark-0.1.0 → rootmark-0.1.2}/src/rootmark/patches/openai.py +0 -0
  45. {rootmark-0.1.0 → rootmark-0.1.2}/src/rootmark/patches/strands_session.py +0 -0
  46. {rootmark-0.1.0 → rootmark-0.1.2}/src/rootmark/schema/__init__.py +0 -0
  47. {rootmark-0.1.0 → rootmark-0.1.2}/tests/core/test_processor_envelope.py +0 -0
  48. {rootmark-0.1.0 → rootmark-0.1.2}/tests/integration/conftest.py +0 -0
  49. {rootmark-0.1.0 → rootmark-0.1.2}/tests/integration/test_strands_e2e.py +0 -0
  50. {rootmark-0.1.0 → rootmark-0.1.2}/tests/patches/__init__.py +0 -0
  51. {rootmark-0.1.0 → rootmark-0.1.2}/tests/test_roundtrip_ingestion.py +0 -0
@@ -0,0 +1,144 @@
1
+ # Changelog
2
+
3
+ Notable changes to the `rootmark` SDK. Versions follow the collector's own
4
+ releases loosely; where the two must match, it says so.
5
+
6
+ ## 0.1.2
7
+
8
+ **Fixes a defect in 0.1.1 that stopped runs ever completing.** Upgrade from
9
+ 0.1.1; there is no reason to stay on it.
10
+
11
+ ### Fixed
12
+
13
+ - **A discarded span held its run open for ever.** 0.1.1 made `start_span`
14
+ write a provisional row, but `discard_span` still emitted nothing -- correct
15
+ when a discarded span had never been mentioned, wrong once it had. The
16
+ provisional row said `running` and nothing superseded it, and a run is
17
+ finished only when all of its spans are. Every run containing a discarded
18
+ span therefore stayed in progress permanently.
19
+
20
+ It was not a corner case. The boto3 interceptor discards its span on *every*
21
+ Bedrock call made inside a Strands agent, because the Strands patch is
22
+ already tracing the same call. On the first deployment running both, 18 of
23
+ 18 runs recorded after the upgrade were stuck "running" and none could ever
24
+ complete.
25
+
26
+ Two changes, because one of them is a guarantee and the other is the right
27
+ shape:
28
+
29
+ * `discard_span` now **retracts** a span it announced, writing a terminal
30
+ `cancelled` row at the end sentinel. Any caller that announced a span can
31
+ discard it without stranding it. `cancelled` rather than `success`,
32
+ because nothing was measured -- a 0 ms success would be averaged in as a
33
+ real and very fast call -- and it is not an error, so error rates are
34
+ untouched.
35
+ * `start_span` takes `announce=False` for a span opened speculatively, and
36
+ the boto3 interceptor uses it. A span that may turn out to belong to
37
+ another layer is no longer announced at open, so discarding it costs
38
+ nothing and leaves no `cancelled` row on every trace.
39
+
40
+ The cost of the second change: a bare Bedrock call made through boto3
41
+ *outside* a Strands agent is no longer visible while it runs, only once it
42
+ completes. Inside Strands -- the common case, and the one that was broken --
43
+ the agent span above it keeps in-progress visibility.
44
+
45
+ ### Repairing existing data
46
+
47
+ Runs already stuck cannot fix themselves: their provisional rows will never be
48
+ superseded. Write the retraction the fixed code would have written -- a
49
+ `cancelled` row at `row_version` 2147483647 with the same `(project_id,
50
+ trace_id, start_time, span_id)` -- for every span matching
51
+
52
+ ```sql
53
+ SELECT * FROM trace_events FINAL
54
+ WHERE status NOT IN ('success','error','timeout','cancelled')
55
+ ```
56
+
57
+ then re-project the affected runs. On the deployment above this moved 18 runs
58
+ from `running` to `success` and left no open spans.
59
+
60
+ ## 0.1.1
61
+
62
+ **Upgrading from 0.1.0 requires a collector upgrade first.** See *Compatibility*
63
+ below — this is not optional, and getting the order wrong loses data.
64
+
65
+ ### Added
66
+
67
+ - **Spans are sent when they start, not only when they finish.** Before this a
68
+ span reached Rootmark only from `end_span`, so anything in flight was simply
69
+ absent — and a step paused for human review was indistinguishable from one
70
+ wedged against a model that had stopped answering. A run is now visible from
71
+ the moment its first span opens.
72
+ - `rootmark.mark_waiting(span, reason)` — say a span is deliberately not
73
+ working, and what it is waiting on. `reason` is free text in the caller's own
74
+ vocabulary (`"human_review"`, `"rate_limit"`, `"upstream"`); the SDK does not
75
+ fix the set, because encoding one application's review workflow into the
76
+ schema would make it everyone's.
77
+ - `heartbeat=` on `rootmark.span()` — re-announce a long span on an interval so
78
+ a killed process can be told apart from a slow one. Opt-in per span, because
79
+ a heartbeat on a 200 ms call is volume spent to say nothing. Intervals below
80
+ five seconds are raised to five rather than refused.
81
+ - `step_key` / `step_kind` on spans, and `SpanEmitter.set_step()` for callers
82
+ that learn what a step is only after starting it. `step_key` is a stable
83
+ identity for which logical step a span is; `step_kind` is what it was for.
84
+ A kind the SDK does not recognise is kept, not dropped.
85
+ - `SpanStatus` gains `running`, `waiting` and `cancelled`, plus an `is_terminal`
86
+ property. The first three values are unchanged.
87
+
88
+ ### Changed
89
+
90
+ - **`TraceEvent` carries `row_version` and `waiting_reason`.** `row_version`
91
+ orders the several writes a span now produces so the collector can keep the
92
+ latest: start is 1, heartbeats climb, the end row takes a sentinel above every
93
+ possible heartbeat. A rank rather than a timestamp, because rows arrive from
94
+ different processes over an at-least-once channel and a clock cannot order
95
+ them.
96
+ - **Bedrock guardrail traces no longer include `modelOutput`**, and the size cap
97
+ rose from 4 KB to 16 KB. Bedrock echoes the model's whole answer back inside
98
+ the guardrail trace; on a long answer that alone overran the old cap, so the
99
+ payload was stored as a truncated string and the `inputAssessment` naming the
100
+ policy that fired was never reached. A real deployment lost a `PROMPT_ATTACK`
101
+ block that way. The removal is recorded under `rootmarkOmitted`, so a reader
102
+ can tell a pruned trace from one Bedrock never sent the key for.
103
+ **If you read `extra.bedrock_guardrail_trace` expecting `modelOutput`, read
104
+ the model's response from the span's outputs instead.**
105
+ - A non-terminal span reports `duration_ms` of 0 and an `end_time` equal to its
106
+ `start_time`. **Read the status, not the duration**, to decide whether a span
107
+ has finished — a 0 ms span is otherwise a plausible-looking lie.
108
+
109
+ ### Compatibility
110
+
111
+ | | |
112
+ |---|---|
113
+ | Collector | Needs ClickHouse migrations `007`–`009`. Upgrade it **before** the SDK. |
114
+ | Python | 3.12+, unchanged |
115
+ | Wire format | Additive; `row_version` and `waiting_reason` are new fields |
116
+
117
+ A collector older than this release deduplicates buffered spans on
118
+ `(project_id, span_id)` and keeps the **first** row it sees. With a 0.1.1
119
+ client that first row is the *start* row, so the end row — the one carrying the
120
+ result, the duration and the token counts — is discarded. Runs appear and never
121
+ finish. Where the two rows land in different batches instead, the old storage
122
+ engine has no version column to order them by and the survivor is undefined.
123
+
124
+ Neither failure reports an error. Upgrade the collector first, or stay on 0.1.0.
125
+
126
+ ### Cost
127
+
128
+ Each span is now sent at least twice, so **a run produces roughly twice the
129
+ rows** it did on 0.1.0, plus one per heartbeat where heartbeats are enabled.
130
+ The collector collapses the pair when it merges, so stored size settles back;
131
+ what doubles is what crosses the network and passes through ingest. There is no
132
+ flag to turn it off — the alternative is being blind to work in progress, which
133
+ is the whole point of the release.
134
+
135
+ ## 0.1.0
136
+
137
+ First public release. Span tree recording, framework instrumentation for
138
+ OpenAI, LangChain, CrewAI, Strands and Bedrock via botocore, batched background
139
+ delivery with a spill file and replay-safe batch identity, and
140
+ `suppress_payloads` for collectors outside the trust boundary.
141
+
142
+ No licence is declared, which means all rights reserved. That is unchanged in
143
+ 0.1.1 and remains the thing to fix before this package is genuinely installable
144
+ by anyone outside the organisation.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: rootmark
3
- Version: 0.1.0
3
+ Version: 0.1.2
4
4
  Summary: Rootmark SDK -- agent instrumentation
5
5
  Project-URL: Homepage, https://rootmark.dev
6
6
  Project-URL: Documentation, https://rootmark.dev/docs/
@@ -51,6 +51,34 @@ pip install rootmark
51
51
 
52
52
  Requires Python 3.12 or newer.
53
53
 
54
+ > **Upgrading from 0.1.0 needs a collector upgrade too.** Since 0.1.1 a span is
55
+ > sent when it *starts* as well as when it ends, so that work in progress is
56
+ > visible at all. A collector older than this release stores the first row it
57
+ > sees for a span and discards the rest — which is the end row, the one
58
+ > carrying the result and the duration. Runs would appear and never finish.
59
+ > Upgrade the collector first (it needs ClickHouse migrations `007`–`009`), or
60
+ > stay on 0.1.0.
61
+
62
+ > **0.1.1 is broken; use 0.1.2 or later.** In 0.1.1 a span that the SDK opened
63
+ > and then discarded was left looking like it was still running, which held its
64
+ > whole run open permanently. Any Bedrock call made through boto3 inside a
65
+ > Strands agent hits it, on every call.
66
+
67
+ ## What changed in 0.1.1
68
+
69
+ - **Runs are visible while they are still going.** A span is recorded when it
70
+ starts, not only when it finishes.
71
+ - **`rootmark.mark_waiting(span, reason)`** distinguishes a step paused on a
72
+ human from one wedged against a model that stopped answering.
73
+ - **`heartbeat=`** on `rootmark.span()`, so a long step keeps saying it is alive.
74
+ - **Steps**: `step_key` and `step_kind` name which logical step a span is, so
75
+ the collector can aggregate the same step across runs.
76
+ - Bedrock guardrail traces no longer carry `modelOutput`, and the size cap rose
77
+ from 4 KB to 16 KB. A long answer used to overrun the cap and take the policy
78
+ assessment with it. Read the model's response from the span's outputs instead.
79
+
80
+ See `CHANGELOG.md` for the full list.
81
+
54
82
  ## Quickstart
55
83
 
56
84
  ```python
@@ -85,6 +113,49 @@ agent loop spawns, because the binding follows the async context.
85
113
  `workflow_name` should not be `"default"`: that value lets framework
86
114
  instrumentation override the name you bind per run with its own agent id.
87
115
 
116
+ ## Naming the steps of a run
117
+
118
+ ```python
119
+ with rootmark.span("fetch_clauses", run_type=RunType.TOOL,
120
+ step_key="fetch_clauses", step_kind="retrieval"):
121
+ ...
122
+ ```
123
+
124
+ `step_key` is a stable identity for *which* logical step this is, constant
125
+ across runs; `step_kind` is what it was for (`retrieval`, `generation`,
126
+ `routing`, `review`, `tool`, `memory`). Together they let the collector answer
127
+ "which step is slow" without anyone reading individual traces.
128
+
129
+ Both are optional, and a kind the SDK does not recognise is kept rather than
130
+ dropped — your vocabulary is allowed to be ahead of ours. Derive `step_key`
131
+ from something stable: a key built from a timestamp or a request id fragments
132
+ its own aggregate, and nothing can detect that for you.
133
+
134
+ ## Long-running steps
135
+
136
+ ```python
137
+ with rootmark.span("await_approval", run_type=RunType.TOOL, heartbeat=30) as span:
138
+ rootmark.mark_waiting(span, "human_review")
139
+ decision = wait_for_approval() # minutes, or hours
140
+ ```
141
+
142
+ `mark_waiting` says the step is deliberately not working, and what it is
143
+ waiting on. The reason is free text in your own vocabulary — `human_review`,
144
+ `rate_limit`, `upstream` — and is shown back verbatim. It is the difference
145
+ between a run somebody has to investigate and one they can leave alone.
146
+
147
+ `heartbeat` re-announces the span every N seconds while it runs. Leave it unset
148
+ for anything that finishes quickly: a span is already visible from the moment
149
+ it starts, and a heartbeat for a 200 ms call is bandwidth spent to say nothing.
150
+ Set it on the long ones, where the useful question is not "is it running" but
151
+ "is anyone still on the other end" — without it, a step whose process was
152
+ killed looks exactly like one that is simply taking its time. Intervals below
153
+ five seconds are raised to five rather than refused.
154
+
155
+ **This roughly doubles the rows a run produces**, since each span is now sent
156
+ at least twice. The collector collapses the pair when it merges, so stored size
157
+ settles back; what doubles is what crosses the network.
158
+
88
159
  ## Framework support
89
160
 
90
161
  The base install instruments nothing on its own beyond direct use. Install the
@@ -0,0 +1,167 @@
1
+ # Rootmark SDK
2
+
3
+ Agent instrumentation for [Rootmark](https://rootmark.dev) — observe, verify and
4
+ govern agent runs.
5
+
6
+ The SDK records what your agents actually did: the span tree of a run, the model
7
+ calls inside it, token counts, and the payloads you choose to keep. It sends
8
+ them to a Rootmark collector, which you can self-host.
9
+
10
+ ```bash
11
+ pip install rootmark
12
+ ```
13
+
14
+ Requires Python 3.12 or newer.
15
+
16
+ > **Upgrading from 0.1.0 needs a collector upgrade too.** Since 0.1.1 a span is
17
+ > sent when it *starts* as well as when it ends, so that work in progress is
18
+ > visible at all. A collector older than this release stores the first row it
19
+ > sees for a span and discards the rest — which is the end row, the one
20
+ > carrying the result and the duration. Runs would appear and never finish.
21
+ > Upgrade the collector first (it needs ClickHouse migrations `007`–`009`), or
22
+ > stay on 0.1.0.
23
+
24
+ > **0.1.1 is broken; use 0.1.2 or later.** In 0.1.1 a span that the SDK opened
25
+ > and then discarded was left looking like it was still running, which held its
26
+ > whole run open permanently. Any Bedrock call made through boto3 inside a
27
+ > Strands agent hits it, on every call.
28
+
29
+ ## What changed in 0.1.1
30
+
31
+ - **Runs are visible while they are still going.** A span is recorded when it
32
+ starts, not only when it finishes.
33
+ - **`rootmark.mark_waiting(span, reason)`** distinguishes a step paused on a
34
+ human from one wedged against a model that stopped answering.
35
+ - **`heartbeat=`** on `rootmark.span()`, so a long step keeps saying it is alive.
36
+ - **Steps**: `step_key` and `step_kind` name which logical step a span is, so
37
+ the collector can aggregate the same step across runs.
38
+ - Bedrock guardrail traces no longer carry `modelOutput`, and the size cap rose
39
+ from 4 KB to 16 KB. A long answer used to overrun the cap and take the policy
40
+ assessment with it. Read the model's response from the span's outputs instead.
41
+
42
+ See `CHANGELOG.md` for the full list.
43
+
44
+ ## Quickstart
45
+
46
+ ```python
47
+ import rootmark
48
+
49
+ rootmark.init(
50
+ api_key="pk_...", # project API key
51
+ project_id="...", # UUID
52
+ api_key_id="...", # UUID
53
+ api_url="https://rootmark.example.com",
54
+ workflow_name="my-service", # not "default" -- see below
55
+ )
56
+
57
+ rootmark.patch() # instrument supported frameworks in place
58
+ ```
59
+
60
+ That is the whole integration for the common case. `patch()` installs
61
+ instrumentation process-wide, so call it once at startup and before the first
62
+ agent invocation.
63
+
64
+ ## Grouping and labelling runs
65
+
66
+ ```python
67
+ with rootmark.workflow_override("contract-review"):
68
+ with rootmark.bind_context(tenant_id="acme", session_id=session, tags=["surface:chat"]):
69
+ result = agent(prompt)
70
+ ```
71
+
72
+ `bind_context` applies to everything that runs inside it, including tasks the
73
+ agent loop spawns, because the binding follows the async context.
74
+
75
+ `workflow_name` should not be `"default"`: that value lets framework
76
+ instrumentation override the name you bind per run with its own agent id.
77
+
78
+ ## Naming the steps of a run
79
+
80
+ ```python
81
+ with rootmark.span("fetch_clauses", run_type=RunType.TOOL,
82
+ step_key="fetch_clauses", step_kind="retrieval"):
83
+ ...
84
+ ```
85
+
86
+ `step_key` is a stable identity for *which* logical step this is, constant
87
+ across runs; `step_kind` is what it was for (`retrieval`, `generation`,
88
+ `routing`, `review`, `tool`, `memory`). Together they let the collector answer
89
+ "which step is slow" without anyone reading individual traces.
90
+
91
+ Both are optional, and a kind the SDK does not recognise is kept rather than
92
+ dropped — your vocabulary is allowed to be ahead of ours. Derive `step_key`
93
+ from something stable: a key built from a timestamp or a request id fragments
94
+ its own aggregate, and nothing can detect that for you.
95
+
96
+ ## Long-running steps
97
+
98
+ ```python
99
+ with rootmark.span("await_approval", run_type=RunType.TOOL, heartbeat=30) as span:
100
+ rootmark.mark_waiting(span, "human_review")
101
+ decision = wait_for_approval() # minutes, or hours
102
+ ```
103
+
104
+ `mark_waiting` says the step is deliberately not working, and what it is
105
+ waiting on. The reason is free text in your own vocabulary — `human_review`,
106
+ `rate_limit`, `upstream` — and is shown back verbatim. It is the difference
107
+ between a run somebody has to investigate and one they can leave alone.
108
+
109
+ `heartbeat` re-announces the span every N seconds while it runs. Leave it unset
110
+ for anything that finishes quickly: a span is already visible from the moment
111
+ it starts, and a heartbeat for a 200 ms call is bandwidth spent to say nothing.
112
+ Set it on the long ones, where the useful question is not "is it running" but
113
+ "is anyone still on the other end" — without it, a step whose process was
114
+ killed looks exactly like one that is simply taking its time. Intervals below
115
+ five seconds are raised to five rather than refused.
116
+
117
+ **This roughly doubles the rows a run produces**, since each span is now sent
118
+ at least twice. The collector collapses the pair when it merges, so stored size
119
+ settles back; what doubles is what crosses the network.
120
+
121
+ ## Framework support
122
+
123
+ The base install instruments nothing on its own beyond direct use. Install the
124
+ extra for what you actually run:
125
+
126
+ ```bash
127
+ pip install "rootmark[openai]" # OpenAI 1.x and 2.x
128
+ pip install "rootmark[langchain]" # LangChain callback handler
129
+ pip install "rootmark[crewai]" # CrewAI event listeners
130
+ pip install "rootmark[strands]" # Strands agents / AWS Bedrock
131
+ pip install "rootmark[boto3]" # Bedrock via botocore, no code change
132
+ ```
133
+
134
+ For boto3, a session built by hand rather than the default one needs
135
+ `rootmark.patch_session(session)` — the botocore hooks only reach the default
136
+ session otherwise.
137
+
138
+ ## Delivery
139
+
140
+ Spans are batched on a background thread and flushed on a timer, so nothing
141
+ blocks a request. A failed export is written to a spill file and retried,
142
+ keeping its batch identity so the collector can recognise a replay rather than
143
+ double-count it. Ordering is preserved: a batch that cannot be delivered holds
144
+ back the ones behind it.
145
+
146
+ Point `spill_file` somewhere writable. The default is relative to the working
147
+ directory, which in a container is frequently owned by root while the process
148
+ runs as someone else — and a spill file that cannot be written is buffering you
149
+ silently do not have.
150
+
151
+ Call `rootmark.flush()` before a process exits if you want outstanding spans
152
+ delivered, and `rootmark.shutdown()` to stop the processor.
153
+
154
+ ## Keeping payloads out
155
+
156
+ ```python
157
+ rootmark.init(..., suppress_payloads=True)
158
+ ```
159
+
160
+ Spans are still recorded — timings, token counts, the shape of the run — but
161
+ prompt and completion text is not sent. Use this when the collector sits outside
162
+ the trust boundary that the data does not leave.
163
+
164
+ ## Links
165
+
166
+ - Documentation: <https://rootmark.dev/docs/>
167
+ - Source: <https://github.com/IvanAdactic/rootmark>
@@ -1,10 +1,12 @@
1
1
  [project]
2
2
  name = "rootmark"
3
- version = "0.1.0"
3
+ version = "0.1.2"
4
4
  description = "Rootmark SDK -- agent instrumentation"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.12"
7
- # No licence declared for 0.1.0; to be added in a later release.
7
+ # No licence declared as of 0.1.2; to be added in a later release. Without
8
+ # one the package defaults to all rights reserved -- see the 0.1.0 release
9
+ # commit (329e16c) for the reasoning and why it still needs revisiting.
8
10
  keywords = ["agents", "observability", "tracing", "llm", "instrumentation"]
9
11
  classifiers = [
10
12
  "Development Status :: 4 - Beta",