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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: swiftapi-python
3
- Version: 1.1.1
3
+ Version: 1.1.2
4
4
  Summary: SwiftAPI Python SDK - AI Action Verification Gateway
5
5
  Author-email: Rayan Pal <rayan@swiftapi.ai>
6
6
  License-Expression: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "swiftapi-python"
7
- version = "1.1.1"
7
+ version = "1.1.2"
8
8
  description = "SwiftAPI Python SDK - AI Action Verification Gateway"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -29,7 +29,7 @@ Usage:
29
29
  db.update(user_id, data)
30
30
  """
31
31
 
32
- __version__ = "1.1.1"
32
+ __version__ = "1.1.2"
33
33
  __author__ = "Rayan Pal"
34
34
 
35
35
  # Core exports
@@ -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, Union, Optional, Any
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, key: str, base_url: str, timeout: int):
69
- self._key = key
70
- self._base_url = base_url.rstrip("/")
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
- Attestation is handled transparently. If any gate fails, content is empty string.
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-mini")
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": max_tokens or 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._base_url}/attest",
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: Forward to /chat/vibe with attestation
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
- vibe_resp = self._session.post(
136
- f"{self._base_url}/chat/vibe",
137
- json=payload,
138
- headers={"X-SwiftAPI-Attestation": json.dumps(attestation)},
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"Chat request failed: {e}")
160
+ raise NetworkError(f"OpenAI request failed: {e}")
143
161
 
144
- if vibe_resp.status_code == 403:
145
- raise AuthenticationError("Invalid SwiftAPI authority key")
146
- if vibe_resp.status_code != 200:
147
- raise SwiftAPIError(f"Chat failed: {vibe_resp.text[:200]}")
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
- content = vibe_resp.json()
150
- if content is None:
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, key: str, base_url: str, timeout: int):
165
- self.completions = Completions(key, base_url, timeout)
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
- No attestation, no output.
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(swiftapi_key="swiftapi_live_...")
195
+ client = OpenAI(
196
+ swiftapi_key="swiftapi_live_...",
197
+ openai_key="sk-..."
198
+ )
179
199
  r = client.chat.completions.create(
180
- model="gpt-4o-mini",
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
- base_url: str = "https://swiftapi.ai",
211
+ authority_url: str = "https://swiftapi.ai",
191
212
  timeout: int = 60,
192
213
  **kwargs,
193
214
  ):
194
- key = swiftapi_key or api_key
195
- if not key:
215
+ if not swiftapi_key:
196
216
  raise AuthenticationError("swiftapi_key is required")
197
- if not key.startswith("swiftapi_live_"):
217
+ if not swiftapi_key.startswith("swiftapi_live_"):
198
218
  raise AuthenticationError("Invalid key format: must start with 'swiftapi_live_'")
199
219
 
200
- self.chat = _ChatNamespace(key, base_url, timeout)
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)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: swiftapi-python
3
- Version: 1.1.1
3
+ Version: 1.1.2
4
4
  Summary: SwiftAPI Python SDK - AI Action Verification Gateway
5
5
  Author-email: Rayan Pal <rayan@swiftapi.ai>
6
6
  License-Expression: MIT