sec-gemini 0.0.1__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,18 @@
1
+ Metadata-Version: 2.4
2
+ Name: sec-gemini
3
+ Version: 0.0.1
4
+ Summary: Sec-Gemini Python SDK
5
+ Requires-Python: >=3.10
6
+ Description-Content-Type: text/markdown
7
+ Requires-Dist: asyncio>=3.4.3
8
+ Requires-Dist: httpx>=0.28.1
9
+ Requires-Dist: openai>=1.59.7
10
+ Requires-Dist: orjson>=3.10.12
11
+ Requires-Dist: pydantic>=2.10.4
12
+ Requires-Dist: python-dotenv>=1.0.1
13
+ Requires-Dist: rich>=13.9.4
14
+ Requires-Dist: websockets>=14.1
15
+ Requires-Dist: dotenv
16
+
17
+ # Sec-Gemini Python SDK
18
+
@@ -0,0 +1,2 @@
1
+ # Sec-Gemini Python SDK
2
+
@@ -0,0 +1,27 @@
1
+ [project]
2
+ name = "sec-gemini"
3
+ version = "0.0.1"
4
+ description = "Sec-Gemini Python SDK"
5
+ readme = "README.md"
6
+ requires-python = ">=3.10"
7
+ dependencies = [
8
+ "asyncio>=3.4.3",
9
+ "httpx>=0.28.1",
10
+ "openai>=1.59.7",
11
+ "orjson>=3.10.12",
12
+ "pydantic>=2.10.4",
13
+ "python-dotenv>=1.0.1",
14
+ "rich>=13.9.4",
15
+ "websockets>=14.1",
16
+ "dotenv" # what version?
17
+ ]
18
+
19
+ [tool.uv]
20
+ dev-dependencies = [
21
+ "ipykernel>=6.29.5",
22
+ "jupyter>=1.1.1",
23
+ "pytest>=8.3.4",
24
+ ]
25
+
26
+ [tool.setuptools.packages.find]
27
+ include = ["sec_gemini*"]
@@ -0,0 +1,34 @@
1
+ # Copyright 2025 Google LLC
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ from .secgemini import SecGemini
16
+ from .models.session_request import SessionRequest
17
+ from .models.session_response import SessionResponse
18
+ from .models.message import Message
19
+ from .models.enums import State
20
+ from .file import File
21
+ from .session import InteractiveSession
22
+ from .models.enums import MimeType, MessageType
23
+
24
+ __all__ = [
25
+ "SecGemini",
26
+ "SessionRequest",
27
+ "SessionResponse",
28
+ "Message",
29
+ "File",
30
+ "InteractiveSession",
31
+ "MimeType",
32
+ "MessageType",
33
+ "State",
34
+ ]
@@ -0,0 +1,15 @@
1
+ # Copyright 2025 Google LLC
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ DEFAULT_TTL = 86400 * 3 # 3 days
@@ -0,0 +1,46 @@
1
+ # Copyright 2025 Google LLC
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ from enum import Enum
16
+
17
+ class SDKInfo(Enum):
18
+ """SDK Info"""
19
+ NAME = "secgemini-python"
20
+ VERSION = "0.2.0" # reported in the header of the API
21
+
22
+ class _URLS(Enum):
23
+ """API URLs"""
24
+ HTTPS = "https://api.secgemini.google"
25
+ WEBSOCKET = "wss://api.secgemini.google"
26
+
27
+ class _EndPoints(Enum):
28
+ """API Endpoints"""
29
+ # users
30
+ USER_INFO = "/v1/user/info"
31
+
32
+ # messages
33
+ GENERATE = "/v1/session/generate"
34
+ STREAM = "/v1/stream"
35
+
36
+ # sessions
37
+ REGISTER_SESSION = "/v1/session/register"
38
+ DELETE_SESSION = "/v1/session/delete"
39
+ LIST_SESSION = "/v1/session/list"
40
+ GET_SESSION = "/v1/session/get"
41
+ UPDATE_SESSION = "/v1/session/update"
42
+ SEND_FEEDBACK = "/v1/session/feedback"
43
+
44
+ # files
45
+ ATTACH_FILE = "/v1/session/attach_file"
46
+ DELETE_FILE = "/v1/session/delete_file"
@@ -0,0 +1,39 @@
1
+ # Copyright 2025 Google LLC
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ from pydantic import BaseModel, Field
16
+ from .models.enums import MimeType
17
+
18
+ class File(BaseModel):
19
+ """
20
+ Represents a file that can be uploaded to the API.
21
+ """
22
+
23
+ filename: str = Field(
24
+ ...,
25
+ title="Filename",
26
+ description="The name of the file."
27
+ )
28
+
29
+ mime_type: MimeType = Field(
30
+ ...,
31
+ title="Mime Type",
32
+ description="The mime type of the file."
33
+ )
34
+
35
+ file: bytes = Field(
36
+ ...,
37
+ title="File",
38
+ description="The file content."
39
+ )
@@ -0,0 +1,121 @@
1
+ # Copyright 2025 Google LLC
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ import sys
16
+ from time import time
17
+ from pydantic import BaseModel, Field
18
+ import httpx
19
+ import logging
20
+ import websockets
21
+ from .enums import SDKInfo
22
+ from typing import TypeVar
23
+ # Define a TypeVar for subclasses of HTTPResponse
24
+ T = TypeVar('T', bound='BaseModel')
25
+
26
+
27
+ class NetResponse(BaseModel):
28
+ url: str = Field(title="Request URL")
29
+ ok: bool
30
+ error_message: str = Field("", title="Error Message")
31
+ data: dict = Field({}, title="Response Data")
32
+ latency: float = Field(0.0, title="Latency",
33
+ description="The time taken to complete the request in seconds.")
34
+
35
+ class NetworkClient():
36
+ def __init__(self,
37
+ base_url: str,
38
+ api_key: str):
39
+ self.base_url = base_url
40
+ self.api_key = api_key
41
+ self.client = httpx.Client(timeout=90)
42
+
43
+
44
+ def post(self, endpoint: str, model: T, headers: dict = {}) -> NetResponse:
45
+ """Post Request to the API
46
+
47
+ Args:
48
+ endpoint: The API endpoint to post to.
49
+ model: The pydantic model to be posted.
50
+ headers: The headers specific to the requests to be sent along.
51
+
52
+ Returns:
53
+ HTTPResponse: The response from the API.
54
+ """
55
+ data = model.model_dump()
56
+ url = self._make_url(endpoint)
57
+ headers = self._make_headers(headers)
58
+
59
+ start_time = time()
60
+ response = self.client.post(url, headers=headers, json=data)
61
+ latency = time() - start_time
62
+
63
+ if response.status_code != 200:
64
+ return NetResponse(url=url,
65
+ ok=False,
66
+ error_message=self._make_error_message(url, response),
67
+ latency=latency)
68
+
69
+ logging.debug(f"[HTTP][POST] {url} -> latency: {latency}")
70
+ return NetResponse(url=url, ok=True, data=response.json(),
71
+ latency=latency)
72
+
73
+ def get(self, endpoint: str, query_params: dict = {}, headers: dict = {}) -> NetResponse:
74
+ """Get Request to the API
75
+
76
+ Args:
77
+ endpoint: The API endpoint to get from.
78
+ query_params: The query parameters to be sent along.
79
+ headers: The headers specific to the requests to be sent along.
80
+
81
+ Returns:
82
+ HTTPResponse: The response from the API.
83
+ """
84
+
85
+ # FIXME: Support for query parameters
86
+
87
+ url = self._make_url(endpoint)
88
+ headers = self._make_headers(headers)
89
+ start_time = time()
90
+ response = self.client.get(url, params=query_params, headers=headers)
91
+ latency = time() - start_time
92
+ if response.status_code != 200:
93
+ return NetResponse(url=url,
94
+ ok=False,
95
+ error_message=self._make_error_message(url, response),
96
+ latency=latency)
97
+ logging.debug(f"[HTTP][GET] {url} -> latency: {latency}")
98
+ return NetResponse(url=url, ok=True, data=response.json(),
99
+ latency=latency)
100
+
101
+ def _make_url(self, endpoint: str) -> str:
102
+ return f"{self.base_url}/{endpoint.lstrip('/')}"
103
+
104
+ def _make_headers(self, headers: dict) -> dict:
105
+ # User-Agent: Mozilla/5.0 (<system-information>) <platform> (<platform-details>) <extensions>
106
+
107
+ # request specific headers
108
+ headers = headers or {}
109
+
110
+ additional_headers = {
111
+ "User-Agent": f"{SDKInfo.NAME.value}/{SDKInfo.VERSION.value} ({sys.platform}) {sys.version} ({sys.version_info})",
112
+ "x-sdk-version": SDKInfo.VERSION.value,
113
+ "x-sdk": "python",
114
+ "x-api-key": self.api_key,
115
+ "Content-Type": "application/json"
116
+ }
117
+ headers.update(additional_headers)
118
+ return headers
119
+
120
+ def _make_error_message(self, url: str, response: httpx.Response) -> str:
121
+ return f"[HTTP] {url} -> {response.status_code}:{response.text}"
File without changes
@@ -0,0 +1,37 @@
1
+
2
+ # Copyright 2025 Google LLC
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+
17
+ from pydantic import BaseModel, Field
18
+ from .enums import MimeType
19
+
20
+ class Attachment(BaseModel):
21
+ """Represents a file upload to the session."""
22
+
23
+ session_id: str = Field(...,
24
+ title="Session ID",
25
+ description="The session ID this file should be attached to.")
26
+
27
+ filename: str = Field(...,
28
+ title="Filename",
29
+ description="The name of the file.")
30
+
31
+ mime_type: MimeType = Field(...,
32
+ title="Mime Type",
33
+ description="The mime type of the file.")
34
+
35
+ content: str = Field(...,
36
+ title="File Content",
37
+ description="The content of the file as string. Always base64 encoded.")
@@ -0,0 +1,222 @@
1
+
2
+ # Copyright 2025 Google LLC
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+
17
+ from enum import Enum
18
+
19
+ class FeedbackType(str, Enum):
20
+ """Type of feedback that can be sent to the system."""
21
+
22
+ USER_FEEDBACK = "user_feedback"
23
+ BUG_REPORT = "bug_report"
24
+
25
+ class VectorDistance(str, Enum):
26
+ COSINE = "COSINE"
27
+ DOT_PRODUCT = "DOT_PRODUCT"
28
+ EUCLIDEAN = "EUCLIDEAN"
29
+
30
+ class UserType(str, Enum):
31
+ "User type"
32
+ UI = "ui" # user interface
33
+ USER = "user" # system user
34
+ ADMIN = "admin" # admin user
35
+ SYSTEM = "system" # orchestrator system user
36
+ SERVICE = "service" # microservice
37
+
38
+ class ResponseStatus(int, Enum):
39
+ # 2xx Success
40
+ OK = 200
41
+ CREATED = 201
42
+ ACCEPTED = 202
43
+ NO_CONTENT = 204
44
+ PARTIAL_CONTENT = 206
45
+
46
+ # 3xx Redirection
47
+ MULTIPLE_CHOICES = 300
48
+ MOVED_PERMANENTLY = 301
49
+ FOUND = 302
50
+ SEE_OTHER = 303
51
+ NOT_MODIFIED = 304
52
+ TEMPORARY_REDIRECT = 307
53
+ PERMANENT_REDIRECT = 308
54
+
55
+ # 4xx Client Errors
56
+ BAD_REQUEST = 400
57
+ UNAUTHORIZED = 401
58
+ AUTHENTICATION_ERROR = 401 # Alias for UNAUTHORIZED
59
+ PAYMENT_REQUIRED = 402
60
+ FORBIDDEN = 403
61
+ NOT_FOUND = 404
62
+ METHOD_NOT_ALLOWED = 405
63
+ NOT_ACCEPTABLE = 406
64
+ PROXY_AUTHENTICATION_REQUIRED = 407
65
+ REQUEST_TIMEOUT = 408
66
+ CONFLICT = 409
67
+ ALREADY_EXISTS = 409 # Alias for CONFLICT
68
+ GONE = 410
69
+ LENGTH_REQUIRED = 411
70
+ PRECONDITION_FAILED = 412
71
+ PAYLOAD_TOO_LARGE = 413
72
+ URI_TOO_LONG = 414
73
+ UNSUPPORTED_MEDIA_TYPE = 415
74
+ RANGE_NOT_SATISFIABLE = 416
75
+ EXPECTATION_FAILED = 417
76
+ I_AM_A_TEAPOT = 418
77
+ UNPROCESSABLE_ENTITY = 422
78
+ TOO_EARLY = 425
79
+ UPGRADE_REQUIRED = 426
80
+ PRECONDITION_REQUIRED = 428
81
+ TOO_MANY_REQUESTS = 429
82
+ QUOTA_EXCEEDED = 429 # Alias for TOO_MANY_REQUESTS
83
+ REQUEST_HEADER_FIELDS_TOO_LARGE = 431
84
+ UNAVAILABLE_FOR_LEGAL_REASONS = 451
85
+
86
+ # 5xx Server Errors
87
+ INTERNAL_SERVER_ERROR = 500
88
+ SERVER_ERROR = 500 # Alias for INTERNAL_SERVER_ERROR
89
+ INTERNAL_ERROR = 500 # Another alias for INTERNAL_SERVER_ERROR
90
+ NOT_IMPLEMENTED = 501
91
+ BAD_GATEWAY = 502
92
+ SERVICE_UNAVAILABLE = 503
93
+ GATEWAY_TIMEOUT = 504
94
+ HTTP_VERSION_NOT_SUPPORTED = 505
95
+ VARIANT_ALSO_NEGOTIATES = 506
96
+ INSUFFICIENT_STORAGE = 507
97
+ LOOP_DETECTED = 508
98
+ NOT_EXTENDED = 510
99
+ NETWORK_AUTHENTICATION_REQUIRED = 511
100
+
101
+ class Role(str, Enum):
102
+ "Describe the role associated with the completion"
103
+ USER = "user"
104
+ AGENT = "agent"
105
+ SYSTEM = "system" # those are not returned to the user
106
+
107
+ class MimeType(str, Enum):
108
+ "Completion type"
109
+ TEXT = "text/plain"
110
+ MARKDOWN = "text/markdown"
111
+ SERIALIZED_JSON = "text/serialized-json"
112
+ BINARY = "application/octet-stream"
113
+
114
+ # IMAGES
115
+ JPEG = "image/jpeg"
116
+ PNG = "image/png"
117
+ TIFF = "image/tiff"
118
+ GIF = "image/gif"
119
+ SVG = "image/svg+xml"
120
+ WEBP = "image/webp"
121
+ AVIF = "image/avif"
122
+
123
+ # AUDIO
124
+ WAV = "audio/wav"
125
+ MP3 = "audio/mpeg"
126
+ OGG = "audio/ogg"
127
+
128
+ # VIDEO
129
+ WEBM = "video/webm"
130
+ MP4 = "video/mp4"
131
+
132
+
133
+ # CODE
134
+ C = "text/c"
135
+ CPP = "text/c++"
136
+ JAVA = "text/java"
137
+ RUST = "text/rust"
138
+ GOLANG = "text/go"
139
+ PYTHON = "text/python"
140
+ PHP = "text/php"
141
+ PERL = "text/perl"
142
+ RUBY = "text/ruby"
143
+ SWIFT = "text/swift"
144
+ KOTLIN = "text/kotlin"
145
+ SCALA = "text/scala"
146
+ JAVASCRIPT = "text/javascript"
147
+ TYPESCRIPT = "text/typescript"
148
+ HTML = "text/html"
149
+ CSS = "text/css"
150
+
151
+ # DATA
152
+ CSV = "text/csv"
153
+ XML = "text/xml"
154
+ YAML = "text/yaml"
155
+ TOML = "text/toml"
156
+ SQL = "text/sql"
157
+ JSON = "application/json"
158
+ JSONL = "application/jsonl"
159
+
160
+
161
+ # COMPRESSED
162
+ # NOTE: Gemini does not support compressed files
163
+ # ZIP = "application/zip"
164
+ # TAR = "application/tar"
165
+ # GZIP = "application/gzip"
166
+ # BZIP2 = "application/bzip2"
167
+ # XZ = "application/xz"
168
+ # SEVENZIP = "application/x-7z-compressed"
169
+
170
+ # DOCUMENTS
171
+ PDF = "application/pdf"
172
+ DOCX = "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
173
+ XLSX = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
174
+ PPTX = "application/vnd.openxmlformats-officedocument.presentationml.presentation"
175
+ DOC = "application/msword"
176
+ XLS = "application/vnd.ms-excel"
177
+ PPT = "application/vnd.ms-powerpoint"
178
+ RTF = "application/rtf"
179
+ ODT = "application/vnd.oasis.opendocument.text"
180
+
181
+
182
+ class State(str, Enum):
183
+ START = "start" # session just started
184
+
185
+ QUERY = "query" # user query
186
+
187
+ RUNNING_AGENT = "running_agent" # executing agent
188
+ AGENT_DONE = "agent_done" # agent done
189
+
190
+ CODING = "coding" # executing code
191
+ CODE_RESULT = "code_result" # code result
192
+
193
+ CALLING_TOOL = "calling_tool" # executing function
194
+ TOOL_RESULT = "tool_result" # function result
195
+
196
+ # semantic sugar states
197
+ GENERATING = "generating" # generating response
198
+ ANSWERING = "answering" # generating answer
199
+ THINKING = "thinking" # thinking
200
+ PLANNING = "planning" # planning execution
201
+ REVIEWING = "reviewing" # reviewing current result
202
+ UNDERSTANDING = "understanding" # intent detection
203
+ RETRIVING = "retriving" # retrieving info
204
+ GROUNDING = "grounding" # grounding
205
+
206
+
207
+ class MessageType(str, Enum):
208
+ "Type of message"
209
+
210
+ # info messages
211
+ RESULT = "result" # result message
212
+ DEBUG = "debug" # debug message
213
+ INFO = "info" # transient info message only used in streaming
214
+ ERROR = "error" # error message
215
+ THINKING = "thinking" # thinking message that persist in the thinking panel
216
+
217
+ # mutation messages
218
+ UPDATE = "update" # update message that modify the output. e.g grounding or new fact
219
+ DELETE = "delete" # Ask to delete a previous message by id
220
+
221
+ # User messages
222
+ QUERY = "query"
@@ -0,0 +1,37 @@
1
+
2
+ # Copyright 2025 Google LLC
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+
17
+ from pydantic import BaseModel, Field
18
+ from .enums import FeedbackType
19
+
20
+
21
+ class Feedback(BaseModel):
22
+ """Represents a feedback to the session."""
23
+
24
+ session_id: str = Field(..., title="Session ID",
25
+ description="The session ID this feedback should be attached to.")
26
+
27
+ group_id: str = Field('', title="Group ID",
28
+ description="The message group ID this feedback should be attached to.")
29
+
30
+ type: FeedbackType = Field(..., title="Feedback Type",
31
+ description="The type of feedback.")
32
+
33
+ score: int = Field(..., title="Score",
34
+ description="The score of the feedback.")
35
+
36
+ comment: str = Field(..., title="Comment",
37
+ description="The comment of the feedback.")