threadify-sdk 0.2.6__tar.gz → 0.2.8__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 (28) hide show
  1. {threadify_sdk-0.2.6/threadify_sdk.egg-info → threadify_sdk-0.2.8}/PKG-INFO +33 -1
  2. {threadify_sdk-0.2.6 → threadify_sdk-0.2.8}/README.md +32 -0
  3. {threadify_sdk-0.2.6 → threadify_sdk-0.2.8}/pyproject.toml +1 -1
  4. {threadify_sdk-0.2.6 → threadify_sdk-0.2.8}/threadify/connection.py +13 -0
  5. {threadify_sdk-0.2.6 → threadify_sdk-0.2.8}/threadify/models.py +1 -0
  6. {threadify_sdk-0.2.6 → threadify_sdk-0.2.8}/threadify/otel_exporter.py +17 -0
  7. {threadify_sdk-0.2.6 → threadify_sdk-0.2.8}/threadify/thread.py +4 -0
  8. {threadify_sdk-0.2.6 → threadify_sdk-0.2.8/threadify_sdk.egg-info}/PKG-INFO +33 -1
  9. {threadify_sdk-0.2.6 → threadify_sdk-0.2.8}/CHANGELOG.md +0 -0
  10. {threadify_sdk-0.2.6 → threadify_sdk-0.2.8}/LICENSE +0 -0
  11. {threadify_sdk-0.2.6 → threadify_sdk-0.2.8}/MANIFEST.in +0 -0
  12. {threadify_sdk-0.2.6 → threadify_sdk-0.2.8}/setup.cfg +0 -0
  13. {threadify_sdk-0.2.6 → threadify_sdk-0.2.8}/tests/test_client.py +0 -0
  14. {threadify_sdk-0.2.6 → threadify_sdk-0.2.8}/tests/test_connection.py +0 -0
  15. {threadify_sdk-0.2.6 → threadify_sdk-0.2.8}/tests/test_data_retriever.py +0 -0
  16. {threadify_sdk-0.2.6 → threadify_sdk-0.2.8}/tests/test_models.py +0 -0
  17. {threadify_sdk-0.2.6 → threadify_sdk-0.2.8}/tests/test_notification.py +0 -0
  18. {threadify_sdk-0.2.6 → threadify_sdk-0.2.8}/tests/test_step.py +0 -0
  19. {threadify_sdk-0.2.6 → threadify_sdk-0.2.8}/tests/test_thread.py +0 -0
  20. {threadify_sdk-0.2.6 → threadify_sdk-0.2.8}/threadify/__init__.py +0 -0
  21. {threadify_sdk-0.2.6 → threadify_sdk-0.2.8}/threadify/client.py +0 -0
  22. {threadify_sdk-0.2.6 → threadify_sdk-0.2.8}/threadify/data_retriever.py +0 -0
  23. {threadify_sdk-0.2.6 → threadify_sdk-0.2.8}/threadify/notification.py +0 -0
  24. {threadify_sdk-0.2.6 → threadify_sdk-0.2.8}/threadify/step.py +0 -0
  25. {threadify_sdk-0.2.6 → threadify_sdk-0.2.8}/threadify_sdk.egg-info/SOURCES.txt +0 -0
  26. {threadify_sdk-0.2.6 → threadify_sdk-0.2.8}/threadify_sdk.egg-info/dependency_links.txt +0 -0
  27. {threadify_sdk-0.2.6 → threadify_sdk-0.2.8}/threadify_sdk.egg-info/requires.txt +0 -0
  28. {threadify_sdk-0.2.6 → threadify_sdk-0.2.8}/threadify_sdk.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: threadify-sdk
3
- Version: 0.2.6
3
+ Version: 0.2.8
4
4
  Summary: Python SDK for Threadify — Service-delivery intelligence. Track every customer request from start to finish across every system, team, and partner. Visit: https://threadify.dev
5
5
  Author-email: Threadify Team <team@threadify.dev>
6
6
  License: MIT
@@ -167,6 +167,38 @@ This SDK follows [Semantic Versioning](https://semver.org/) and [Conventional Co
167
167
  - `feat: ...` -> Minor bump
168
168
  - `feat!: ...` or `BREAKING CHANGE: ...` -> Major bump
169
169
 
170
+ ## OpenTelemetry Integration
171
+
172
+ The Python SDK includes the OpenTelemetry SpanExporter in the core package.
173
+
174
+ ```python
175
+ from opentelemetry import trace
176
+ from opentelemetry.sdk.trace import TracerProvider
177
+ from opentelemetry.sdk.trace.export import BatchSpanProcessor
178
+ from threadify import Threadify
179
+
180
+ conn = await Threadify.connect("api-key", service_name="checkout-service")
181
+
182
+ # Create exporter
183
+ exporter = conn.create_span_exporter(options={"refs": ["order.id", "customer.id"]})
184
+
185
+ # Filter spans by name — exact match or prefix wildcard with *
186
+ exporter = conn.create_span_exporter(options={
187
+ "refs": ["order.id", "customer.id"],
188
+ "filters": ["invoke_llm", "adk.before*", "llm.*"],
189
+ })
190
+
191
+ provider = TracerProvider()
192
+ provider.add_span_processor(BatchSpanProcessor(exporter))
193
+ trace.set_tracer_provider(provider)
194
+ ```
195
+
196
+ **Filter patterns:**
197
+
198
+ - `"invoke_llm"` — exact match
199
+ - `"adk.before*"` — prefix wildcard, drops any span starting with `adk.before`
200
+ - `"llm.*"` — prefix wildcard, drops any span starting with `llm.`
201
+
170
202
  ## Testing
171
203
 
172
204
  To run the SDK tests, execute:
@@ -140,6 +140,38 @@ This SDK follows [Semantic Versioning](https://semver.org/) and [Conventional Co
140
140
  - `feat: ...` -> Minor bump
141
141
  - `feat!: ...` or `BREAKING CHANGE: ...` -> Major bump
142
142
 
143
+ ## OpenTelemetry Integration
144
+
145
+ The Python SDK includes the OpenTelemetry SpanExporter in the core package.
146
+
147
+ ```python
148
+ from opentelemetry import trace
149
+ from opentelemetry.sdk.trace import TracerProvider
150
+ from opentelemetry.sdk.trace.export import BatchSpanProcessor
151
+ from threadify import Threadify
152
+
153
+ conn = await Threadify.connect("api-key", service_name="checkout-service")
154
+
155
+ # Create exporter
156
+ exporter = conn.create_span_exporter(options={"refs": ["order.id", "customer.id"]})
157
+
158
+ # Filter spans by name — exact match or prefix wildcard with *
159
+ exporter = conn.create_span_exporter(options={
160
+ "refs": ["order.id", "customer.id"],
161
+ "filters": ["invoke_llm", "adk.before*", "llm.*"],
162
+ })
163
+
164
+ provider = TracerProvider()
165
+ provider.add_span_processor(BatchSpanProcessor(exporter))
166
+ trace.set_tracer_provider(provider)
167
+ ```
168
+
169
+ **Filter patterns:**
170
+
171
+ - `"invoke_llm"` — exact match
172
+ - `"adk.before*"` — prefix wildcard, drops any span starting with `adk.before`
173
+ - `"llm.*"` — prefix wildcard, drops any span starting with `llm.`
174
+
143
175
  ## Testing
144
176
 
145
177
  To run the SDK tests, execute:
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "threadify-sdk"
7
- version = "0.2.6"
7
+ version = "0.2.8"
8
8
  description = "Python SDK for Threadify — Service-delivery intelligence. Track every customer request from start to finish across every system, team, and partner. Visit: https://threadify.dev"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -35,6 +35,7 @@ from threadify.models import (
35
35
  FIELD_SERVICE_NAME,
36
36
  FIELD_STATUS,
37
37
  FIELD_STEP_NAME,
38
+ FIELD_TAGS,
38
39
  FIELD_THREAD_ID,
39
40
  FIELD_THREAD_ID_ACK,
40
41
  FIELD_THREAD_TOKEN,
@@ -144,6 +145,7 @@ class Connection:
144
145
  contract_name: str = "",
145
146
  service_name: str = "",
146
147
  refs: dict[str, Any] | None = None,
148
+ tags: list[str] | None = None,
147
149
  ) -> ThreadInstance:
148
150
  from threadify.thread import ThreadInstance
149
151
 
@@ -174,6 +176,13 @@ class Connection:
174
176
 
175
177
  msg[FIELD_ROLE] = role
176
178
 
179
+ # Validate and attach tags if provided
180
+ if tags:
181
+ for t in tags:
182
+ if not isinstance(t, str) or not t.strip():
183
+ raise ValueError("Each tag must be a non-empty string")
184
+ msg[FIELD_TAGS] = list(tags)
185
+
177
186
  await self._send(msg)
178
187
 
179
188
  resp = await self._wait_response(lambda m: m.get(FIELD_ACTION) == ACTION_START_THREAD)
@@ -183,6 +192,7 @@ class Connection:
183
192
 
184
193
  thread_id = resp[FIELD_THREAD_ID]
185
194
  thread = ThreadInstance(self, thread_id, contract_name, "", resp.get(FIELD_ACCESS_LEVEL, ""), None)
195
+ thread.tags = list(tags) if tags else []
186
196
  self._threads[thread_id] = thread
187
197
  self._logger.debug(f"Thread started: {thread_id}")
188
198
  return thread
@@ -464,6 +474,9 @@ class Connection:
464
474
  Args:
465
475
  options: Optional configuration dict. Supported keys:
466
476
  - ``refs``: list of attribute keys to map to Threadify refs.
477
+ - ``filters``: list of span-name patterns to drop. A trailing ``*``
478
+ acts as a wildcard prefix match; otherwise an exact match is used.
479
+ Example: ``["invoke_llm", "adk.before*", "llm.*"]``.
467
480
 
468
481
  Returns:
469
482
  A :class:`~threadify.otel_exporter.ThreadifySpanExporter` instance.
@@ -75,6 +75,7 @@ FIELD_OWNER_ID = "ownerId"
75
75
  FIELD_SEVERITY = "severity"
76
76
  FIELD_TIMESTAMP = "timestamp"
77
77
  FIELD_VIOLATION_TYPE = "violationType"
78
+ FIELD_TAGS = "tags"
78
79
 
79
80
  # Protocol status values
80
81
  STATUS_SUCCESS = "success"
@@ -73,6 +73,9 @@ class ThreadifySpanExporter(_SpanExporterBase):
73
73
  else:
74
74
  self._refs_map = {}
75
75
 
76
+ # Span-name filters; e.g. ["invoke_llm", "adk.before*", "llm.*"]
77
+ self._filters: list[str] = self._options.get("filters", [])
78
+
76
79
  # trace_id -> asyncio.Future[ThreadInstance]
77
80
  self._trace_threads: dict[str, asyncio.Future[Any]] = {}
78
81
 
@@ -111,6 +114,8 @@ class ThreadifySpanExporter(_SpanExporterBase):
111
114
 
112
115
  async def _process_all(self, spans: list[ReadableSpan]) -> None:
113
116
  for span in spans:
117
+ if self._should_drop(span.name):
118
+ continue
114
119
  await self._process_span(span)
115
120
 
116
121
  async def _process_span(self, span: ReadableSpan) -> None:
@@ -276,6 +281,18 @@ class ThreadifySpanExporter(_SpanExporterBase):
276
281
 
277
282
  return await self._trace_threads[trace_id]
278
283
 
284
+ def _should_drop(self, name: str) -> bool:
285
+ for f in self._filters:
286
+ if not f:
287
+ continue
288
+ if f.endswith("*"):
289
+ if name.startswith(f[:-1]):
290
+ return True
291
+ continue
292
+ if name == f:
293
+ return True
294
+ return False
295
+
279
296
  @staticmethod
280
297
  def _span_attr(span: ReadableSpan, key: str) -> str | None:
281
298
  value = span.attributes.get(key)
@@ -71,6 +71,7 @@ class ThreadInstance:
71
71
  self.role = role
72
72
  self.access_level = access_level
73
73
  self.refs: dict[str, str] = refs or {}
74
+ self.tags: list[str] = [] # Tags applied at thread creation (immutable)
74
75
 
75
76
  self._steps: dict[str, Any] = {}
76
77
  self._pending_waits: dict[str, _PendingWait] = {}
@@ -300,6 +301,9 @@ class ThreadInstance:
300
301
  Args:
301
302
  options: Optional configuration dict. Supported keys:
302
303
  - ``refs``: list of attribute keys to map to Threadify refs.
304
+ - ``filters``: list of span-name patterns to drop. A trailing ``*``
305
+ acts as a wildcard prefix match; otherwise an exact match is used.
306
+ Example: ``["invoke_llm", "adk.before*", "llm.*"]``.
303
307
 
304
308
  Returns:
305
309
  A :class:`~threadify.otel_exporter.ThreadifySpanExporter` instance.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: threadify-sdk
3
- Version: 0.2.6
3
+ Version: 0.2.8
4
4
  Summary: Python SDK for Threadify — Service-delivery intelligence. Track every customer request from start to finish across every system, team, and partner. Visit: https://threadify.dev
5
5
  Author-email: Threadify Team <team@threadify.dev>
6
6
  License: MIT
@@ -167,6 +167,38 @@ This SDK follows [Semantic Versioning](https://semver.org/) and [Conventional Co
167
167
  - `feat: ...` -> Minor bump
168
168
  - `feat!: ...` or `BREAKING CHANGE: ...` -> Major bump
169
169
 
170
+ ## OpenTelemetry Integration
171
+
172
+ The Python SDK includes the OpenTelemetry SpanExporter in the core package.
173
+
174
+ ```python
175
+ from opentelemetry import trace
176
+ from opentelemetry.sdk.trace import TracerProvider
177
+ from opentelemetry.sdk.trace.export import BatchSpanProcessor
178
+ from threadify import Threadify
179
+
180
+ conn = await Threadify.connect("api-key", service_name="checkout-service")
181
+
182
+ # Create exporter
183
+ exporter = conn.create_span_exporter(options={"refs": ["order.id", "customer.id"]})
184
+
185
+ # Filter spans by name — exact match or prefix wildcard with *
186
+ exporter = conn.create_span_exporter(options={
187
+ "refs": ["order.id", "customer.id"],
188
+ "filters": ["invoke_llm", "adk.before*", "llm.*"],
189
+ })
190
+
191
+ provider = TracerProvider()
192
+ provider.add_span_processor(BatchSpanProcessor(exporter))
193
+ trace.set_tracer_provider(provider)
194
+ ```
195
+
196
+ **Filter patterns:**
197
+
198
+ - `"invoke_llm"` — exact match
199
+ - `"adk.before*"` — prefix wildcard, drops any span starting with `adk.before`
200
+ - `"llm.*"` — prefix wildcard, drops any span starting with `llm.`
201
+
170
202
  ## Testing
171
203
 
172
204
  To run the SDK tests, execute:
File without changes
File without changes
File without changes