bluejay-sdk 0.1.0__py3-none-any.whl
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.
- bluejay_sdk/__init__.py +3 -0
- bluejay_sdk/tracing.py +135 -0
- bluejay_sdk-0.1.0.dist-info/METADATA +10 -0
- bluejay_sdk-0.1.0.dist-info/RECORD +5 -0
- bluejay_sdk-0.1.0.dist-info/WHEEL +4 -0
bluejay_sdk/__init__.py
ADDED
bluejay_sdk/tracing.py
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import os
|
|
3
|
+
|
|
4
|
+
import httpx
|
|
5
|
+
import opentelemetry.trace as otel_trace
|
|
6
|
+
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
|
|
7
|
+
from opentelemetry.sdk import trace as trace_sdk
|
|
8
|
+
from opentelemetry.sdk.resources import SERVICE_NAME, Resource
|
|
9
|
+
from opentelemetry.sdk.trace.export import SimpleSpanProcessor
|
|
10
|
+
|
|
11
|
+
logger = logging.getLogger("bluejay_sdk")
|
|
12
|
+
|
|
13
|
+
DEFAULT_OTLP_ENDPOINT = "https://otlp.getbluejay.ai/v1/traces"
|
|
14
|
+
DEFAULT_API_URL = "https://api.getbluejay.ai/v1"
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class BluejayTracing:
|
|
18
|
+
def __init__(
|
|
19
|
+
self,
|
|
20
|
+
api_key: str,
|
|
21
|
+
*,
|
|
22
|
+
service_name: str = "bluejay-agent",
|
|
23
|
+
otlp_endpoint: str = DEFAULT_OTLP_ENDPOINT,
|
|
24
|
+
api_url: str = DEFAULT_API_URL,
|
|
25
|
+
):
|
|
26
|
+
self.api_key = api_key
|
|
27
|
+
self.api_url = api_url
|
|
28
|
+
self.simulation_result_id: str | None = None
|
|
29
|
+
self.trace_id: str | None = None
|
|
30
|
+
|
|
31
|
+
resource = Resource.create({SERVICE_NAME: service_name})
|
|
32
|
+
self.tracer_provider = trace_sdk.TracerProvider(resource=resource)
|
|
33
|
+
self.tracer_provider.add_span_processor(
|
|
34
|
+
SimpleSpanProcessor(
|
|
35
|
+
OTLPSpanExporter(otlp_endpoint, headers={"X-API-KEY": api_key})
|
|
36
|
+
)
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
try:
|
|
40
|
+
from livekit.agents.telemetry import set_tracer_provider
|
|
41
|
+
|
|
42
|
+
set_tracer_provider(self.tracer_provider)
|
|
43
|
+
except ImportError:
|
|
44
|
+
pass
|
|
45
|
+
|
|
46
|
+
otel_trace.set_tracer_provider(self.tracer_provider)
|
|
47
|
+
|
|
48
|
+
@classmethod
|
|
49
|
+
def init(
|
|
50
|
+
cls,
|
|
51
|
+
api_key: str | None = None,
|
|
52
|
+
*,
|
|
53
|
+
service_name: str | None = None,
|
|
54
|
+
otlp_endpoint: str | None = None,
|
|
55
|
+
api_url: str | None = None,
|
|
56
|
+
) -> "BluejayTracing":
|
|
57
|
+
key = api_key or os.getenv("BLUEJAY_API_KEY")
|
|
58
|
+
if not key:
|
|
59
|
+
raise ValueError("BLUEJAY_API_KEY not set and no api_key provided")
|
|
60
|
+
|
|
61
|
+
return cls(
|
|
62
|
+
api_key=key,
|
|
63
|
+
service_name=service_name or os.getenv("BLUEJAY_SERVICE_NAME", "bluejay-agent"),
|
|
64
|
+
otlp_endpoint=otlp_endpoint or os.getenv("BLUEJAY_OTLP_ENDPOINT", DEFAULT_OTLP_ENDPOINT),
|
|
65
|
+
api_url=api_url or os.getenv("BLUEJAY_API_URL", DEFAULT_API_URL),
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
def link_to_session(self, ctx) -> None:
|
|
69
|
+
"""Register participant listener and shutdown callback on a LiveKit JobContext."""
|
|
70
|
+
from livekit import rtc
|
|
71
|
+
|
|
72
|
+
@ctx.room.on("participant_connected")
|
|
73
|
+
def on_participant_connected(participant: rtc.RemoteParticipant):
|
|
74
|
+
if self.simulation_result_id:
|
|
75
|
+
return
|
|
76
|
+
result_id = (participant.attributes or {}).get("X-Simulation-Result-Id")
|
|
77
|
+
if result_id:
|
|
78
|
+
self.simulation_result_id = str(result_id)
|
|
79
|
+
logger.info(f"captured simulation_result_id={result_id}")
|
|
80
|
+
|
|
81
|
+
for p in ctx.room.remote_participants.values():
|
|
82
|
+
result_id = (p.attributes or {}).get("X-Simulation-Result-Id")
|
|
83
|
+
if result_id:
|
|
84
|
+
self.simulation_result_id = str(result_id)
|
|
85
|
+
break
|
|
86
|
+
|
|
87
|
+
ctx.add_shutdown_callback(self._on_shutdown)
|
|
88
|
+
|
|
89
|
+
def capture_trace(self) -> str | None:
|
|
90
|
+
"""Capture trace_id from the current OTel span (call after session.start())."""
|
|
91
|
+
span = otel_trace.get_current_span()
|
|
92
|
+
span_ctx = span.get_span_context()
|
|
93
|
+
if span_ctx.is_valid:
|
|
94
|
+
self.trace_id = format(span_ctx.trace_id, "032x")
|
|
95
|
+
logger.info(f"agent_session trace_id={self.trace_id}")
|
|
96
|
+
return self.trace_id
|
|
97
|
+
|
|
98
|
+
async def _on_shutdown(self) -> None:
|
|
99
|
+
logger.info(f"shutdown — simulation_result_id={self.simulation_result_id} trace_id={self.trace_id}")
|
|
100
|
+
|
|
101
|
+
try:
|
|
102
|
+
self.tracer_provider.force_flush()
|
|
103
|
+
except Exception as e:
|
|
104
|
+
logger.error(f"force_flush failed: {e}")
|
|
105
|
+
|
|
106
|
+
if self.simulation_result_id and self.trace_id:
|
|
107
|
+
await self._post_result()
|
|
108
|
+
else:
|
|
109
|
+
logger.warning(f"skipping update-simulation-result — simulation_result_id={self.simulation_result_id} trace_id={self.trace_id}")
|
|
110
|
+
|
|
111
|
+
try:
|
|
112
|
+
self.tracer_provider.shutdown()
|
|
113
|
+
except Exception as e:
|
|
114
|
+
logger.error(f"tracer shutdown failed: {e}")
|
|
115
|
+
|
|
116
|
+
async def _post_result(self) -> None:
|
|
117
|
+
payload = {
|
|
118
|
+
"simulation_result_id": self.simulation_result_id,
|
|
119
|
+
"trace_ids": [self.trace_id],
|
|
120
|
+
}
|
|
121
|
+
headers = {"X-API-Key": self.api_key, "Content-Type": "application/json"}
|
|
122
|
+
|
|
123
|
+
async with httpx.AsyncClient(timeout=10) as client:
|
|
124
|
+
try:
|
|
125
|
+
resp = await client.post(
|
|
126
|
+
f"{self.api_url}/update-simulation-result",
|
|
127
|
+
json=payload,
|
|
128
|
+
headers=headers,
|
|
129
|
+
)
|
|
130
|
+
resp.raise_for_status()
|
|
131
|
+
logger.info("update-simulation-result SUCCESS")
|
|
132
|
+
except httpx.HTTPStatusError as e:
|
|
133
|
+
logger.error(f"update-simulation-result FAILED: {e.response.status_code} {e.response.text}")
|
|
134
|
+
except Exception as e:
|
|
135
|
+
logger.error(f"update-simulation-result FAILED: {e}")
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: bluejay-sdk
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Bluejay SDK for LiveKit voice agents
|
|
5
|
+
Requires-Python: >=3.10
|
|
6
|
+
Requires-Dist: httpx>=0.25
|
|
7
|
+
Requires-Dist: opentelemetry-exporter-otlp-proto-http
|
|
8
|
+
Requires-Dist: opentelemetry-sdk
|
|
9
|
+
Provides-Extra: livekit
|
|
10
|
+
Requires-Dist: livekit-agents>=1.0; extra == 'livekit'
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
bluejay_sdk/__init__.py,sha256=vNAhrGWEJmZsCscA6NrWdS7U5JInuChqUxDDuFlTT8Y,77
|
|
2
|
+
bluejay_sdk/tracing.py,sha256=zPc-PZPjUOV0OYx5TGLaV3eOx91-FXOE36e2_ZhmFLc,5070
|
|
3
|
+
bluejay_sdk-0.1.0.dist-info/METADATA,sha256=E7IRPCdXebHtC_aMI8kWlamim1hwLuVl4T6UY0drTAo,318
|
|
4
|
+
bluejay_sdk-0.1.0.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
|
|
5
|
+
bluejay_sdk-0.1.0.dist-info/RECORD,,
|