swiftapi-python 1.1.1__tar.gz → 1.1.2__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.
- {swiftapi_python-1.1.1 → swiftapi_python-1.1.2}/PKG-INFO +1 -1
- {swiftapi_python-1.1.1 → swiftapi_python-1.1.2}/pyproject.toml +1 -1
- {swiftapi_python-1.1.1 → swiftapi_python-1.1.2}/swiftapi/__init__.py +1 -1
- {swiftapi_python-1.1.1 → swiftapi_python-1.1.2}/swiftapi/openai.py +64 -40
- {swiftapi_python-1.1.1 → swiftapi_python-1.1.2}/swiftapi_python.egg-info/PKG-INFO +1 -1
- {swiftapi_python-1.1.1 → swiftapi_python-1.1.2}/README.md +0 -0
- {swiftapi_python-1.1.1 → swiftapi_python-1.1.2}/setup.cfg +0 -0
- {swiftapi_python-1.1.1 → swiftapi_python-1.1.2}/swiftapi/client.py +0 -0
- {swiftapi_python-1.1.1 → swiftapi_python-1.1.2}/swiftapi/enforcement.py +0 -0
- {swiftapi_python-1.1.1 → swiftapi_python-1.1.2}/swiftapi/exceptions.py +0 -0
- {swiftapi_python-1.1.1 → swiftapi_python-1.1.2}/swiftapi/utils.py +0 -0
- {swiftapi_python-1.1.1 → swiftapi_python-1.1.2}/swiftapi/verifier.py +0 -0
- {swiftapi_python-1.1.1 → swiftapi_python-1.1.2}/swiftapi_python.egg-info/SOURCES.txt +0 -0
- {swiftapi_python-1.1.1 → swiftapi_python-1.1.2}/swiftapi_python.egg-info/dependency_links.txt +0 -0
- {swiftapi_python-1.1.1 → swiftapi_python-1.1.2}/swiftapi_python.egg-info/requires.txt +0 -0
- {swiftapi_python-1.1.1 → swiftapi_python-1.1.2}/swiftapi_python.egg-info/top_level.txt +0 -0
|
@@ -3,19 +3,19 @@ SwiftAPI Attested OpenAI - Drop-in replacement.
|
|
|
3
3
|
|
|
4
4
|
# Before (vibe coding):
|
|
5
5
|
from openai import OpenAI
|
|
6
|
-
client = OpenAI()
|
|
6
|
+
client = OpenAI(api_key="sk-...")
|
|
7
7
|
|
|
8
8
|
# After (attested):
|
|
9
9
|
from swiftapi import OpenAI
|
|
10
|
-
client = OpenAI(swiftapi_key="swiftapi_live_...")
|
|
10
|
+
client = OpenAI(swiftapi_key="swiftapi_live_...", openai_key="sk-...")
|
|
11
11
|
|
|
12
12
|
Same interface. Same return type. Every completion is cryptographically attested.
|
|
13
|
-
No attestation, no output.
|
|
13
|
+
No attestation, no output. SwiftAPI governs. OpenAI executes. You bring both keys.
|
|
14
14
|
"""
|
|
15
15
|
|
|
16
16
|
import json
|
|
17
17
|
import requests
|
|
18
|
-
from typing import List, Dict,
|
|
18
|
+
from typing import List, Dict, Optional, Any
|
|
19
19
|
|
|
20
20
|
from .exceptions import SwiftAPIError, AuthenticationError, NetworkError
|
|
21
21
|
|
|
@@ -65,16 +65,12 @@ class ChatCompletion:
|
|
|
65
65
|
class Completions:
|
|
66
66
|
"""Handles chat.completions.create() calls."""
|
|
67
67
|
|
|
68
|
-
def __init__(self,
|
|
69
|
-
self.
|
|
70
|
-
self.
|
|
68
|
+
def __init__(self, swiftapi_key: str, openai_key: str, authority_url: str, timeout: int):
|
|
69
|
+
self._swiftapi_key = swiftapi_key
|
|
70
|
+
self._openai_key = openai_key
|
|
71
|
+
self._authority_url = authority_url.rstrip("/")
|
|
71
72
|
self._timeout = timeout
|
|
72
73
|
self._session = requests.Session()
|
|
73
|
-
self._session.headers.update({
|
|
74
|
-
"X-SwiftAPI-Authority": key,
|
|
75
|
-
"Content-Type": "application/json",
|
|
76
|
-
"User-Agent": "swiftapi-python/1.1.0",
|
|
77
|
-
})
|
|
78
74
|
|
|
79
75
|
def create(
|
|
80
76
|
self,
|
|
@@ -89,10 +85,13 @@ class Completions:
|
|
|
89
85
|
Create an attested chat completion.
|
|
90
86
|
|
|
91
87
|
Same interface as openai.chat.completions.create().
|
|
92
|
-
|
|
88
|
+
Step 1: Attest with SwiftAPI (governance).
|
|
89
|
+
Step 2: Call OpenAI directly with your key (execution).
|
|
90
|
+
|
|
91
|
+
If governance denies, content is empty string. Void.
|
|
93
92
|
|
|
94
93
|
Args:
|
|
95
|
-
model: Model name (e.g. "gpt-4o
|
|
94
|
+
model: Model name (e.g. "gpt-4o")
|
|
96
95
|
messages: List of message dicts with role and content
|
|
97
96
|
temperature: Sampling temperature
|
|
98
97
|
max_completion_tokens: Max tokens in response
|
|
@@ -101,18 +100,25 @@ class Completions:
|
|
|
101
100
|
Returns:
|
|
102
101
|
ChatCompletion with .choices[0].message.content
|
|
103
102
|
"""
|
|
103
|
+
effective_max = max_tokens or max_completion_tokens
|
|
104
|
+
|
|
104
105
|
payload = {
|
|
105
106
|
"model": model,
|
|
106
107
|
"messages": messages,
|
|
107
108
|
"temperature": temperature,
|
|
108
|
-
"max_completion_tokens":
|
|
109
|
+
"max_completion_tokens": effective_max,
|
|
109
110
|
}
|
|
110
111
|
|
|
111
|
-
# Step 1: Attest
|
|
112
|
+
# Step 1: Attest with SwiftAPI — governance check
|
|
112
113
|
try:
|
|
113
114
|
attest_resp = self._session.post(
|
|
114
|
-
f"{self.
|
|
115
|
+
f"{self._authority_url}/attest",
|
|
115
116
|
json={"action_type": "chat_completion", "action_data": payload},
|
|
117
|
+
headers={
|
|
118
|
+
"X-SwiftAPI-Authority": self._swiftapi_key,
|
|
119
|
+
"Content-Type": "application/json",
|
|
120
|
+
"User-Agent": "swiftapi-python/1.1.1",
|
|
121
|
+
},
|
|
116
122
|
timeout=self._timeout,
|
|
117
123
|
)
|
|
118
124
|
except requests.exceptions.RequestException as e:
|
|
@@ -130,25 +136,36 @@ class Completions:
|
|
|
130
136
|
if not attestation.get("approved"):
|
|
131
137
|
return ChatCompletion(content="", model=model)
|
|
132
138
|
|
|
133
|
-
# Step 2:
|
|
139
|
+
# Step 2: Call OpenAI directly — user's own key, user's own credits
|
|
140
|
+
openai_payload = {
|
|
141
|
+
"model": model,
|
|
142
|
+
"messages": messages,
|
|
143
|
+
"temperature": temperature,
|
|
144
|
+
"max_completion_tokens": effective_max,
|
|
145
|
+
}
|
|
146
|
+
openai_payload.update(kwargs)
|
|
147
|
+
|
|
134
148
|
try:
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
json=
|
|
138
|
-
headers={
|
|
149
|
+
openai_resp = self._session.post(
|
|
150
|
+
"https://api.openai.com/v1/chat/completions",
|
|
151
|
+
json=openai_payload,
|
|
152
|
+
headers={
|
|
153
|
+
"Authorization": f"Bearer {self._openai_key}",
|
|
154
|
+
"Content-Type": "application/json",
|
|
155
|
+
"User-Agent": "swiftapi-python/1.1.1",
|
|
156
|
+
},
|
|
139
157
|
timeout=self._timeout,
|
|
140
158
|
)
|
|
141
159
|
except requests.exceptions.RequestException as e:
|
|
142
|
-
raise NetworkError(f"
|
|
160
|
+
raise NetworkError(f"OpenAI request failed: {e}")
|
|
143
161
|
|
|
144
|
-
if
|
|
145
|
-
raise AuthenticationError("Invalid
|
|
146
|
-
if
|
|
147
|
-
raise SwiftAPIError(f"
|
|
162
|
+
if openai_resp.status_code == 401:
|
|
163
|
+
raise AuthenticationError("Invalid OpenAI API key")
|
|
164
|
+
if openai_resp.status_code != 200:
|
|
165
|
+
raise SwiftAPIError(f"OpenAI error: {openai_resp.text[:200]}")
|
|
148
166
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
content = ""
|
|
167
|
+
data = openai_resp.json()
|
|
168
|
+
content = data.get("choices", [{}])[0].get("message", {}).get("content", "")
|
|
152
169
|
|
|
153
170
|
return ChatCompletion(
|
|
154
171
|
content=content,
|
|
@@ -161,8 +178,8 @@ class Completions:
|
|
|
161
178
|
class _ChatNamespace:
|
|
162
179
|
"""Namespace for client.chat.completions"""
|
|
163
180
|
|
|
164
|
-
def __init__(self,
|
|
165
|
-
self.completions = Completions(
|
|
181
|
+
def __init__(self, swiftapi_key: str, openai_key: str, authority_url: str, timeout: int):
|
|
182
|
+
self.completions = Completions(swiftapi_key, openai_key, authority_url, timeout)
|
|
166
183
|
|
|
167
184
|
|
|
168
185
|
class OpenAI:
|
|
@@ -170,14 +187,17 @@ class OpenAI:
|
|
|
170
187
|
Drop-in replacement for openai.OpenAI.
|
|
171
188
|
|
|
172
189
|
Every completion is cryptographically attested via SwiftAPI.
|
|
173
|
-
|
|
190
|
+
SwiftAPI governs. OpenAI executes. You bring both keys.
|
|
174
191
|
|
|
175
192
|
Usage:
|
|
176
193
|
from swiftapi import OpenAI
|
|
177
194
|
|
|
178
|
-
client = OpenAI(
|
|
195
|
+
client = OpenAI(
|
|
196
|
+
swiftapi_key="swiftapi_live_...",
|
|
197
|
+
openai_key="sk-..."
|
|
198
|
+
)
|
|
179
199
|
r = client.chat.completions.create(
|
|
180
|
-
model="gpt-4o
|
|
200
|
+
model="gpt-4o",
|
|
181
201
|
messages=[{"role": "user", "content": "Hello"}]
|
|
182
202
|
)
|
|
183
203
|
print(r.choices[0].message.content)
|
|
@@ -186,15 +206,19 @@ class OpenAI:
|
|
|
186
206
|
def __init__(
|
|
187
207
|
self,
|
|
188
208
|
swiftapi_key: str = None,
|
|
209
|
+
openai_key: str = None,
|
|
189
210
|
api_key: str = None,
|
|
190
|
-
|
|
211
|
+
authority_url: str = "https://swiftapi.ai",
|
|
191
212
|
timeout: int = 60,
|
|
192
213
|
**kwargs,
|
|
193
214
|
):
|
|
194
|
-
|
|
195
|
-
if not key:
|
|
215
|
+
if not swiftapi_key:
|
|
196
216
|
raise AuthenticationError("swiftapi_key is required")
|
|
197
|
-
if not
|
|
217
|
+
if not swiftapi_key.startswith("swiftapi_live_"):
|
|
198
218
|
raise AuthenticationError("Invalid key format: must start with 'swiftapi_live_'")
|
|
199
219
|
|
|
200
|
-
|
|
220
|
+
oai_key = openai_key or api_key
|
|
221
|
+
if not oai_key:
|
|
222
|
+
raise AuthenticationError("openai_key is required (your OpenAI API key)")
|
|
223
|
+
|
|
224
|
+
self.chat = _ChatNamespace(swiftapi_key, oai_key, authority_url, timeout)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{swiftapi_python-1.1.1 → swiftapi_python-1.1.2}/swiftapi_python.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|