telemetry-dev-openrouter 0.1.1__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.
@@ -0,0 +1,142 @@
1
+ Metadata-Version: 2.4
2
+ Name: telemetry-dev-openrouter
3
+ Version: 0.1.1
4
+ Summary: OpenRouter integration for telemetry.dev Python SDK
5
+ Keywords: telemetry,opentelemetry,openrouter,llm,genai,tracing
6
+ Author: telemetry.dev
7
+ License-Expression: MIT
8
+ Classifier: Development Status :: 4 - Beta
9
+ Classifier: Intended Audience :: Developers
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3.10
12
+ Classifier: Programming Language :: Python :: 3.11
13
+ Classifier: Programming Language :: Python :: 3.12
14
+ Classifier: Programming Language :: Python :: 3.13
15
+ Classifier: Typing :: Typed
16
+ Requires-Dist: telemetry-dev>=0.2.0
17
+ Requires-Dist: openrouter>=1.1.0,<2
18
+ Requires-Python: >=3.10
19
+ Project-URL: Homepage, https://telemetry.dev
20
+ Project-URL: Repository, https://github.com/telemetry-dev/telemetry.dev
21
+ Description-Content-Type: text/markdown
22
+
23
+ # telemetry-dev-openrouter
24
+
25
+ OpenRouter SDK instrumentation for telemetry.dev. It wraps the official `openrouter` Python SDK
26
+ and emits telemetry.dev generation and embedding spans through `telemetry-dev`.
27
+
28
+ ## Install
29
+
30
+ ```sh
31
+ pip install telemetry-dev-openrouter
32
+ ```
33
+
34
+ Initialize the core SDK first:
35
+
36
+ ```py
37
+ import telemetry_dev
38
+
39
+ telemetry_dev.init(
40
+ api_key="td_live_...",
41
+ service_name="my-service",
42
+ )
43
+ ```
44
+
45
+ ## Per-client wrapping
46
+
47
+ ```py
48
+ from openrouter import OpenRouter
49
+ from telemetry_dev_openrouter import wrap_open_router
50
+
51
+ client = wrap_open_router(OpenRouter(api_key="sk-or-v1-..."))
52
+
53
+ client.chat.send(
54
+ model="openai/gpt-4o-mini",
55
+ messages=[{"role": "user", "content": "Tell me a joke about OpenTelemetry"}],
56
+ )
57
+ ```
58
+
59
+ Use this when you want explicit control over which clients are instrumented. The same wrapped
60
+ client supports synchronous methods and their `*_async` counterparts.
61
+
62
+ ## Global instrumentation
63
+
64
+ ```py
65
+ from openrouter import OpenRouter
66
+ from telemetry_dev_openrouter import instrument_openrouter, uninstrument_openrouter
67
+
68
+ instrument_openrouter()
69
+ client = OpenRouter(api_key="sk-or-v1-...")
70
+
71
+ try:
72
+ client.responses.send(model="openai/gpt-4o-mini", input="Explain OpenTelemetry briefly")
73
+ finally:
74
+ uninstrument_openrouter()
75
+ ```
76
+
77
+ Use this as the app-wide one-liner at startup when all OpenRouter clients should be instrumented.
78
+ Repeated wrapping or global instrumentation is safe, and `uninstrument_openrouter()` restores the
79
+ original SDK methods.
80
+
81
+ ## Instrumented surfaces
82
+
83
+ Synchronous and asynchronous variants are covered:
84
+
85
+ - `client.chat.send(...)` and `client.chat.send_async(...)`
86
+ - `client.responses.send(...)` and `client.responses.send_async(...)`
87
+ - `client.embeddings.generate(...)` and `client.embeddings.generate_async(...)`
88
+
89
+ All spans use `gen_ai.provider.name = "openrouter"`. Generation spans capture the request model and
90
+ input, supported sampling parameters, response model and ID, finish reasons, output messages, and
91
+ token usage. Embedding spans capture the request input, request and response models, and token
92
+ usage; embedding vectors are intentionally not captured as output.
93
+
94
+ When OpenRouter returns cost information, the integration records `gen_ai.usage.cost` from
95
+ `usage.cost`. If that field is absent, it falls back to
96
+ `usage.cost_details.upstream_inference_cost`. The cost attribute is omitted when neither value is
97
+ available.
98
+
99
+ ## Streaming
100
+
101
+ Chat and Responses API streams are traced for sync and async callers. The integration accumulates
102
+ captured output, records time to first chunk, and maps terminal usage and cost when OpenRouter
103
+ provides them. Terminal Responses API events close the span, including completed, failed,
104
+ incomplete, and error events.
105
+
106
+ Responses stream output can include reconstructed output items followed by bounded
107
+ `{"type": "telemetry.dev.response_stream_event", "event_type": ..., "payload": ...}` entries for
108
+ consumed image-generation lifecycle and partial-image events, apply-patch diff events, fusion
109
+ lifecycle, analysis, and panel events, web-search lifecycle events, and debug timing events.
110
+ OpenRouter debug upstream request-body echoes are not retained. These provider-event entries share
111
+ the stream capture budget and set
112
+ `telemetry.dev.capture.truncated = true` when only a prefix can be retained.
113
+
114
+ Requests are passed to OpenRouter unchanged. The integration does not add or modify
115
+ `stream_options`, so streaming usage and cost are available only when they are present in the
116
+ stream returned by OpenRouter.
117
+
118
+ ## Failure behavior
119
+
120
+ Instrumentation is fail-open when `telemetry_dev.init()` has not been called: OpenRouter requests
121
+ still execute and return their normal SDK values without exporting telemetry.
122
+
123
+ ## Limitations
124
+
125
+ - Unconsumed streams end their spans only when the stream is exhausted, errors, or is closed.
126
+ - Streaming output is retained only up to the core SDK capture budget; terminal metadata and usage
127
+ can still be recorded after the budget is reached. A span with partial captured output includes
128
+ `telemetry.dev.capture.truncated = true`.
129
+ - Only the SDK methods listed above are instrumented in this version.
130
+
131
+ ## Development
132
+
133
+ From `sdks/python-openrouter`:
134
+
135
+ ```sh
136
+ uv sync
137
+ uv run ruff format .
138
+ uv run pytest
139
+ uv run ruff format --check .
140
+ uv run ruff check .
141
+ uv run pyright
142
+ ```
@@ -0,0 +1,120 @@
1
+ # telemetry-dev-openrouter
2
+
3
+ OpenRouter SDK instrumentation for telemetry.dev. It wraps the official `openrouter` Python SDK
4
+ and emits telemetry.dev generation and embedding spans through `telemetry-dev`.
5
+
6
+ ## Install
7
+
8
+ ```sh
9
+ pip install telemetry-dev-openrouter
10
+ ```
11
+
12
+ Initialize the core SDK first:
13
+
14
+ ```py
15
+ import telemetry_dev
16
+
17
+ telemetry_dev.init(
18
+ api_key="td_live_...",
19
+ service_name="my-service",
20
+ )
21
+ ```
22
+
23
+ ## Per-client wrapping
24
+
25
+ ```py
26
+ from openrouter import OpenRouter
27
+ from telemetry_dev_openrouter import wrap_open_router
28
+
29
+ client = wrap_open_router(OpenRouter(api_key="sk-or-v1-..."))
30
+
31
+ client.chat.send(
32
+ model="openai/gpt-4o-mini",
33
+ messages=[{"role": "user", "content": "Tell me a joke about OpenTelemetry"}],
34
+ )
35
+ ```
36
+
37
+ Use this when you want explicit control over which clients are instrumented. The same wrapped
38
+ client supports synchronous methods and their `*_async` counterparts.
39
+
40
+ ## Global instrumentation
41
+
42
+ ```py
43
+ from openrouter import OpenRouter
44
+ from telemetry_dev_openrouter import instrument_openrouter, uninstrument_openrouter
45
+
46
+ instrument_openrouter()
47
+ client = OpenRouter(api_key="sk-or-v1-...")
48
+
49
+ try:
50
+ client.responses.send(model="openai/gpt-4o-mini", input="Explain OpenTelemetry briefly")
51
+ finally:
52
+ uninstrument_openrouter()
53
+ ```
54
+
55
+ Use this as the app-wide one-liner at startup when all OpenRouter clients should be instrumented.
56
+ Repeated wrapping or global instrumentation is safe, and `uninstrument_openrouter()` restores the
57
+ original SDK methods.
58
+
59
+ ## Instrumented surfaces
60
+
61
+ Synchronous and asynchronous variants are covered:
62
+
63
+ - `client.chat.send(...)` and `client.chat.send_async(...)`
64
+ - `client.responses.send(...)` and `client.responses.send_async(...)`
65
+ - `client.embeddings.generate(...)` and `client.embeddings.generate_async(...)`
66
+
67
+ All spans use `gen_ai.provider.name = "openrouter"`. Generation spans capture the request model and
68
+ input, supported sampling parameters, response model and ID, finish reasons, output messages, and
69
+ token usage. Embedding spans capture the request input, request and response models, and token
70
+ usage; embedding vectors are intentionally not captured as output.
71
+
72
+ When OpenRouter returns cost information, the integration records `gen_ai.usage.cost` from
73
+ `usage.cost`. If that field is absent, it falls back to
74
+ `usage.cost_details.upstream_inference_cost`. The cost attribute is omitted when neither value is
75
+ available.
76
+
77
+ ## Streaming
78
+
79
+ Chat and Responses API streams are traced for sync and async callers. The integration accumulates
80
+ captured output, records time to first chunk, and maps terminal usage and cost when OpenRouter
81
+ provides them. Terminal Responses API events close the span, including completed, failed,
82
+ incomplete, and error events.
83
+
84
+ Responses stream output can include reconstructed output items followed by bounded
85
+ `{"type": "telemetry.dev.response_stream_event", "event_type": ..., "payload": ...}` entries for
86
+ consumed image-generation lifecycle and partial-image events, apply-patch diff events, fusion
87
+ lifecycle, analysis, and panel events, web-search lifecycle events, and debug timing events.
88
+ OpenRouter debug upstream request-body echoes are not retained. These provider-event entries share
89
+ the stream capture budget and set
90
+ `telemetry.dev.capture.truncated = true` when only a prefix can be retained.
91
+
92
+ Requests are passed to OpenRouter unchanged. The integration does not add or modify
93
+ `stream_options`, so streaming usage and cost are available only when they are present in the
94
+ stream returned by OpenRouter.
95
+
96
+ ## Failure behavior
97
+
98
+ Instrumentation is fail-open when `telemetry_dev.init()` has not been called: OpenRouter requests
99
+ still execute and return their normal SDK values without exporting telemetry.
100
+
101
+ ## Limitations
102
+
103
+ - Unconsumed streams end their spans only when the stream is exhausted, errors, or is closed.
104
+ - Streaming output is retained only up to the core SDK capture budget; terminal metadata and usage
105
+ can still be recorded after the budget is reached. A span with partial captured output includes
106
+ `telemetry.dev.capture.truncated = true`.
107
+ - Only the SDK methods listed above are instrumented in this version.
108
+
109
+ ## Development
110
+
111
+ From `sdks/python-openrouter`:
112
+
113
+ ```sh
114
+ uv sync
115
+ uv run ruff format .
116
+ uv run pytest
117
+ uv run ruff format --check .
118
+ uv run ruff check .
119
+ uv run pyright
120
+ ```
@@ -0,0 +1,78 @@
1
+ [project]
2
+ name = "telemetry-dev-openrouter"
3
+ version = "0.1.1"
4
+ description = "OpenRouter integration for telemetry.dev Python SDK"
5
+ readme = "README.md"
6
+ license = "MIT"
7
+ requires-python = ">=3.10"
8
+ keywords = [
9
+ "telemetry",
10
+ "opentelemetry",
11
+ "openrouter",
12
+ "llm",
13
+ "genai",
14
+ "tracing",
15
+ ]
16
+ classifiers = [
17
+ "Development Status :: 4 - Beta",
18
+ "Intended Audience :: Developers",
19
+ "Programming Language :: Python :: 3",
20
+ "Programming Language :: Python :: 3.10",
21
+ "Programming Language :: Python :: 3.11",
22
+ "Programming Language :: Python :: 3.12",
23
+ "Programming Language :: Python :: 3.13",
24
+ "Typing :: Typed",
25
+ ]
26
+ dependencies = [
27
+ "telemetry-dev>=0.2.0",
28
+ "openrouter>=1.1.0,<2",
29
+ ]
30
+
31
+ [[project.authors]]
32
+ name = "telemetry.dev"
33
+
34
+ [project.urls]
35
+ Homepage = "https://telemetry.dev"
36
+ Repository = "https://github.com/telemetry-dev/telemetry.dev"
37
+
38
+ [tool.uv.sources.telemetry-dev]
39
+ path = "../python"
40
+ editable = true
41
+
42
+ [tool.pytest.ini_options]
43
+ asyncio_mode = "auto"
44
+ testpaths = ["tests"]
45
+
46
+ [tool.ruff]
47
+ line-length = 100
48
+ target-version = "py310"
49
+
50
+ [tool.ruff.lint]
51
+ select = [
52
+ "E",
53
+ "F",
54
+ "I",
55
+ "UP",
56
+ "B",
57
+ "RUF",
58
+ ]
59
+
60
+ [tool.pyright]
61
+ include = [
62
+ "src",
63
+ "tests",
64
+ ]
65
+ typeCheckingMode = "strict"
66
+ pythonVersion = "3.10"
67
+
68
+ [dependency-groups]
69
+ dev = [
70
+ "pytest>=8.3",
71
+ "pytest-asyncio>=0.25",
72
+ "ruff>=0.9",
73
+ "pyright>=1.1.390",
74
+ ]
75
+
76
+ [build-system]
77
+ requires = ["uv_build>=0.9.0,<0.10.0"]
78
+ build-backend = "uv_build"
@@ -0,0 +1,58 @@
1
+ [project]
2
+ name = "telemetry-dev-openrouter"
3
+ version = "0.1.1"
4
+ description = "OpenRouter integration for telemetry.dev Python SDK"
5
+ readme = "README.md"
6
+ license = "MIT"
7
+ requires-python = ">=3.10"
8
+ authors = [{ name = "telemetry.dev" }]
9
+ keywords = ["telemetry", "opentelemetry", "openrouter", "llm", "genai", "tracing"]
10
+ classifiers = [
11
+ "Development Status :: 4 - Beta",
12
+ "Intended Audience :: Developers",
13
+ "Programming Language :: Python :: 3",
14
+ "Programming Language :: Python :: 3.10",
15
+ "Programming Language :: Python :: 3.11",
16
+ "Programming Language :: Python :: 3.12",
17
+ "Programming Language :: Python :: 3.13",
18
+ "Typing :: Typed",
19
+ ]
20
+ dependencies = [
21
+ "telemetry-dev>=0.2.0",
22
+ "openrouter>=1.1.0,<2",
23
+ ]
24
+
25
+ [project.urls]
26
+ Homepage = "https://telemetry.dev"
27
+ Repository = "https://github.com/telemetry-dev/telemetry.dev"
28
+
29
+ [tool.uv.sources]
30
+ telemetry-dev = { path = "../python", editable = true }
31
+
32
+ [dependency-groups]
33
+ dev = [
34
+ "pytest>=8.3",
35
+ "pytest-asyncio>=0.25",
36
+ "ruff>=0.9",
37
+ "pyright>=1.1.390",
38
+ ]
39
+
40
+ [build-system]
41
+ requires = ["uv_build>=0.9.0,<0.10.0"]
42
+ build-backend = "uv_build"
43
+
44
+ [tool.pytest.ini_options]
45
+ asyncio_mode = "auto"
46
+ testpaths = ["tests"]
47
+
48
+ [tool.ruff]
49
+ line-length = 100
50
+ target-version = "py310"
51
+
52
+ [tool.ruff.lint]
53
+ select = ["E", "F", "I", "UP", "B", "RUF"]
54
+
55
+ [tool.pyright]
56
+ include = ["src", "tests"]
57
+ typeCheckingMode = "strict"
58
+ pythonVersion = "3.10"