earthinia 1.0.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.
- earthinia-1.0.0/LICENSE +21 -0
- earthinia-1.0.0/MANIFEST.in +4 -0
- earthinia-1.0.0/PKG-INFO +167 -0
- earthinia-1.0.0/README.md +124 -0
- earthinia-1.0.0/earthinia/__init__.py +6 -0
- earthinia-1.0.0/earthinia/_version.py +3 -0
- earthinia-1.0.0/earthinia/auth.py +14 -0
- earthinia-1.0.0/earthinia/client.py +29 -0
- earthinia-1.0.0/earthinia/config.py +23 -0
- earthinia-1.0.0/earthinia/console.py +47 -0
- earthinia-1.0.0/earthinia/exceptions.py +170 -0
- earthinia-1.0.0/earthinia/generated.py +66 -0
- earthinia-1.0.0/earthinia/models.py +205 -0
- earthinia-1.0.0/earthinia/pagination.py +14 -0
- earthinia-1.0.0/earthinia/py.typed +0 -0
- earthinia-1.0.0/earthinia/resources/__init__.py +4 -0
- earthinia-1.0.0/earthinia/resources/api_keys.py +36 -0
- earthinia-1.0.0/earthinia/resources/chat.py +29 -0
- earthinia-1.0.0/earthinia/resources/clusters.py +13 -0
- earthinia-1.0.0/earthinia/resources/files.py +20 -0
- earthinia-1.0.0/earthinia/resources/knowledge.py +22 -0
- earthinia-1.0.0/earthinia/resources/memory.py +14 -0
- earthinia-1.0.0/earthinia/resources/sessions.py +29 -0
- earthinia-1.0.0/earthinia/resources/tools.py +22 -0
- earthinia-1.0.0/earthinia/resources/workers.py +14 -0
- earthinia-1.0.0/earthinia/transport.py +55 -0
- earthinia-1.0.0/earthinia/types/__init__.py +0 -0
- earthinia-1.0.0/earthinia/types/chat.py +0 -0
- earthinia-1.0.0/earthinia/types/instance.py +0 -0
- earthinia-1.0.0/earthinia/types/session.py +0 -0
- earthinia-1.0.0/earthinia.egg-info/PKG-INFO +167 -0
- earthinia-1.0.0/earthinia.egg-info/SOURCES.txt +36 -0
- earthinia-1.0.0/earthinia.egg-info/dependency_links.txt +1 -0
- earthinia-1.0.0/earthinia.egg-info/entry_points.txt +2 -0
- earthinia-1.0.0/earthinia.egg-info/requires.txt +15 -0
- earthinia-1.0.0/earthinia.egg-info/top_level.txt +1 -0
- earthinia-1.0.0/pyproject.toml +106 -0
- earthinia-1.0.0/setup.cfg +4 -0
earthinia-1.0.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Earthinia
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
earthinia-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: earthinia
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Official Python SDK for the Earthinia AI Workforce Platform.
|
|
5
|
+
Author-email: Earthinia <support@eacse.com>
|
|
6
|
+
Maintainer-email: Earthinia <support@eacse.com>
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
Project-URL: Homepage, https://earthinia.com
|
|
9
|
+
Project-URL: Documentation, https://docs.earthinia.com
|
|
10
|
+
Project-URL: Source, https://github.com/kilan-go/earthinia-platform/tree/main/packages/sdk-python
|
|
11
|
+
Project-URL: Issues, https://github.com/kilan-go/earthinia-platform/issues
|
|
12
|
+
Keywords: earthinia,ai,agents,assistant,automation,llm,workforce,enterprise,sdk
|
|
13
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Intended Audience :: Information Technology
|
|
16
|
+
Classifier: Operating System :: OS Independent
|
|
17
|
+
Classifier: Programming Language :: Python
|
|
18
|
+
Classifier: Programming Language :: Python :: 3
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
23
|
+
Classifier: Topic :: Software Development
|
|
24
|
+
Classifier: Topic :: Internet
|
|
25
|
+
Classifier: Typing :: Typed
|
|
26
|
+
Requires-Python: >=3.10
|
|
27
|
+
Description-Content-Type: text/markdown
|
|
28
|
+
License-File: LICENSE
|
|
29
|
+
Requires-Dist: requests>=2.32.0
|
|
30
|
+
Requires-Dist: pydantic<3,>=2.11.0
|
|
31
|
+
Provides-Extra: dev
|
|
32
|
+
Requires-Dist: pytest>=8.4.0; extra == "dev"
|
|
33
|
+
Requires-Dist: pytest-cov>=6.2.0; extra == "dev"
|
|
34
|
+
Requires-Dist: pytest-asyncio>=1.1.0; extra == "dev"
|
|
35
|
+
Requires-Dist: ruff>=0.12.0; extra == "dev"
|
|
36
|
+
Requires-Dist: mypy>=1.17.0; extra == "dev"
|
|
37
|
+
Requires-Dist: build>=1.3.0; extra == "dev"
|
|
38
|
+
Requires-Dist: twine>=6.1.0; extra == "dev"
|
|
39
|
+
Provides-Extra: docs
|
|
40
|
+
Requires-Dist: mkdocs>=1.6.0; extra == "docs"
|
|
41
|
+
Requires-Dist: mkdocs-material>=9.6.0; extra == "docs"
|
|
42
|
+
Dynamic: license-file
|
|
43
|
+
|
|
44
|
+
# Earthinia Python SDK
|
|
45
|
+
|
|
46
|
+
The official synchronous Python client for the Earthinia public REST API. Requires Python 3.10+.
|
|
47
|
+
This directory is the source of the `earthinia` distribution; registry installation requires a published release.
|
|
48
|
+
|
|
49
|
+
## Install
|
|
50
|
+
|
|
51
|
+
After release:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
pip install earthinia
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Execute a prompt
|
|
58
|
+
|
|
59
|
+
Create a public API key for an existing cluster in the Earthinia Console. The key must have
|
|
60
|
+
`cluster:<cluster_id>:chat` scope. Replace the cluster ID below with that cluster's ID.
|
|
61
|
+
|
|
62
|
+
```python
|
|
63
|
+
from earthinia import Earthinia
|
|
64
|
+
|
|
65
|
+
with Earthinia(api_key="earth_live_...") as client:
|
|
66
|
+
response = client.chat.create(
|
|
67
|
+
cluster_id="your-cluster-id",
|
|
68
|
+
message="Prepare today's sales report.",
|
|
69
|
+
)
|
|
70
|
+
print(response.text)
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
The key above is a placeholder, not a usable credential. Keep real keys on your server.
|
|
74
|
+
You can also use environment-variable authentication:
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
export EARTHINIA_API_KEY="earth_live_..."
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
```python
|
|
81
|
+
from earthinia import Earthinia
|
|
82
|
+
|
|
83
|
+
with Earthinia() as client:
|
|
84
|
+
response = client.clusters.execute(
|
|
85
|
+
"your-cluster-id", "Prepare today's sales report.", session_id="sales-report"
|
|
86
|
+
)
|
|
87
|
+
print(response.text)
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
An explicit `api_key` takes precedence over `EARTHINIA_API_KEY`. The client does not load `.env` files.
|
|
91
|
+
Reuse a client for connection pooling; use it as a context manager or call `client.close()`.
|
|
92
|
+
|
|
93
|
+
## Contract and behavior
|
|
94
|
+
|
|
95
|
+
Both `chat.create` and `clusters.execute` call
|
|
96
|
+
`POST https://api.eacse.com/api/v1/clusters/{cluster_id}/chat` using `X-Earthinia-Key`.
|
|
97
|
+
The server derives account identity and permissions from the key. User identity cannot be overridden.
|
|
98
|
+
`chat.create` also accepts `session_id`, `metadata`, `attachments`, and `output_format`.
|
|
99
|
+
Attachment objects follow the public API contract; the client does not read or upload local files implicitly.
|
|
100
|
+
Responses are generated Pydantic models with `text`, `success`, `status`, `session_id`, `usage`, and other API fields.
|
|
101
|
+
The `earthinia.models.ChatResponse` alias refers to the generated response model.
|
|
102
|
+
|
|
103
|
+
The production origin defaults to `https://api.eacse.com`. Set `base_url` to an HTTPS origin
|
|
104
|
+
without `/api`; the client adds the full API path. Loopback HTTP is allowed for local development:
|
|
105
|
+
|
|
106
|
+
```python
|
|
107
|
+
client = Earthinia(base_url="http://localhost:8001", timeout=60)
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
`timeout` is a positive number of seconds (default 30), applied to connection and read operations.
|
|
111
|
+
It is not an end-to-end execution deadline. TLS verification stays enabled. Redirects are not followed.
|
|
112
|
+
Environment proxy and netrc settings are not used. Prompt submissions are never retried automatically:
|
|
113
|
+
a timeout may occur after execution has begun, so check the operation before submitting it again.
|
|
114
|
+
|
|
115
|
+
```python
|
|
116
|
+
from earthinia.exceptions import AuthenticationError, EarthiniaError, RateLimitError
|
|
117
|
+
|
|
118
|
+
try:
|
|
119
|
+
with Earthinia() as client:
|
|
120
|
+
response = client.chat.create("your-cluster-id", "Prepare today's sales report.")
|
|
121
|
+
except AuthenticationError:
|
|
122
|
+
print("Configure a valid API key.")
|
|
123
|
+
except RateLimitError as error:
|
|
124
|
+
print("Rate limited; retry-after seconds:", error.retry_after)
|
|
125
|
+
except EarthiniaError as error:
|
|
126
|
+
print(error.status_code, str(error))
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
HTTP failures raise SDK exceptions; malformed successful responses raise `SerializationError`.
|
|
130
|
+
Exception messages omit remote bodies and headers to avoid exposing credentials or user data.
|
|
131
|
+
The SDK does not log requests or keys.
|
|
132
|
+
|
|
133
|
+
## Supported surface
|
|
134
|
+
|
|
135
|
+
This release supports public-key chat and cluster prompt execution. Cluster administration,
|
|
136
|
+
files, sessions, streaming, and other account-management APIs are not exposed by this client.
|
|
137
|
+
Earlier README examples advertised unimplemented operations and a nonexistent async client;
|
|
138
|
+
there is no `AsyncEarthinia` or `run()` method. Use the actual methods above.
|
|
139
|
+
The former administrative cluster methods targeted nonexistent public-key endpoints and have
|
|
140
|
+
been removed from the client surface. `user_id` overrides are rejected. Chat responses are now
|
|
141
|
+
Pydantic objects; use `.model_dump()` or `.model_dump_json()` when you need serialized data.
|
|
142
|
+
|
|
143
|
+
The optional CLI uses the same key and endpoint:
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
earthinia your-cluster-id "Prepare today's sales report."
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
## Development and release
|
|
150
|
+
|
|
151
|
+
From this SDK directory:
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
python -m pip install '.[dev]'
|
|
155
|
+
python -m pytest
|
|
156
|
+
python -m build
|
|
157
|
+
python -m twine check dist/*
|
|
158
|
+
python ../../scripts/check-sdk-artifacts.py dist/*
|
|
159
|
+
python ../../scripts/test-python-sdk-install.py dist/*.whl
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
See [the monorepo release guide](https://github.com/kilan-go/earthinia-platform/blob/main/docs/sdk-releases.md)
|
|
163
|
+
for contract regeneration, independent versioning, and PyPI Trusted Publishing setup.
|
|
164
|
+
|
|
165
|
+
## License
|
|
166
|
+
|
|
167
|
+
MIT. See LICENSE.
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
# Earthinia Python SDK
|
|
2
|
+
|
|
3
|
+
The official synchronous Python client for the Earthinia public REST API. Requires Python 3.10+.
|
|
4
|
+
This directory is the source of the `earthinia` distribution; registry installation requires a published release.
|
|
5
|
+
|
|
6
|
+
## Install
|
|
7
|
+
|
|
8
|
+
After release:
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
pip install earthinia
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Execute a prompt
|
|
15
|
+
|
|
16
|
+
Create a public API key for an existing cluster in the Earthinia Console. The key must have
|
|
17
|
+
`cluster:<cluster_id>:chat` scope. Replace the cluster ID below with that cluster's ID.
|
|
18
|
+
|
|
19
|
+
```python
|
|
20
|
+
from earthinia import Earthinia
|
|
21
|
+
|
|
22
|
+
with Earthinia(api_key="earth_live_...") as client:
|
|
23
|
+
response = client.chat.create(
|
|
24
|
+
cluster_id="your-cluster-id",
|
|
25
|
+
message="Prepare today's sales report.",
|
|
26
|
+
)
|
|
27
|
+
print(response.text)
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
The key above is a placeholder, not a usable credential. Keep real keys on your server.
|
|
31
|
+
You can also use environment-variable authentication:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
export EARTHINIA_API_KEY="earth_live_..."
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
```python
|
|
38
|
+
from earthinia import Earthinia
|
|
39
|
+
|
|
40
|
+
with Earthinia() as client:
|
|
41
|
+
response = client.clusters.execute(
|
|
42
|
+
"your-cluster-id", "Prepare today's sales report.", session_id="sales-report"
|
|
43
|
+
)
|
|
44
|
+
print(response.text)
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
An explicit `api_key` takes precedence over `EARTHINIA_API_KEY`. The client does not load `.env` files.
|
|
48
|
+
Reuse a client for connection pooling; use it as a context manager or call `client.close()`.
|
|
49
|
+
|
|
50
|
+
## Contract and behavior
|
|
51
|
+
|
|
52
|
+
Both `chat.create` and `clusters.execute` call
|
|
53
|
+
`POST https://api.eacse.com/api/v1/clusters/{cluster_id}/chat` using `X-Earthinia-Key`.
|
|
54
|
+
The server derives account identity and permissions from the key. User identity cannot be overridden.
|
|
55
|
+
`chat.create` also accepts `session_id`, `metadata`, `attachments`, and `output_format`.
|
|
56
|
+
Attachment objects follow the public API contract; the client does not read or upload local files implicitly.
|
|
57
|
+
Responses are generated Pydantic models with `text`, `success`, `status`, `session_id`, `usage`, and other API fields.
|
|
58
|
+
The `earthinia.models.ChatResponse` alias refers to the generated response model.
|
|
59
|
+
|
|
60
|
+
The production origin defaults to `https://api.eacse.com`. Set `base_url` to an HTTPS origin
|
|
61
|
+
without `/api`; the client adds the full API path. Loopback HTTP is allowed for local development:
|
|
62
|
+
|
|
63
|
+
```python
|
|
64
|
+
client = Earthinia(base_url="http://localhost:8001", timeout=60)
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
`timeout` is a positive number of seconds (default 30), applied to connection and read operations.
|
|
68
|
+
It is not an end-to-end execution deadline. TLS verification stays enabled. Redirects are not followed.
|
|
69
|
+
Environment proxy and netrc settings are not used. Prompt submissions are never retried automatically:
|
|
70
|
+
a timeout may occur after execution has begun, so check the operation before submitting it again.
|
|
71
|
+
|
|
72
|
+
```python
|
|
73
|
+
from earthinia.exceptions import AuthenticationError, EarthiniaError, RateLimitError
|
|
74
|
+
|
|
75
|
+
try:
|
|
76
|
+
with Earthinia() as client:
|
|
77
|
+
response = client.chat.create("your-cluster-id", "Prepare today's sales report.")
|
|
78
|
+
except AuthenticationError:
|
|
79
|
+
print("Configure a valid API key.")
|
|
80
|
+
except RateLimitError as error:
|
|
81
|
+
print("Rate limited; retry-after seconds:", error.retry_after)
|
|
82
|
+
except EarthiniaError as error:
|
|
83
|
+
print(error.status_code, str(error))
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
HTTP failures raise SDK exceptions; malformed successful responses raise `SerializationError`.
|
|
87
|
+
Exception messages omit remote bodies and headers to avoid exposing credentials or user data.
|
|
88
|
+
The SDK does not log requests or keys.
|
|
89
|
+
|
|
90
|
+
## Supported surface
|
|
91
|
+
|
|
92
|
+
This release supports public-key chat and cluster prompt execution. Cluster administration,
|
|
93
|
+
files, sessions, streaming, and other account-management APIs are not exposed by this client.
|
|
94
|
+
Earlier README examples advertised unimplemented operations and a nonexistent async client;
|
|
95
|
+
there is no `AsyncEarthinia` or `run()` method. Use the actual methods above.
|
|
96
|
+
The former administrative cluster methods targeted nonexistent public-key endpoints and have
|
|
97
|
+
been removed from the client surface. `user_id` overrides are rejected. Chat responses are now
|
|
98
|
+
Pydantic objects; use `.model_dump()` or `.model_dump_json()` when you need serialized data.
|
|
99
|
+
|
|
100
|
+
The optional CLI uses the same key and endpoint:
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
earthinia your-cluster-id "Prepare today's sales report."
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Development and release
|
|
107
|
+
|
|
108
|
+
From this SDK directory:
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
python -m pip install '.[dev]'
|
|
112
|
+
python -m pytest
|
|
113
|
+
python -m build
|
|
114
|
+
python -m twine check dist/*
|
|
115
|
+
python ../../scripts/check-sdk-artifacts.py dist/*
|
|
116
|
+
python ../../scripts/test-python-sdk-install.py dist/*.whl
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
See [the monorepo release guide](https://github.com/kilan-go/earthinia-platform/blob/main/docs/sdk-releases.md)
|
|
120
|
+
for contract regeneration, independent versioning, and PyPI Trusted Publishing setup.
|
|
121
|
+
|
|
122
|
+
## License
|
|
123
|
+
|
|
124
|
+
MIT. See LICENSE.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
from ._version import __version__
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class APIKeyAuth:
|
|
5
|
+
def __init__(self, api_key: str):
|
|
6
|
+
self._api_key = api_key
|
|
7
|
+
|
|
8
|
+
@property
|
|
9
|
+
def headers(self) -> dict[str, str]:
|
|
10
|
+
return {
|
|
11
|
+
"X-Earthinia-Key": self._api_key,
|
|
12
|
+
"Accept": "application/json",
|
|
13
|
+
"User-Agent": f"earthinia-python/{__version__}",
|
|
14
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"""Synchronous public API client; no server dependencies are imported."""
|
|
2
|
+
import os
|
|
3
|
+
|
|
4
|
+
from .auth import APIKeyAuth
|
|
5
|
+
from .config import SDKConfig
|
|
6
|
+
from .exceptions import AuthenticationError
|
|
7
|
+
from .resources.chat import ChatResource
|
|
8
|
+
from .resources.clusters import ClusterResource
|
|
9
|
+
from .transport import Transport
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class Earthinia:
|
|
13
|
+
def __init__(self, api_key: str | None = None,
|
|
14
|
+
base_url: str = "https://api.eacse.com", *, timeout: float = 30.0):
|
|
15
|
+
key = api_key if api_key is not None else os.getenv("EARTHINIA_API_KEY")
|
|
16
|
+
if not isinstance(key, str) or not key.strip() or any(c.isspace() for c in key):
|
|
17
|
+
raise AuthenticationError("Provide api_key or set EARTHINIA_API_KEY to a non-empty API key.")
|
|
18
|
+
self._transport = Transport(SDKConfig(key, base_url, timeout), APIKeyAuth(key))
|
|
19
|
+
self.chat = ChatResource(self._transport)
|
|
20
|
+
self.clusters = ClusterResource(self._transport)
|
|
21
|
+
|
|
22
|
+
def close(self) -> None:
|
|
23
|
+
self._transport.close()
|
|
24
|
+
|
|
25
|
+
def __enter__(self):
|
|
26
|
+
return self
|
|
27
|
+
|
|
28
|
+
def __exit__(self, *_):
|
|
29
|
+
self.close()
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"""Validated connection settings. API keys are excluded from representations."""
|
|
2
|
+
from dataclasses import dataclass, field
|
|
3
|
+
import math
|
|
4
|
+
from urllib.parse import urlsplit
|
|
5
|
+
|
|
6
|
+
from .exceptions import ConfigurationError
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@dataclass
|
|
10
|
+
class SDKConfig:
|
|
11
|
+
api_key: str = field(repr=False)
|
|
12
|
+
base_url: str = "https://api.eacse.com"
|
|
13
|
+
timeout: float = 30.0
|
|
14
|
+
|
|
15
|
+
def __post_init__(self):
|
|
16
|
+
self.base_url = self.base_url.rstrip("/")
|
|
17
|
+
url = urlsplit(self.base_url)
|
|
18
|
+
local = url.hostname in {"localhost", "127.0.0.1", "::1"}
|
|
19
|
+
if (not url.hostname or url.username or url.password or url.query or url.fragment
|
|
20
|
+
or url.path or not (url.scheme == "https" or (url.scheme == "http" and local))):
|
|
21
|
+
raise ConfigurationError("base_url must be an HTTPS origin (HTTP is allowed on loopback for development).")
|
|
22
|
+
if not math.isfinite(self.timeout) or self.timeout <= 0:
|
|
23
|
+
raise ConfigurationError("timeout must be a positive finite number of seconds.")
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"""Command-line entry point for cluster prompts."""
|
|
2
|
+
|
|
3
|
+
import argparse
|
|
4
|
+
import base64
|
|
5
|
+
import mimetypes
|
|
6
|
+
import os
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
from .client import Earthinia
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def main():
|
|
13
|
+
parser = argparse.ArgumentParser(prog="earthinia")
|
|
14
|
+
parser.add_argument("cluster_id")
|
|
15
|
+
parser.add_argument("prompt")
|
|
16
|
+
parser.add_argument("--session", default="console")
|
|
17
|
+
parser.add_argument("--file", action="append", default=[])
|
|
18
|
+
parser.add_argument("--format", default="text")
|
|
19
|
+
parser.add_argument("--base-url", default=os.getenv("EARTHINIA_BASE_URL", "https://api.eacse.com"))
|
|
20
|
+
args = parser.parse_args()
|
|
21
|
+
|
|
22
|
+
attachments = []
|
|
23
|
+
for filename in args.file:
|
|
24
|
+
path = Path(filename)
|
|
25
|
+
attachments.append({
|
|
26
|
+
"filename": path.name,
|
|
27
|
+
"mime_type": mimetypes.guess_type(path.name)[0] or "application/octet-stream",
|
|
28
|
+
"content_base64": base64.b64encode(path.read_bytes()).decode(),
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
client = Earthinia(
|
|
32
|
+
api_key=os.getenv("EARTHINIA_API_KEY"),
|
|
33
|
+
base_url=args.base_url,
|
|
34
|
+
)
|
|
35
|
+
result = client.clusters.execute(
|
|
36
|
+
args.cluster_id,
|
|
37
|
+
args.prompt,
|
|
38
|
+
args.session,
|
|
39
|
+
attachments=attachments,
|
|
40
|
+
output_format=args.format,
|
|
41
|
+
)
|
|
42
|
+
print(result.model_dump_json(indent=2))
|
|
43
|
+
client.close()
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
if __name__ == "__main__":
|
|
47
|
+
main()
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Earthinia SDK Exceptions
|
|
3
|
+
|
|
4
|
+
Provides the complete exception hierarchy used by the SDK.
|
|
5
|
+
|
|
6
|
+
Applications should catch the most specific exception possible.
|
|
7
|
+
|
|
8
|
+
Example:
|
|
9
|
+
|
|
10
|
+
try:
|
|
11
|
+
client.chat.create(request)
|
|
12
|
+
except AuthenticationError:
|
|
13
|
+
...
|
|
14
|
+
except RateLimitError:
|
|
15
|
+
...
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
from __future__ import annotations
|
|
19
|
+
|
|
20
|
+
from typing import Any
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class EarthiniaError(Exception):
|
|
24
|
+
"""
|
|
25
|
+
Base class for all Earthinia SDK exceptions.
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
def __init__(
|
|
29
|
+
self,
|
|
30
|
+
message: str,
|
|
31
|
+
*,
|
|
32
|
+
status_code: int | None = None,
|
|
33
|
+
request_id: str | None = None,
|
|
34
|
+
error_code: str | None = None,
|
|
35
|
+
details: Any = None,
|
|
36
|
+
) -> None:
|
|
37
|
+
|
|
38
|
+
super().__init__(message)
|
|
39
|
+
|
|
40
|
+
self.message = message
|
|
41
|
+
self.status_code = status_code
|
|
42
|
+
self.request_id = request_id
|
|
43
|
+
self.error_code = error_code
|
|
44
|
+
self.details = details
|
|
45
|
+
|
|
46
|
+
def __str__(self) -> str:
|
|
47
|
+
|
|
48
|
+
parts = [self.message]
|
|
49
|
+
|
|
50
|
+
if self.status_code is not None:
|
|
51
|
+
parts.append(f"(status={self.status_code})")
|
|
52
|
+
|
|
53
|
+
if self.error_code:
|
|
54
|
+
parts.append(f"[{self.error_code}]")
|
|
55
|
+
|
|
56
|
+
if self.request_id:
|
|
57
|
+
parts.append(f"request_id={self.request_id}")
|
|
58
|
+
|
|
59
|
+
return " ".join(parts)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
# ---------------------------------------------------------------------
|
|
63
|
+
# Client Errors
|
|
64
|
+
# ---------------------------------------------------------------------
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class AuthenticationError(EarthiniaError):
|
|
68
|
+
"""
|
|
69
|
+
Invalid or expired API key.
|
|
70
|
+
"""
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
class AuthorizationError(EarthiniaError):
|
|
74
|
+
"""
|
|
75
|
+
User is authenticated but lacks permissions.
|
|
76
|
+
"""
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
class ValidationError(EarthiniaError):
|
|
80
|
+
"""
|
|
81
|
+
Invalid request payload.
|
|
82
|
+
"""
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
class ResourceNotFoundError(EarthiniaError):
|
|
86
|
+
"""
|
|
87
|
+
Requested resource does not exist.
|
|
88
|
+
"""
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
class ConflictError(EarthiniaError):
|
|
92
|
+
"""
|
|
93
|
+
Resource conflict.
|
|
94
|
+
"""
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
class RateLimitError(EarthiniaError):
|
|
98
|
+
"""
|
|
99
|
+
API rate limit exceeded.
|
|
100
|
+
"""
|
|
101
|
+
|
|
102
|
+
def __init__(
|
|
103
|
+
self,
|
|
104
|
+
message: str,
|
|
105
|
+
*,
|
|
106
|
+
retry_after: int | None = None,
|
|
107
|
+
**kwargs: Any,
|
|
108
|
+
) -> None:
|
|
109
|
+
|
|
110
|
+
super().__init__(message, **kwargs)
|
|
111
|
+
|
|
112
|
+
self.retry_after = retry_after
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
# ---------------------------------------------------------------------
|
|
116
|
+
# Server Errors
|
|
117
|
+
# ---------------------------------------------------------------------
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
class ServerError(EarthiniaError):
|
|
121
|
+
"""
|
|
122
|
+
Internal Earthinia server error.
|
|
123
|
+
"""
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
class ServiceUnavailableError(ServerError):
|
|
127
|
+
"""
|
|
128
|
+
Earthinia service temporarily unavailable.
|
|
129
|
+
"""
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
class TimeoutError(ServerError):
|
|
133
|
+
"""
|
|
134
|
+
Request timed out.
|
|
135
|
+
"""
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
# ---------------------------------------------------------------------
|
|
139
|
+
# SDK Errors
|
|
140
|
+
# ---------------------------------------------------------------------
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
class ConfigurationError(EarthiniaError):
|
|
144
|
+
"""
|
|
145
|
+
Invalid SDK configuration.
|
|
146
|
+
"""
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
class ConnectionError(EarthiniaError):
|
|
150
|
+
"""
|
|
151
|
+
Network connection failed.
|
|
152
|
+
"""
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
class SerializationError(EarthiniaError):
|
|
156
|
+
"""
|
|
157
|
+
Failed to serialize or deserialize data.
|
|
158
|
+
"""
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
class StreamingError(EarthiniaError):
|
|
162
|
+
"""
|
|
163
|
+
Streaming connection failed.
|
|
164
|
+
"""
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
class WebSocketError(EarthiniaError):
|
|
168
|
+
"""
|
|
169
|
+
WebSocket connection failed.
|
|
170
|
+
"""
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# generated by datamodel-codegen:
|
|
2
|
+
# filename: public.openapi.json
|
|
3
|
+
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
from enum import Enum
|
|
7
|
+
from typing import Any
|
|
8
|
+
|
|
9
|
+
from pydantic import BaseModel, ConfigDict, Field
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class Status(Enum):
|
|
13
|
+
completed = 'completed'
|
|
14
|
+
failed = 'failed'
|
|
15
|
+
needs_input = 'needs_input'
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class ExecutionError(BaseModel):
|
|
19
|
+
code: str = Field(..., title='Code')
|
|
20
|
+
details: dict[str, Any] | None = Field(None, title='Details')
|
|
21
|
+
message: str = Field(..., title='Message')
|
|
22
|
+
retryable: bool | None = Field(False, title='Retryable')
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class PublicChatRequest(BaseModel):
|
|
26
|
+
attachments: list[dict[str, Any]] | None = Field(None, title='Attachments')
|
|
27
|
+
channel: str | None = Field('api', title='Channel')
|
|
28
|
+
message: str = Field(..., title='Message')
|
|
29
|
+
metadata: dict[str, Any] | None = Field(None, title='Metadata')
|
|
30
|
+
output_format: str | None = Field('text', title='Output Format')
|
|
31
|
+
session_id: str | None = Field(None, title='Session Id')
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class ValidationError(BaseModel):
|
|
35
|
+
ctx: dict[str, Any] | None = Field(None, title='Context')
|
|
36
|
+
input: Any | None = Field(None, title='Input')
|
|
37
|
+
loc: list[str | int] = Field(..., title='Location')
|
|
38
|
+
msg: str = Field(..., title='Message')
|
|
39
|
+
type: str = Field(..., title='Error Type')
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class ChatResponse(BaseModel):
|
|
43
|
+
model_config = ConfigDict(
|
|
44
|
+
extra='forbid',
|
|
45
|
+
)
|
|
46
|
+
account_id: str = Field(..., title='Account Id')
|
|
47
|
+
channel: str = Field(..., title='Channel')
|
|
48
|
+
cluster_id: str = Field(..., title='Cluster Id')
|
|
49
|
+
detail: str | None = Field(None, title='Detail')
|
|
50
|
+
error: ExecutionError | None = None
|
|
51
|
+
id: str = Field(..., title='Id')
|
|
52
|
+
message: dict[str, Any] = Field(..., title='Message')
|
|
53
|
+
operations: dict[str, Any] | None = Field(None, title='Operations')
|
|
54
|
+
output: dict[str, Any] | None = Field(None, title='Output')
|
|
55
|
+
provider_event_id: str | None = Field(..., title='Provider Event Id')
|
|
56
|
+
request_id: str = Field(..., title='Request Id')
|
|
57
|
+
result: dict[str, Any] = Field(..., title='Result')
|
|
58
|
+
session_id: str = Field(..., title='Session Id')
|
|
59
|
+
status: Status = Field(..., title='Status')
|
|
60
|
+
success: bool = Field(..., title='Success')
|
|
61
|
+
text: str | None = Field('', title='Text')
|
|
62
|
+
usage: dict[str, int] | None = Field(None, title='Usage')
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class HTTPValidationError(BaseModel):
|
|
66
|
+
detail: list[ValidationError] | None = Field(None, title='Detail')
|