Skip to content

Commit 337a244

Browse files
authored
Merge pull request #791 from parea-ai/PAI-1069-add-sdk-header
feat: integrate with sglang
2 parents 65ea7f5 + 57945d6 commit 337a244

File tree

5 files changed

+44
-17
lines changed

5 files changed

+44
-17
lines changed

parea/__init__.py

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@
99
run the following command: ```bash pip install parea ```.
1010
"""
1111
import sys
12-
from importlib import metadata as importlib_metadata
1312

13+
from parea.api_client import get_version
1414
from parea.cache import InMemoryCache
1515
from parea.client import Parea
1616
from parea.experiment.cli import experiment as _experiment_cli
@@ -22,14 +22,6 @@
2222
from parea.wrapper.openai_raw_api_tracer import aprocess_stream_and_yield, process_stream_and_yield
2323
from parea.wrapper.utils import convert_openai_raw_to_log
2424

25-
26-
def get_version() -> str:
27-
try:
28-
return importlib_metadata.version(__name__)
29-
except importlib_metadata.PackageNotFoundError: # pragma: no cover
30-
return "unknown"
31-
32-
3325
version: str = get_version()
3426

3527

parea/api_client.py

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
from typing import Any, AsyncIterable, Callable, Dict, Optional
1+
from typing import Any, AsyncIterable, Callable, Dict, List, Optional
22

33
import asyncio
44
import json
55
import os
66
import time
77
from functools import wraps
8+
from importlib import metadata as importlib_metadata
89

910
import httpx
1011
from dotenv import load_dotenv
@@ -60,6 +61,7 @@ class HTTPClient:
6061
_instance = None
6162
base_url = os.getenv("PAREA_BASE_URL", "https://parea-ai-backend-us-9ac16cdbc7a7b006.onporter.run/api/parea/v1")
6263
api_key = None
64+
integrations: List[str] = []
6365

6466
def __new__(cls, *args, **kwargs):
6567
if cls._instance is None:
@@ -71,6 +73,20 @@ def __new__(cls, *args, **kwargs):
7173
def set_api_key(self, api_key: str):
7274
self.api_key = api_key
7375

76+
def add_integration(self, integration: str):
77+
if integration not in self.integrations:
78+
self.integrations.append(integration)
79+
80+
def _get_headers(self, api_key: Optional[str] = None) -> Dict[str, str]:
81+
headers = {
82+
"x-api-key": self.api_key or api_key,
83+
"x-sdk-version": get_version(),
84+
"x-sdk-language": "python",
85+
}
86+
if self.integrations:
87+
headers["x-sdk-integrations"] = ",".join(self.integrations)
88+
return headers
89+
7490
@retry_on_502
7591
def request(
7692
self,
@@ -83,7 +99,7 @@ def request(
8399
"""
84100
Makes an HTTP request to the specified endpoint.
85101
"""
86-
headers = {"x-api-key": self.api_key} if self.api_key else api_key
102+
headers = self._get_headers(api_key=api_key)
87103
try:
88104
response = self.sync_client.request(method, endpoint, json=data, headers=headers, params=params)
89105
response.raise_for_status()
@@ -106,7 +122,7 @@ async def request_async(
106122
"""
107123
Makes an asynchronous HTTP request to the specified endpoint.
108124
"""
109-
headers = {"x-api-key": self.api_key} if self.api_key else api_key
125+
headers = self._get_headers(api_key=api_key)
110126
try:
111127
response = await self.async_client.request(method, endpoint, json=data, headers=headers, params=params)
112128
response.raise_for_status()
@@ -128,7 +144,7 @@ def stream_request(
128144
"""
129145
Makes a streaming HTTP request to the specified endpoint, yielding chunks of data.
130146
"""
131-
headers = {"x-api-key": self.api_key} if self.api_key else api_key
147+
headers = self._get_headers(api_key=api_key)
132148
try:
133149
with self.sync_client.stream(method, endpoint, json=data, headers=headers, params=params, timeout=None) as response:
134150
response.raise_for_status()
@@ -151,7 +167,7 @@ async def stream_request_async(
151167
"""
152168
Makes an asynchronous streaming HTTP request to the specified endpoint, yielding chunks of data.
153169
"""
154-
headers = {"x-api-key": self.api_key} if self.api_key else api_key
170+
headers = self._get_headers(api_key=api_key)
155171
try:
156172
async with self.async_client.stream(method, endpoint, json=data, headers=headers, params=params, timeout=None) as response:
157173
response.raise_for_status()
@@ -200,3 +216,10 @@ def parse_event_data(byte_data):
200216
except Exception as e:
201217
print(f"Error parsing event data: {e}")
202218
return None
219+
220+
221+
def get_version() -> str:
222+
try:
223+
return importlib_metadata.version("parea-ai")
224+
except importlib_metadata.PackageNotFoundError: # pragma: no cover
225+
return "unknown"

parea/client.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,19 +76,25 @@ def __attrs_post_init__(self):
7676
parea_logger.set_client(self._client)
7777
parea_logger.set_project_uuid(self.project_uuid)
7878

79-
def wrap_openai_client(self, client: "OpenAI") -> None:
79+
def wrap_openai_client(self, client: "OpenAI", integration: Optional[str] = None) -> None:
8080
"""Only necessary for instance client with OpenAI version >= 1.0.0"""
8181
from parea.wrapper import OpenAIWrapper
8282
from parea.wrapper.openai_beta_wrapper import BetaWrappers
8383

8484
OpenAIWrapper().init(log=logger_all_possible, cache=self.cache, module_client=client)
8585
BetaWrappers(client).init()
8686

87-
def wrap_anthropic_client(self, client: "Anthropic") -> None:
87+
if integration:
88+
self._client.add_integration(integration)
89+
90+
def wrap_anthropic_client(self, client: "Anthropic", integration: Optional[str] = None) -> None:
8891
from parea.wrapper.anthropic.anthropic import AnthropicWrapper
8992

9093
AnthropicWrapper().init(log=logger_all_possible, cache=self.cache, client=client)
9194

95+
if integration:
96+
self._client.add_integration(integration)
97+
9298
def auto_trace_openai_clients(self) -> None:
9399
import openai
94100

@@ -97,6 +103,10 @@ def auto_trace_openai_clients(self) -> None:
97103
openai.AzureOpenAI = patch_openai_client_classes(openai.AzureOpenAI, self)
98104
openai.AsyncAzureOpenAI = patch_openai_client_classes(openai.AsyncAzureOpenAI, self)
99105

106+
def integrate_with_sglang(self):
107+
self.auto_trace_openai_clients()
108+
self._client.add_integration("sglang")
109+
100110
def _add_project_uuid_to_data(self, data) -> dict:
101111
data_dict = asdict(data)
102112
data_dict["project_uuid"] = self._project.uuid

parea/parea_logger.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ def record_vendor_log(self, data: Dict[str, Any], vendor: TraceIntegrations) ->
6666
data["project_uuid"] = self._project_uuid
6767
if experiment_uuid := os.getenv(PAREA_OS_ENV_EXPERIMENT_UUID, None):
6868
data["experiment_uuid"] = experiment_uuid
69+
self._client.add_integration("langchain")
6970
self._client.request(
7071
"POST",
7172
VENDOR_LOG_ENDPOINT.format(vendor=vendor.value),
@@ -76,6 +77,7 @@ async def arecord_vendor_log(self, data: Dict[str, Any], vendor: TraceIntegratio
7677
data["project_uuid"] = self._project_uuid
7778
if experiment_uuid := os.getenv(PAREA_OS_ENV_EXPERIMENT_UUID, None):
7879
data["experiment_uuid"] = experiment_uuid
80+
self._client.add_integration("langchain")
7981
await self._client.request_async(
8082
"POST",
8183
VENDOR_LOG_ENDPOINT.format(vendor=vendor.value),

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ build-backend = "poetry.core.masonry.api"
66
[tool.poetry]
77
name = "parea-ai"
88
packages = [{ include = "parea" }]
9-
version = "0.2.138"
9+
version = "0.2.139"
1010
description = "Parea python sdk"
1111
readme = "README.md"
1212
authors = ["joel-parea-ai <[email protected]>"]

0 commit comments

Comments
 (0)