loopers-client 0.4.0__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,117 @@
1
+ Metadata-Version: 2.4
2
+ Name: loopers-client
3
+ Version: 0.4.0
4
+ Summary: A premium Python client wrapper for the Loopers AI budget & rate-limit proxy.
5
+ License: MIT
6
+ Classifier: Programming Language :: Python :: 3
7
+ Classifier: License :: OSI Approved :: MIT License
8
+ Classifier: Operating System :: OS Independent
9
+ Requires-Python: >=3.7
10
+ Description-Content-Type: text/markdown
11
+ Requires-Dist: httpx>=0.20.0
12
+ Provides-Extra: openai
13
+ Requires-Dist: openai>=1.0.0; extra == "openai"
14
+ Provides-Extra: anthropic
15
+ Requires-Dist: anthropic>=0.3.0; extra == "anthropic"
16
+
17
+ # Loopers Python Client SDK (`loopers-client`)
18
+
19
+ The `loopers-client` package provides a drop-in wrapper around official OpenAI and Anthropic SDK clients to make integration with the Loopers cost firewall seamless.
20
+
21
+ ## Installation
22
+
23
+ ```bash
24
+ pip install loopers-client
25
+ ```
26
+
27
+ Additionally, install the official provider package you plan to use:
28
+
29
+ ```bash
30
+ pip install openai
31
+ # or
32
+ pip install anthropic
33
+ ```
34
+
35
+ ## Features
36
+
37
+ - **Automatic Headers Injection**: Automatically handles injection of Loopers proxy keys (`Authorization`), upstream provider keys (`X-Loopers-Provider-Key`), and session budget limits.
38
+ - **Custom Attributes**: Intercepts response headers and attaches cost metadata directly to the returned objects.
39
+
40
+ ## Usage
41
+
42
+ ### OpenAI Integration
43
+
44
+ Replace `openai.OpenAI` with `LoopersOpenAI`:
45
+
46
+ ```python
47
+ from loopers_client import LoopersOpenAI
48
+
49
+ # Initialize client
50
+ client = LoopersOpenAI(
51
+ loopers_url="http://localhost:8080",
52
+ loopers_key="lp-xxx", # Loopers proxy key
53
+ provider_key="sk-proj-xxx", # Upstream OpenAI key
54
+ session_id="agent-run-123", # Optional: track steps and budget for an agent session
55
+ session_budget=2.50, # Optional: limit session to $2.50
56
+ max_steps=20 # Optional: limit session to 20 steps
57
+ )
58
+
59
+ # Call completions exactly like the official client
60
+ response = client.chat.completions.create(
61
+ model="gpt-4o",
62
+ messages=[{"role": "user", "content": "Hello!"}],
63
+ )
64
+
65
+ # Inspect budget/cost metadata attached to response
66
+ print(f"Request Cost: ${response.loopers_cost} USD")
67
+ print(f"Estimated Cost: ${response.loopers_cost_estimated} USD")
68
+ print(f"Session Spend: ${response.loopers_session_spend} USD")
69
+ print(f"Session Steps: {response.loopers_session_steps}")
70
+ print(f"Session Remaining: ${response.loopers_session_remaining} USD")
71
+ ```
72
+
73
+ ### Async OpenAI
74
+
75
+ ```python
76
+ import asyncio
77
+ from loopers_client import LoopersAsyncOpenAI
78
+
79
+ async def main():
80
+ client = LoopersAsyncOpenAI(
81
+ loopers_url="http://localhost:8080",
82
+ loopers_key="lp-xxx",
83
+ provider_key="sk-proj-xxx"
84
+ )
85
+
86
+ response = await client.chat.completions.create(
87
+ model="gpt-4o",
88
+ messages=[{"role": "user", "content": "Hello!"}]
89
+ )
90
+ print(response.loopers_cost)
91
+
92
+ asyncio.run(main())
93
+ ```
94
+
95
+ ### Anthropic Integration
96
+
97
+ ```python
98
+ from loopers_client import LoopersAnthropic
99
+
100
+ client = LoopersAnthropic(
101
+ loopers_url="http://localhost:8080",
102
+ loopers_key="lp-xxx",
103
+ provider_key="sk-ant-xxx"
104
+ )
105
+
106
+ response = client.messages.create(
107
+ model="claude-3-5-sonnet-latest",
108
+ max_tokens=1000,
109
+ messages=[{"role": "user", "content": "Hello!"}]
110
+ )
111
+
112
+ print(response.loopers_cost)
113
+ ```
114
+
115
+ ## License
116
+
117
+ MIT
@@ -0,0 +1,101 @@
1
+ # Loopers Python Client SDK (`loopers-client`)
2
+
3
+ The `loopers-client` package provides a drop-in wrapper around official OpenAI and Anthropic SDK clients to make integration with the Loopers cost firewall seamless.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pip install loopers-client
9
+ ```
10
+
11
+ Additionally, install the official provider package you plan to use:
12
+
13
+ ```bash
14
+ pip install openai
15
+ # or
16
+ pip install anthropic
17
+ ```
18
+
19
+ ## Features
20
+
21
+ - **Automatic Headers Injection**: Automatically handles injection of Loopers proxy keys (`Authorization`), upstream provider keys (`X-Loopers-Provider-Key`), and session budget limits.
22
+ - **Custom Attributes**: Intercepts response headers and attaches cost metadata directly to the returned objects.
23
+
24
+ ## Usage
25
+
26
+ ### OpenAI Integration
27
+
28
+ Replace `openai.OpenAI` with `LoopersOpenAI`:
29
+
30
+ ```python
31
+ from loopers_client import LoopersOpenAI
32
+
33
+ # Initialize client
34
+ client = LoopersOpenAI(
35
+ loopers_url="http://localhost:8080",
36
+ loopers_key="lp-xxx", # Loopers proxy key
37
+ provider_key="sk-proj-xxx", # Upstream OpenAI key
38
+ session_id="agent-run-123", # Optional: track steps and budget for an agent session
39
+ session_budget=2.50, # Optional: limit session to $2.50
40
+ max_steps=20 # Optional: limit session to 20 steps
41
+ )
42
+
43
+ # Call completions exactly like the official client
44
+ response = client.chat.completions.create(
45
+ model="gpt-4o",
46
+ messages=[{"role": "user", "content": "Hello!"}],
47
+ )
48
+
49
+ # Inspect budget/cost metadata attached to response
50
+ print(f"Request Cost: ${response.loopers_cost} USD")
51
+ print(f"Estimated Cost: ${response.loopers_cost_estimated} USD")
52
+ print(f"Session Spend: ${response.loopers_session_spend} USD")
53
+ print(f"Session Steps: {response.loopers_session_steps}")
54
+ print(f"Session Remaining: ${response.loopers_session_remaining} USD")
55
+ ```
56
+
57
+ ### Async OpenAI
58
+
59
+ ```python
60
+ import asyncio
61
+ from loopers_client import LoopersAsyncOpenAI
62
+
63
+ async def main():
64
+ client = LoopersAsyncOpenAI(
65
+ loopers_url="http://localhost:8080",
66
+ loopers_key="lp-xxx",
67
+ provider_key="sk-proj-xxx"
68
+ )
69
+
70
+ response = await client.chat.completions.create(
71
+ model="gpt-4o",
72
+ messages=[{"role": "user", "content": "Hello!"}]
73
+ )
74
+ print(response.loopers_cost)
75
+
76
+ asyncio.run(main())
77
+ ```
78
+
79
+ ### Anthropic Integration
80
+
81
+ ```python
82
+ from loopers_client import LoopersAnthropic
83
+
84
+ client = LoopersAnthropic(
85
+ loopers_url="http://localhost:8080",
86
+ loopers_key="lp-xxx",
87
+ provider_key="sk-ant-xxx"
88
+ )
89
+
90
+ response = client.messages.create(
91
+ model="claude-3-5-sonnet-latest",
92
+ max_tokens=1000,
93
+ messages=[{"role": "user", "content": "Hello!"}]
94
+ )
95
+
96
+ print(response.loopers_cost)
97
+ ```
98
+
99
+ ## License
100
+
101
+ MIT
@@ -0,0 +1,13 @@
1
+ from .client import (
2
+ LoopersOpenAI,
3
+ LoopersAsyncOpenAI,
4
+ LoopersAnthropic,
5
+ LoopersAsyncAnthropic,
6
+ )
7
+
8
+ __all__ = [
9
+ "LoopersOpenAI",
10
+ "LoopersAsyncOpenAI",
11
+ "LoopersAnthropic",
12
+ "LoopersAsyncAnthropic",
13
+ ]
@@ -0,0 +1,294 @@
1
+ import contextvars
2
+ from typing import Optional, Any
3
+
4
+ import httpx
5
+
6
+ # Context variable to hold response headers of the last request safely in multithreaded/async contexts
7
+ _last_headers_context = contextvars.ContextVar("last_headers", default={})
8
+
9
+ def _get_last_headers() -> dict:
10
+ return _last_headers_context.get()
11
+
12
+ def _set_last_headers(headers: dict):
13
+ _last_headers_context.set(headers)
14
+
15
+ def _response_hook(response: httpx.Response):
16
+ headers = response.headers
17
+ loopers_headers = {
18
+ "cost": headers.get("X-Loopers-Request-Cost"),
19
+ "cost_estimated": headers.get("X-Loopers-Request-Cost-Estimated"),
20
+ "session_spend": headers.get("X-Loopers-Session-Spend"),
21
+ "session_steps": headers.get("X-Loopers-Session-Steps"),
22
+ "session_remaining": headers.get("X-Loopers-Session-Remaining"),
23
+ }
24
+ _set_last_headers(loopers_headers)
25
+
26
+ async def _async_response_hook(response: httpx.Response):
27
+ _response_hook(response)
28
+
29
+ def _attach_loopers_attributes(res: Any):
30
+ headers = _get_last_headers()
31
+ if not headers:
32
+ return
33
+
34
+ # Safely attach Loopers metrics to the returned resource/completion/stream object
35
+ for name, header_key in [
36
+ ("loopers_cost", "cost"),
37
+ ("loopers_cost_estimated", "cost_estimated"),
38
+ ("loopers_session_spend", "session_spend"),
39
+ ("loopers_session_remaining", "session_remaining"),
40
+ ]:
41
+ val = headers.get(header_key)
42
+ try:
43
+ setattr(res, name, float(val) if val else None)
44
+ except Exception:
45
+ pass
46
+
47
+ steps_val = headers.get("session_steps")
48
+ try:
49
+ setattr(res, "loopers_session_steps", int(steps_val) if steps_val else None)
50
+ except Exception:
51
+ pass
52
+
53
+
54
+ # Try importing openai
55
+ try:
56
+ import openai
57
+ HAS_OPENAI = True
58
+ except ImportError:
59
+ HAS_OPENAI = False
60
+
61
+ if HAS_OPENAI:
62
+ class LoopersOpenAI(openai.OpenAI):
63
+ """
64
+ A subclass of openai.OpenAI that automatically routes calls through
65
+ the Loopers budget/rate-limit proxy and parses response metrics.
66
+ """
67
+ def __init__(
68
+ self,
69
+ loopers_url: str,
70
+ loopers_key: str,
71
+ provider_key: Optional[str] = None,
72
+ session_id: Optional[str] = None,
73
+ session_budget: Optional[float] = None,
74
+ max_steps: Optional[int] = None,
75
+ **kwargs
76
+ ):
77
+ # Intercept event hooks to capture Loopers response headers
78
+ event_hooks = kwargs.pop("event_hooks", {})
79
+ if "response" not in event_hooks:
80
+ event_hooks["response"] = []
81
+ event_hooks["response"].append(_response_hook)
82
+
83
+ if "http_client" not in kwargs:
84
+ kwargs["http_client"] = httpx.Client(event_hooks=event_hooks)
85
+
86
+ base_url = f"{loopers_url.rstrip('/')}/openai/v1"
87
+
88
+ default_headers = kwargs.pop("default_headers", {})
89
+ default_headers["Authorization"] = f"Bearer {loopers_key}"
90
+ if provider_key:
91
+ default_headers["X-Loopers-Provider-Key"] = provider_key
92
+ if session_id:
93
+ default_headers["X-Loopers-Session-ID"] = session_id
94
+ if session_budget is not None:
95
+ default_headers["X-Loopers-Session-Budget"] = str(session_budget)
96
+ if max_steps is not None:
97
+ default_headers["X-Loopers-Session-Max-Steps"] = str(max_steps)
98
+
99
+ super().__init__(
100
+ base_url=base_url,
101
+ api_key=loopers_key,
102
+ default_headers=default_headers,
103
+ **kwargs
104
+ )
105
+
106
+ def request(self, *args, **kwargs):
107
+ _set_last_headers({})
108
+ res = super().request(*args, **kwargs)
109
+ _attach_loopers_attributes(res)
110
+ return res
111
+
112
+ class LoopersAsyncOpenAI(openai.AsyncOpenAI):
113
+ """
114
+ A subclass of openai.AsyncOpenAI that automatically routes calls through
115
+ the Loopers budget/rate-limit proxy and parses response metrics.
116
+ """
117
+ def __init__(
118
+ self,
119
+ loopers_url: str,
120
+ loopers_key: str,
121
+ provider_key: Optional[str] = None,
122
+ session_id: Optional[str] = None,
123
+ session_budget: Optional[float] = None,
124
+ max_steps: Optional[int] = None,
125
+ **kwargs
126
+ ):
127
+ event_hooks = kwargs.pop("event_hooks", {})
128
+ if "response" not in event_hooks:
129
+ event_hooks["response"] = []
130
+ event_hooks["response"].append(_async_response_hook)
131
+
132
+ if "http_client" not in kwargs:
133
+ kwargs["http_client"] = httpx.AsyncClient(event_hooks=event_hooks)
134
+
135
+ base_url = f"{loopers_url.rstrip('/')}/openai/v1"
136
+
137
+ default_headers = kwargs.pop("default_headers", {})
138
+ default_headers["Authorization"] = f"Bearer {loopers_key}"
139
+ if provider_key:
140
+ default_headers["X-Loopers-Provider-Key"] = provider_key
141
+ if session_id:
142
+ default_headers["X-Loopers-Session-ID"] = session_id
143
+ if session_budget is not None:
144
+ default_headers["X-Loopers-Session-Budget"] = str(session_budget)
145
+ if max_steps is not None:
146
+ default_headers["X-Loopers-Session-Max-Steps"] = str(max_steps)
147
+
148
+ super().__init__(
149
+ base_url=base_url,
150
+ api_key=loopers_key,
151
+ default_headers=default_headers,
152
+ **kwargs
153
+ )
154
+
155
+ async def request(self, *args, **kwargs):
156
+ _set_last_headers({})
157
+ res = await super().request(*args, **kwargs)
158
+ _attach_loopers_attributes(res)
159
+ return res
160
+ else:
161
+ class LoopersOpenAI:
162
+ def __init__(self, *args, **kwargs):
163
+ raise ImportError(
164
+ "The 'openai' package is required to use LoopersOpenAI. "
165
+ "Install it via 'pip install openai'."
166
+ )
167
+
168
+ class LoopersAsyncOpenAI:
169
+ def __init__(self, *args, **kwargs):
170
+ raise ImportError(
171
+ "The 'openai' package is required to use LoopersAsyncOpenAI. "
172
+ "Install it via 'pip install openai'."
173
+ )
174
+
175
+
176
+ # Try importing anthropic
177
+ try:
178
+ import anthropic
179
+ HAS_ANTHROPIC = True
180
+ except ImportError:
181
+ HAS_ANTHROPIC = False
182
+
183
+ if HAS_ANTHROPIC:
184
+ class LoopersAnthropic(anthropic.Anthropic):
185
+ """
186
+ A subclass of anthropic.Anthropic that automatically routes calls through
187
+ the Loopers budget/rate-limit proxy and parses response metrics.
188
+ """
189
+ def __init__(
190
+ self,
191
+ loopers_url: str,
192
+ loopers_key: str,
193
+ provider_key: Optional[str] = None,
194
+ session_id: Optional[str] = None,
195
+ session_budget: Optional[float] = None,
196
+ max_steps: Optional[int] = None,
197
+ **kwargs
198
+ ):
199
+ event_hooks = kwargs.pop("event_hooks", {})
200
+ if "response" not in event_hooks:
201
+ event_hooks["response"] = []
202
+ event_hooks["response"].append(_response_hook)
203
+
204
+ if "http_client" not in kwargs:
205
+ kwargs["http_client"] = httpx.Client(event_hooks=event_hooks)
206
+
207
+ base_url = f"{loopers_url.rstrip('/')}/anthropic"
208
+
209
+ default_headers = kwargs.pop("default_headers", {})
210
+ default_headers["Authorization"] = f"Bearer {loopers_key}"
211
+ if provider_key:
212
+ default_headers["X-Loopers-Provider-Key"] = provider_key
213
+ if session_id:
214
+ default_headers["X-Loopers-Session-ID"] = session_id
215
+ if session_budget is not None:
216
+ default_headers["X-Loopers-Session-Budget"] = str(session_budget)
217
+ if max_steps is not None:
218
+ default_headers["X-Loopers-Session-Max-Steps"] = str(max_steps)
219
+
220
+ super().__init__(
221
+ base_url=base_url,
222
+ auth_token=loopers_key,
223
+ default_headers=default_headers,
224
+ **kwargs
225
+ )
226
+
227
+ def request(self, *args, **kwargs):
228
+ _set_last_headers({})
229
+ res = super().request(*args, **kwargs)
230
+ _attach_loopers_attributes(res)
231
+ return res
232
+
233
+ class LoopersAsyncAnthropic(anthropic.AsyncAnthropic):
234
+ """
235
+ A subclass of anthropic.AsyncAnthropic that automatically routes calls through
236
+ the Loopers budget/rate-limit proxy and parses response metrics.
237
+ """
238
+ def __init__(
239
+ self,
240
+ loopers_url: str,
241
+ loopers_key: str,
242
+ provider_key: Optional[str] = None,
243
+ session_id: Optional[str] = None,
244
+ session_budget: Optional[float] = None,
245
+ max_steps: Optional[int] = None,
246
+ **kwargs
247
+ ):
248
+ event_hooks = kwargs.pop("event_hooks", {})
249
+ if "response" not in event_hooks:
250
+ event_hooks["response"] = []
251
+ event_hooks["response"].append(_async_response_hook)
252
+
253
+ if "http_client" not in kwargs:
254
+ kwargs["http_client"] = httpx.AsyncClient(event_hooks=event_hooks)
255
+
256
+ base_url = f"{loopers_url.rstrip('/')}/anthropic"
257
+
258
+ default_headers = kwargs.pop("default_headers", {})
259
+ default_headers["Authorization"] = f"Bearer {loopers_key}"
260
+ if provider_key:
261
+ default_headers["X-Loopers-Provider-Key"] = provider_key
262
+ if session_id:
263
+ default_headers["X-Loopers-Session-ID"] = session_id
264
+ if session_budget is not None:
265
+ default_headers["X-Loopers-Session-Budget"] = str(session_budget)
266
+ if max_steps is not None:
267
+ default_headers["X-Loopers-Session-Max-Steps"] = str(max_steps)
268
+
269
+ super().__init__(
270
+ base_url=base_url,
271
+ auth_token=loopers_key,
272
+ default_headers=default_headers,
273
+ **kwargs
274
+ )
275
+
276
+ async def request(self, *args, **kwargs):
277
+ _set_last_headers({})
278
+ res = await super().request(*args, **kwargs)
279
+ _attach_loopers_attributes(res)
280
+ return res
281
+ else:
282
+ class LoopersAnthropic:
283
+ def __init__(self, *args, **kwargs):
284
+ raise ImportError(
285
+ "The 'anthropic' package is required to use LoopersAnthropic. "
286
+ "Install it via 'pip install anthropic'."
287
+ )
288
+
289
+ class LoopersAsyncAnthropic:
290
+ def __init__(self, *args, **kwargs):
291
+ raise ImportError(
292
+ "The 'anthropic' package is required to use LoopersAsyncAnthropic. "
293
+ "Install it via 'pip install anthropic'."
294
+ )
@@ -0,0 +1,117 @@
1
+ Metadata-Version: 2.4
2
+ Name: loopers-client
3
+ Version: 0.4.0
4
+ Summary: A premium Python client wrapper for the Loopers AI budget & rate-limit proxy.
5
+ License: MIT
6
+ Classifier: Programming Language :: Python :: 3
7
+ Classifier: License :: OSI Approved :: MIT License
8
+ Classifier: Operating System :: OS Independent
9
+ Requires-Python: >=3.7
10
+ Description-Content-Type: text/markdown
11
+ Requires-Dist: httpx>=0.20.0
12
+ Provides-Extra: openai
13
+ Requires-Dist: openai>=1.0.0; extra == "openai"
14
+ Provides-Extra: anthropic
15
+ Requires-Dist: anthropic>=0.3.0; extra == "anthropic"
16
+
17
+ # Loopers Python Client SDK (`loopers-client`)
18
+
19
+ The `loopers-client` package provides a drop-in wrapper around official OpenAI and Anthropic SDK clients to make integration with the Loopers cost firewall seamless.
20
+
21
+ ## Installation
22
+
23
+ ```bash
24
+ pip install loopers-client
25
+ ```
26
+
27
+ Additionally, install the official provider package you plan to use:
28
+
29
+ ```bash
30
+ pip install openai
31
+ # or
32
+ pip install anthropic
33
+ ```
34
+
35
+ ## Features
36
+
37
+ - **Automatic Headers Injection**: Automatically handles injection of Loopers proxy keys (`Authorization`), upstream provider keys (`X-Loopers-Provider-Key`), and session budget limits.
38
+ - **Custom Attributes**: Intercepts response headers and attaches cost metadata directly to the returned objects.
39
+
40
+ ## Usage
41
+
42
+ ### OpenAI Integration
43
+
44
+ Replace `openai.OpenAI` with `LoopersOpenAI`:
45
+
46
+ ```python
47
+ from loopers_client import LoopersOpenAI
48
+
49
+ # Initialize client
50
+ client = LoopersOpenAI(
51
+ loopers_url="http://localhost:8080",
52
+ loopers_key="lp-xxx", # Loopers proxy key
53
+ provider_key="sk-proj-xxx", # Upstream OpenAI key
54
+ session_id="agent-run-123", # Optional: track steps and budget for an agent session
55
+ session_budget=2.50, # Optional: limit session to $2.50
56
+ max_steps=20 # Optional: limit session to 20 steps
57
+ )
58
+
59
+ # Call completions exactly like the official client
60
+ response = client.chat.completions.create(
61
+ model="gpt-4o",
62
+ messages=[{"role": "user", "content": "Hello!"}],
63
+ )
64
+
65
+ # Inspect budget/cost metadata attached to response
66
+ print(f"Request Cost: ${response.loopers_cost} USD")
67
+ print(f"Estimated Cost: ${response.loopers_cost_estimated} USD")
68
+ print(f"Session Spend: ${response.loopers_session_spend} USD")
69
+ print(f"Session Steps: {response.loopers_session_steps}")
70
+ print(f"Session Remaining: ${response.loopers_session_remaining} USD")
71
+ ```
72
+
73
+ ### Async OpenAI
74
+
75
+ ```python
76
+ import asyncio
77
+ from loopers_client import LoopersAsyncOpenAI
78
+
79
+ async def main():
80
+ client = LoopersAsyncOpenAI(
81
+ loopers_url="http://localhost:8080",
82
+ loopers_key="lp-xxx",
83
+ provider_key="sk-proj-xxx"
84
+ )
85
+
86
+ response = await client.chat.completions.create(
87
+ model="gpt-4o",
88
+ messages=[{"role": "user", "content": "Hello!"}]
89
+ )
90
+ print(response.loopers_cost)
91
+
92
+ asyncio.run(main())
93
+ ```
94
+
95
+ ### Anthropic Integration
96
+
97
+ ```python
98
+ from loopers_client import LoopersAnthropic
99
+
100
+ client = LoopersAnthropic(
101
+ loopers_url="http://localhost:8080",
102
+ loopers_key="lp-xxx",
103
+ provider_key="sk-ant-xxx"
104
+ )
105
+
106
+ response = client.messages.create(
107
+ model="claude-3-5-sonnet-latest",
108
+ max_tokens=1000,
109
+ messages=[{"role": "user", "content": "Hello!"}]
110
+ )
111
+
112
+ print(response.loopers_cost)
113
+ ```
114
+
115
+ ## License
116
+
117
+ MIT
@@ -0,0 +1,9 @@
1
+ README.md
2
+ pyproject.toml
3
+ loopers_client/__init__.py
4
+ loopers_client/client.py
5
+ loopers_client.egg-info/PKG-INFO
6
+ loopers_client.egg-info/SOURCES.txt
7
+ loopers_client.egg-info/dependency_links.txt
8
+ loopers_client.egg-info/requires.txt
9
+ loopers_client.egg-info/top_level.txt
@@ -0,0 +1,7 @@
1
+ httpx>=0.20.0
2
+
3
+ [anthropic]
4
+ anthropic>=0.3.0
5
+
6
+ [openai]
7
+ openai>=1.0.0
@@ -0,0 +1 @@
1
+ loopers_client
@@ -0,0 +1,27 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "loopers-client"
7
+ version = "0.4.0"
8
+ description = "A premium Python client wrapper for the Loopers AI budget & rate-limit proxy."
9
+ readme = "README.md"
10
+ requires-python = ">=3.7"
11
+ license = { text = "MIT" }
12
+ classifiers = [
13
+ "Programming Language :: Python :: 3",
14
+ "License :: OSI Approved :: MIT License",
15
+ "Operating System :: OS Independent",
16
+ ]
17
+ dependencies = [
18
+ "httpx>=0.20.0",
19
+ ]
20
+
21
+ [project.optional-dependencies]
22
+ openai = ["openai>=1.0.0"]
23
+ anthropic = ["anthropic>=0.3.0"]
24
+
25
+ [tool.setuptools.packages.find]
26
+ where = ["."]
27
+ include = ["loopers_client*"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+