simile 0.1.1__py3-none-any.whl → 0.2.0__py3-none-any.whl
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.
Potentially problematic release.
This version of simile might be problematic. Click here for more details.
- simile/__init__.py +26 -36
- simile/client.py +134 -0
- simile/exceptions.py +31 -0
- simile/models.py +74 -0
- simile-0.2.0.dist-info/METADATA +47 -0
- simile-0.2.0.dist-info/RECORD +9 -0
- {simile-0.1.1.dist-info → simile-0.2.0.dist-info}/WHEEL +1 -1
- {simile-0.1.1.dist-info → simile-0.2.0.dist-info/licenses}/LICENSE +1 -1
- simile/api_requestor.py +0 -48
- simile/config.py +0 -21
- simile/error.py +0 -16
- simile/resource_agent.py +0 -135
- simile/resource_population.py +0 -119
- simile/task.py +0 -81
- simile/utils.py +0 -8
- simile-0.1.1.dist-info/METADATA +0 -41
- simile-0.1.1.dist-info/RECORD +0 -13
- {simile-0.1.1.dist-info → simile-0.2.0.dist-info}/top_level.txt +0 -0
simile/__init__.py
CHANGED
|
@@ -1,38 +1,28 @@
|
|
|
1
|
-
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
from .client import Simile
|
|
2
|
+
from .models import (
|
|
3
|
+
Population, Agent, DataItem,
|
|
4
|
+
CreatePopulationPayload, CreateAgentPayload, CreateDataItemPayload, UpdateDataItemPayload,
|
|
5
|
+
DeletionResponse,
|
|
6
|
+
QualGenerationRequest,
|
|
7
|
+
QualGenerationResponse,
|
|
8
|
+
MCGenerationRequest,
|
|
9
|
+
MCGenerationResponse
|
|
10
|
+
)
|
|
11
|
+
from .exceptions import (
|
|
12
|
+
SimileAPIError,
|
|
13
|
+
SimileAuthenticationError,
|
|
14
|
+
SimileNotFoundError,
|
|
15
|
+
SimileBadRequestError
|
|
16
|
+
)
|
|
8
17
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
return config.api_base
|
|
19
|
-
elif hasattr(self._real_module, name):
|
|
20
|
-
return getattr(self._real_module, name)
|
|
21
|
-
else:
|
|
22
|
-
raise AttributeError(f"No attribute {name} in simile")
|
|
23
|
-
|
|
24
|
-
def __setattr__(self, name, value):
|
|
25
|
-
if name in ("_real_module",):
|
|
26
|
-
super().__setattr__(name, value)
|
|
27
|
-
elif name == "api_key":
|
|
28
|
-
config.api_key = value
|
|
29
|
-
elif name == "api_base":
|
|
30
|
-
config.api_base = value
|
|
31
|
-
else:
|
|
32
|
-
setattr(self._real_module, name, value)
|
|
18
|
+
__all__ = [
|
|
19
|
+
"Simile",
|
|
20
|
+
"Population", "Agent", "DataItem",
|
|
21
|
+
"CreatePopulationPayload", "CreateAgentPayload", "CreateDataItemPayload", "UpdateDataItemPayload",
|
|
22
|
+
"DeletionResponse",
|
|
23
|
+
"QualGenerationRequest", "QualGenerationResponse",
|
|
24
|
+
"MCGenerationRequest", "MCGenerationResponse",
|
|
25
|
+
"SimileAPIError", "SimileAuthenticationError", "SimileNotFoundError", "SimileBadRequestError"
|
|
26
|
+
]
|
|
33
27
|
|
|
34
|
-
|
|
35
|
-
_this_module = sys.modules[__name__]
|
|
36
|
-
|
|
37
|
-
# Replace it with our proxy
|
|
38
|
-
sys.modules[__name__] = _SimileModuleProxy(_this_module)
|
|
28
|
+
__version__ = "0.1.0"
|
simile/client.py
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import httpx
|
|
2
|
+
from httpx import AsyncClient
|
|
3
|
+
from typing import List, Dict, Any, Optional, Union, Type
|
|
4
|
+
import uuid
|
|
5
|
+
from pydantic import BaseModel
|
|
6
|
+
|
|
7
|
+
from .models import (
|
|
8
|
+
Population, Agent, DataItem,
|
|
9
|
+
CreatePopulationPayload, CreateAgentPayload, CreateDataItemPayload, UpdateDataItemPayload,
|
|
10
|
+
DeletionResponse, QualGenerationRequest, QualGenerationResponse, MCGenerationRequest, MCGenerationResponse
|
|
11
|
+
)
|
|
12
|
+
from .exceptions import (
|
|
13
|
+
SimileAPIError, SimileAuthenticationError, SimileNotFoundError, SimileBadRequestError
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
DEFAULT_BASE_URL = "https://simile-api-3a83be7adae0.herokuapp.com/api/v1"
|
|
17
|
+
TIMEOUT_CONFIG = httpx.Timeout(5.0, read=30.0, write=30.0, pool=30.0)
|
|
18
|
+
|
|
19
|
+
class Simile:
|
|
20
|
+
def __init__(self, api_key: str, base_url: str = DEFAULT_BASE_URL):
|
|
21
|
+
if not api_key:
|
|
22
|
+
raise ValueError("API key is required.")
|
|
23
|
+
self.api_key = api_key
|
|
24
|
+
self.base_url = base_url.rstrip('/')
|
|
25
|
+
self._client = AsyncClient(
|
|
26
|
+
headers={"X-API-Key": self.api_key},
|
|
27
|
+
timeout=TIMEOUT_CONFIG
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
async def _request(self, method: str, endpoint: str, **kwargs) -> Union[httpx.Response, BaseModel]:
|
|
31
|
+
url = f"{self.base_url}/{endpoint.lstrip('/')}"
|
|
32
|
+
response_model_cls: Optional[Type[BaseModel]] = kwargs.pop("response_model", None)
|
|
33
|
+
|
|
34
|
+
try:
|
|
35
|
+
response = await self._client.request(method, url, **kwargs)
|
|
36
|
+
response.raise_for_status()
|
|
37
|
+
|
|
38
|
+
if response_model_cls:
|
|
39
|
+
return response_model_cls(**response.json())
|
|
40
|
+
else:
|
|
41
|
+
return response
|
|
42
|
+
except httpx.HTTPStatusError as e:
|
|
43
|
+
status_code = e.response.status_code
|
|
44
|
+
try:
|
|
45
|
+
error_data = e.response.json()
|
|
46
|
+
detail = error_data.get("detail", e.response.text)
|
|
47
|
+
except Exception:
|
|
48
|
+
detail = e.response.text
|
|
49
|
+
|
|
50
|
+
if status_code == 401:
|
|
51
|
+
raise SimileAuthenticationError(detail=detail)
|
|
52
|
+
elif status_code == 404:
|
|
53
|
+
raise SimileNotFoundError(detail=detail)
|
|
54
|
+
elif status_code == 400:
|
|
55
|
+
raise SimileBadRequestError(detail=detail)
|
|
56
|
+
else:
|
|
57
|
+
raise SimileAPIError(f"API request failed: {e}", status_code=status_code, detail=detail)
|
|
58
|
+
except httpx.RequestError as e:
|
|
59
|
+
raise SimileAPIError(f"Request error: {e}")
|
|
60
|
+
|
|
61
|
+
# --- Population Endpoints ---
|
|
62
|
+
async def create_population(self, payload: CreatePopulationPayload) -> Population:
|
|
63
|
+
response_data = await self._request("POST", "populations/create", json=payload.model_dump(mode='json', exclude_none=True), response_model=Population)
|
|
64
|
+
return response_data
|
|
65
|
+
|
|
66
|
+
async def get_population(self, population_id: Union[str, uuid.UUID]) -> Population:
|
|
67
|
+
response_data = await self._request("GET", f"populations/get/{str(population_id)}", response_model=Population)
|
|
68
|
+
return response_data
|
|
69
|
+
|
|
70
|
+
async def delete_population(self, population_id: Union[str, uuid.UUID]) -> DeletionResponse:
|
|
71
|
+
response_data = await self._request("DELETE", f"populations/delete/{str(population_id)}", response_model=DeletionResponse)
|
|
72
|
+
return response_data
|
|
73
|
+
|
|
74
|
+
# --- Agent Endpoints ---
|
|
75
|
+
async def create_agent(self, payload: CreateAgentPayload) -> Agent:
|
|
76
|
+
response_data = await self._request("POST", "agents/create", json=payload.model_dump(mode='json', exclude_none=True), response_model=Agent)
|
|
77
|
+
return response_data
|
|
78
|
+
|
|
79
|
+
async def get_agent(self, agent_id: Union[str, uuid.UUID]) -> Agent:
|
|
80
|
+
response_data = await self._request("GET", f"agents/get/{str(agent_id)}", response_model=Agent)
|
|
81
|
+
return response_data
|
|
82
|
+
|
|
83
|
+
async def delete_agent(self, agent_id: Union[str, uuid.UUID]) -> DeletionResponse:
|
|
84
|
+
response_data = await self._request("DELETE", f"agents/delete/{str(agent_id)}", response_model=DeletionResponse)
|
|
85
|
+
return response_data
|
|
86
|
+
|
|
87
|
+
# --- Data Item Endpoints ---
|
|
88
|
+
async def create_data_item(self, agent_id: Union[str, uuid.UUID], payload: CreateDataItemPayload) -> DataItem:
|
|
89
|
+
response_data = await self._request("POST", f"data_item/create/{str(agent_id)}", json=payload.model_dump(mode='json'), response_model=DataItem)
|
|
90
|
+
return response_data
|
|
91
|
+
|
|
92
|
+
async def get_data_item(self, data_item_id: Union[str, uuid.UUID]) -> DataItem:
|
|
93
|
+
response_data = await self._request("GET", f"data_item/get/{str(data_item_id)}", response_model=DataItem)
|
|
94
|
+
return response_data
|
|
95
|
+
|
|
96
|
+
async def list_data_items(self, agent_id: Union[str, uuid.UUID], data_type: Optional[str] = None) -> List[DataItem]:
|
|
97
|
+
params = {}
|
|
98
|
+
if data_type:
|
|
99
|
+
params["data_type"] = data_type
|
|
100
|
+
raw_response = await self._request("GET", f"data_item/list/{str(agent_id)}", params=params)
|
|
101
|
+
return [DataItem(**item) for item in raw_response.json()]
|
|
102
|
+
|
|
103
|
+
async def update_data_item(self, data_item_id: Union[str, uuid.UUID], payload: UpdateDataItemPayload) -> DataItem:
|
|
104
|
+
response_data = await self._request("POST", f"data_item/update/{data_item_id}", json=payload.model_dump(), response_model=DataItem)
|
|
105
|
+
return response_data
|
|
106
|
+
|
|
107
|
+
async def delete_data_item(self, data_item_id: Union[str, uuid.UUID]) -> DeletionResponse:
|
|
108
|
+
response_data = await self._request("DELETE", f"data_item/delete/{str(data_item_id)}", response_model=DeletionResponse)
|
|
109
|
+
return response_data
|
|
110
|
+
|
|
111
|
+
# --- LLM Generation Methods ---
|
|
112
|
+
async def generate_qual_response(self, agent_id: uuid.UUID, request_payload: QualGenerationRequest) -> QualGenerationResponse:
|
|
113
|
+
endpoint = f"/generation/qual/{str(agent_id)}"
|
|
114
|
+
response_data = await self._request(
|
|
115
|
+
"POST",
|
|
116
|
+
endpoint,
|
|
117
|
+
json=request_payload.model_dump(),
|
|
118
|
+
response_model=QualGenerationResponse
|
|
119
|
+
)
|
|
120
|
+
return response_data
|
|
121
|
+
|
|
122
|
+
async def generate_mc_response(self, agent_id: uuid.UUID, request_payload: MCGenerationRequest) -> MCGenerationResponse:
|
|
123
|
+
endpoint = f"generation/mc/{agent_id}"
|
|
124
|
+
response_data = await self._request("POST", endpoint, json=request_payload.model_dump(), response_model=MCGenerationResponse)
|
|
125
|
+
return response_data
|
|
126
|
+
|
|
127
|
+
async def aclose(self):
|
|
128
|
+
await self._client.aclose()
|
|
129
|
+
|
|
130
|
+
async def __aenter__(self):
|
|
131
|
+
return self
|
|
132
|
+
|
|
133
|
+
async def __aexit__(self, exc_type, exc_val, exc_tb):
|
|
134
|
+
await self.aclose()
|
simile/exceptions.py
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
class SimileAPIError(Exception):
|
|
2
|
+
"""Base exception for Simile API client errors."""
|
|
3
|
+
def __init__(self, message: str, status_code: int = None, detail: str = None):
|
|
4
|
+
super().__init__(message)
|
|
5
|
+
self.status_code = status_code
|
|
6
|
+
self.detail = detail
|
|
7
|
+
|
|
8
|
+
def __str__(self):
|
|
9
|
+
if self.status_code and self.detail:
|
|
10
|
+
return f"{super().__str__()} (Status Code: {self.status_code}, Detail: {self.detail})"
|
|
11
|
+
elif self.status_code:
|
|
12
|
+
return f"{super().__str__()} (Status Code: {self.status_code})"
|
|
13
|
+
return super().__str__()
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class SimileAuthenticationError(SimileAPIError):
|
|
17
|
+
"""Exception for authentication errors (e.g., invalid API key)."""
|
|
18
|
+
def __init__(self, message: str = "Authentication failed. Ensure API key is valid.", status_code: int = 401, detail: str = None):
|
|
19
|
+
super().__init__(message, status_code, detail)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class SimileNotFoundError(SimileAPIError):
|
|
23
|
+
"""Exception for resource not found errors (404)."""
|
|
24
|
+
def __init__(self, message: str = "Resource not found.", status_code: int = 404, detail: str = None):
|
|
25
|
+
super().__init__(message, status_code, detail)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class SimileBadRequestError(SimileAPIError):
|
|
29
|
+
"""Exception for bad request errors (400)."""
|
|
30
|
+
def __init__(self, message: str = "Bad request.", status_code: int = 400, detail: str = None):
|
|
31
|
+
super().__init__(message, status_code, detail)
|
simile/models.py
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
from typing import List, Dict, Any, Optional
|
|
2
|
+
from pydantic import BaseModel, Field
|
|
3
|
+
from datetime import datetime
|
|
4
|
+
import uuid
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Population(BaseModel):
|
|
8
|
+
population_id: uuid.UUID
|
|
9
|
+
name: str
|
|
10
|
+
description: Optional[str] = None
|
|
11
|
+
created_at: datetime
|
|
12
|
+
updated_at: datetime
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class DataItem(BaseModel):
|
|
16
|
+
id: uuid.UUID
|
|
17
|
+
agent_id: uuid.UUID
|
|
18
|
+
data_type: str
|
|
19
|
+
content: Any
|
|
20
|
+
created_at: datetime
|
|
21
|
+
updated_at: datetime
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class Agent(BaseModel):
|
|
25
|
+
agent_id: uuid.UUID
|
|
26
|
+
name: str
|
|
27
|
+
population_id: Optional[uuid.UUID] = None
|
|
28
|
+
created_at: datetime
|
|
29
|
+
updated_at: datetime
|
|
30
|
+
data_items: List[DataItem] = Field(default_factory=list)
|
|
31
|
+
|
|
32
|
+
class CreatePopulationPayload(BaseModel):
|
|
33
|
+
name: str
|
|
34
|
+
description: Optional[str] = None
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class CreateAgentPayload(BaseModel):
|
|
38
|
+
name: str
|
|
39
|
+
population_id: Optional[uuid.UUID] = None
|
|
40
|
+
agent_data: Optional[List[Dict[str, Any]]] = None # For initial data items
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class CreateDataItemPayload(BaseModel):
|
|
44
|
+
data_type: str
|
|
45
|
+
content: Any
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class UpdateDataItemPayload(BaseModel):
|
|
49
|
+
content: Any
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class DeletionResponse(BaseModel):
|
|
53
|
+
message: str
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
# --- LLM Generation Models ---
|
|
57
|
+
|
|
58
|
+
class QualGenerationRequest(BaseModel):
|
|
59
|
+
question: str
|
|
60
|
+
|
|
61
|
+
class QualGenerationResponse(BaseModel):
|
|
62
|
+
agent_id: uuid.UUID
|
|
63
|
+
question: str
|
|
64
|
+
answer: str
|
|
65
|
+
|
|
66
|
+
class MCGenerationRequest(BaseModel):
|
|
67
|
+
question: str
|
|
68
|
+
options: List[str]
|
|
69
|
+
|
|
70
|
+
class MCGenerationResponse(BaseModel):
|
|
71
|
+
agent_id: uuid.UUID
|
|
72
|
+
question: str
|
|
73
|
+
options: List[str]
|
|
74
|
+
chosen_option: str
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: simile
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Package for interfacing with Simile AI agents for simulation
|
|
5
|
+
Author-email: Simile AI <cqz@simile.ai>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/simile-team/simile-sdk
|
|
8
|
+
Keywords: api,sdk,simile,ai-agent,simulation
|
|
9
|
+
Classifier: Development Status :: 3 - Alpha
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Operating System :: OS Independent
|
|
18
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
19
|
+
Requires-Python: >=3.8
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
License-File: LICENSE
|
|
22
|
+
Requires-Dist: httpx>=0.20.0
|
|
23
|
+
Requires-Dist: pydantic>=2.0.0
|
|
24
|
+
Dynamic: license-file
|
|
25
|
+
|
|
26
|
+
# Simile API Python Client
|
|
27
|
+
|
|
28
|
+
A Python client for interacting with the Simile API server.
|
|
29
|
+
|
|
30
|
+
## Installation
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
pip install simile
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Dependencies
|
|
37
|
+
|
|
38
|
+
- `httpx>=0.20.0`
|
|
39
|
+
- `pydantic>=2.0.0`
|
|
40
|
+
|
|
41
|
+
## Usage
|
|
42
|
+
|
|
43
|
+
```python
|
|
44
|
+
from simile import Simile
|
|
45
|
+
|
|
46
|
+
client = Simile(api_key="your_api_key")
|
|
47
|
+
```
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
simile/__init__.py,sha256=2OZ1LQIkAEtSs0EI5Fzlg7QGKduCgCe_nTh9FfIuHlQ,865
|
|
2
|
+
simile/client.py,sha256=8FMhdyi35CQPJFh7pMLf6c9pczN7IlcCvnBh8kocOiI,6377
|
|
3
|
+
simile/exceptions.py,sha256=-rJ3KZcpvNRi9JXbDpxWDSL2lU1mEJX2piwYRZvhKmg,1406
|
|
4
|
+
simile/models.py,sha256=3T1UYCPp3KWMBD-u7lZEMahm4fS4ltm9h0oPUWs_oyI,1530
|
|
5
|
+
simile-0.2.0.dist-info/licenses/LICENSE,sha256=tpxX3bpODfyOQVyEM6kCMvPHFCpkjFDj0AICRqKqOFA,1066
|
|
6
|
+
simile-0.2.0.dist-info/METADATA,sha256=CTeN0Kl12ehJhMPbvra6o7ruVuojOyfpPB7uvUHuHjw,1245
|
|
7
|
+
simile-0.2.0.dist-info/WHEEL,sha256=DnLRTWE75wApRYVsjgc6wsVswC54sMSJhAEd4xhDpBk,91
|
|
8
|
+
simile-0.2.0.dist-info/top_level.txt,sha256=41lJneubAG4-ZOAs5qn7iDtDb-MDxa6DdvgBKwNX84M,7
|
|
9
|
+
simile-0.2.0.dist-info/RECORD,,
|
simile/api_requestor.py
DELETED
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
# simile/api_requestor.py
|
|
2
|
-
import requests
|
|
3
|
-
from . import config
|
|
4
|
-
from .error import AuthenticationError, RequestError, ApiKeyNotSetError
|
|
5
|
-
|
|
6
|
-
def request(method, endpoint, params=None, data=None, json=None, headers=None, timeout=30):
|
|
7
|
-
# Refer back to config.api_key so changes to config are seen here
|
|
8
|
-
if not config.api_key:
|
|
9
|
-
raise ApiKeyNotSetError("No API key set. Please set simile.api_key = '...'")
|
|
10
|
-
|
|
11
|
-
if not endpoint.startswith("/"):
|
|
12
|
-
endpoint = "/" + endpoint
|
|
13
|
-
|
|
14
|
-
url = config.api_base.rstrip("/") + endpoint
|
|
15
|
-
|
|
16
|
-
# Common default headers
|
|
17
|
-
default_headers = {
|
|
18
|
-
"Authorization": f"Api-Key {config.api_key}",
|
|
19
|
-
"Content-Type": "application/json",
|
|
20
|
-
}
|
|
21
|
-
if headers:
|
|
22
|
-
default_headers.update(headers)
|
|
23
|
-
|
|
24
|
-
try:
|
|
25
|
-
resp = requests.request(
|
|
26
|
-
method=method,
|
|
27
|
-
url=url,
|
|
28
|
-
params=params,
|
|
29
|
-
data=data,
|
|
30
|
-
json=json,
|
|
31
|
-
headers=default_headers,
|
|
32
|
-
timeout=timeout
|
|
33
|
-
)
|
|
34
|
-
except requests.exceptions.RequestException as e:
|
|
35
|
-
raise RequestError(f"Request error: {e}")
|
|
36
|
-
|
|
37
|
-
# Check for typical authentication or 4xx/5xx issues
|
|
38
|
-
if resp.status_code == 401:
|
|
39
|
-
raise AuthenticationError("Invalid or missing API key.")
|
|
40
|
-
elif 400 <= resp.status_code < 600:
|
|
41
|
-
# For all other error codes, raise a generic error
|
|
42
|
-
raise RequestError(
|
|
43
|
-
f"Error from server (status {resp.status_code}): {resp.text}",
|
|
44
|
-
status_code=resp.status_code,
|
|
45
|
-
response=resp.text
|
|
46
|
-
)
|
|
47
|
-
|
|
48
|
-
return resp
|
simile/config.py
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
# simile/config.py
|
|
2
|
-
"""
|
|
3
|
-
Holds global configurations for the simile library.
|
|
4
|
-
"""
|
|
5
|
-
|
|
6
|
-
# Default global configs
|
|
7
|
-
api_key = None # The user must set this before making calls
|
|
8
|
-
api_base = "https://agentbank-f515f1977c64.herokuapp.com/agents/api" # default; override if needed
|
|
9
|
-
|
|
10
|
-
def configure(key=None, base=None):
|
|
11
|
-
"""
|
|
12
|
-
Convenience function to set global API key/base from user code.
|
|
13
|
-
Example:
|
|
14
|
-
import simile
|
|
15
|
-
simile.configure(key="abc123", base="https://example.com/agents/api")
|
|
16
|
-
"""
|
|
17
|
-
global api_key, api_base
|
|
18
|
-
if key is not None:
|
|
19
|
-
api_key = key
|
|
20
|
-
if base is not None:
|
|
21
|
-
api_base = base
|
simile/error.py
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
# simile/error.py
|
|
2
|
-
"""
|
|
3
|
-
Custom error/exception types for the simile library.
|
|
4
|
-
"""
|
|
5
|
-
|
|
6
|
-
class ApiKeyNotSetError(Exception):
|
|
7
|
-
pass
|
|
8
|
-
|
|
9
|
-
class AuthenticationError(Exception):
|
|
10
|
-
pass
|
|
11
|
-
|
|
12
|
-
class RequestError(Exception):
|
|
13
|
-
def __init__(self, message, status_code=None, response=None):
|
|
14
|
-
super().__init__(message)
|
|
15
|
-
self.status_code = status_code
|
|
16
|
-
self.response = response
|
simile/resource_agent.py
DELETED
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
# simile/resource_agent.py
|
|
2
|
-
"""
|
|
3
|
-
Implements Agent-related methods.
|
|
4
|
-
We now hide async calls by automatically waiting on tasks.
|
|
5
|
-
"""
|
|
6
|
-
|
|
7
|
-
from .api_requestor import request
|
|
8
|
-
from .task import Task
|
|
9
|
-
from .error import RequestError
|
|
10
|
-
|
|
11
|
-
class Agent:
|
|
12
|
-
@staticmethod
|
|
13
|
-
def create(
|
|
14
|
-
first_name,
|
|
15
|
-
last_name,
|
|
16
|
-
forked_agent_id="",
|
|
17
|
-
speech_pattern="",
|
|
18
|
-
self_description="",
|
|
19
|
-
population_id=None,
|
|
20
|
-
read_permission="private",
|
|
21
|
-
write_permission="private",
|
|
22
|
-
agent_data=None
|
|
23
|
-
):
|
|
24
|
-
"""
|
|
25
|
-
Creates a new agent (blocking call).
|
|
26
|
-
|
|
27
|
-
* first_name (required)
|
|
28
|
-
* last_name (required)
|
|
29
|
-
* population_id (required)
|
|
30
|
-
* read_permission (default: 'private')
|
|
31
|
-
* write_permission (default: 'private')
|
|
32
|
-
|
|
33
|
-
This function will not return until the creation is fully done server-side.
|
|
34
|
-
|
|
35
|
-
Returns:
|
|
36
|
-
agent_id (str): The new agent's unique ID.
|
|
37
|
-
|
|
38
|
-
Raises:
|
|
39
|
-
ValueError if required fields are missing.
|
|
40
|
-
RequestError if the server returns an error.
|
|
41
|
-
"""
|
|
42
|
-
# Validate required fields
|
|
43
|
-
if not first_name:
|
|
44
|
-
raise ValueError("first_name is required.")
|
|
45
|
-
if not last_name:
|
|
46
|
-
raise ValueError("last_name is required.")
|
|
47
|
-
if not population_id:
|
|
48
|
-
raise ValueError("population_id is required.")
|
|
49
|
-
if not read_permission:
|
|
50
|
-
raise ValueError("read_permission is required.")
|
|
51
|
-
if not write_permission:
|
|
52
|
-
raise ValueError("write_permission is required.")
|
|
53
|
-
|
|
54
|
-
if agent_data is None:
|
|
55
|
-
agent_data = []
|
|
56
|
-
|
|
57
|
-
payload = {
|
|
58
|
-
"first_name": first_name,
|
|
59
|
-
"last_name": last_name,
|
|
60
|
-
"forked_agent_id": forked_agent_id,
|
|
61
|
-
"speech_pattern": speech_pattern,
|
|
62
|
-
"self_description": self_description,
|
|
63
|
-
"population_id": population_id,
|
|
64
|
-
"read_permission": read_permission,
|
|
65
|
-
"write_permission": write_permission,
|
|
66
|
-
"agent_data": agent_data
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
# Kick off the creation, which returns a task
|
|
70
|
-
resp = request("POST", "/create_single_agent/", json=payload)
|
|
71
|
-
data = resp.json()
|
|
72
|
-
task_id = data.get("task_id")
|
|
73
|
-
if not task_id:
|
|
74
|
-
raise RequestError("No 'task_id' returned from create_single_agent endpoint.")
|
|
75
|
-
|
|
76
|
-
# The result endpoint is /create_single_agent_result/<task_id>/
|
|
77
|
-
result_endpoint = "/create_single_agent_result/{task_id}/"
|
|
78
|
-
|
|
79
|
-
# Wait for the task to finish
|
|
80
|
-
final_data = Task(task_id, result_endpoint).wait()
|
|
81
|
-
agent_id = final_data.get("agent_id")
|
|
82
|
-
|
|
83
|
-
if not agent_id:
|
|
84
|
-
raise RequestError("No 'agent_id' returned in final result.")
|
|
85
|
-
|
|
86
|
-
return agent_id
|
|
87
|
-
|
|
88
|
-
@staticmethod
|
|
89
|
-
def retrieve_details(agent_id):
|
|
90
|
-
"""
|
|
91
|
-
Synchronously retrieve agent details via GET /get_agent_details/.
|
|
92
|
-
Returns a dict with details or raises RequestError on failure.
|
|
93
|
-
"""
|
|
94
|
-
params = {"agent_id": agent_id}
|
|
95
|
-
resp = request("GET", "/get_agent_details/", params=params)
|
|
96
|
-
return resp.json()
|
|
97
|
-
|
|
98
|
-
@staticmethod
|
|
99
|
-
def delete(agent_id):
|
|
100
|
-
"""
|
|
101
|
-
Synchronously delete an agent via POST /delete_agent/.
|
|
102
|
-
Returns a dict with {status, message} or raises RequestError.
|
|
103
|
-
"""
|
|
104
|
-
payload = {"agent_id": agent_id}
|
|
105
|
-
resp = request("POST", "/delete_agent/", json=payload)
|
|
106
|
-
return resp.json()
|
|
107
|
-
|
|
108
|
-
@staticmethod
|
|
109
|
-
def generate_response(agent_id, question_type, question_payload):
|
|
110
|
-
"""
|
|
111
|
-
Generates an agent's response (blocking call).
|
|
112
|
-
|
|
113
|
-
question_type can be 'categorical', 'numerical', or 'chat'.
|
|
114
|
-
question_payload is a dict, e.g. { "question": "...", "options": [...] }
|
|
115
|
-
|
|
116
|
-
Returns:
|
|
117
|
-
The final result from the server once the async task completes.
|
|
118
|
-
"""
|
|
119
|
-
payload = {
|
|
120
|
-
"agent_id": agent_id,
|
|
121
|
-
"question_type": question_type,
|
|
122
|
-
"question": question_payload
|
|
123
|
-
}
|
|
124
|
-
resp = request("POST", "/generate_agent_response/", json=payload)
|
|
125
|
-
data = resp.json()
|
|
126
|
-
task_id = data.get("task_id")
|
|
127
|
-
if not task_id:
|
|
128
|
-
raise RequestError("No 'task_id' returned from generate_agent_response endpoint.")
|
|
129
|
-
|
|
130
|
-
# The result endpoint is /generate_agent_response_result/<task_id>/
|
|
131
|
-
result_endpoint = "/generate_agent_response_result/{task_id}/"
|
|
132
|
-
|
|
133
|
-
# Wait and return final data
|
|
134
|
-
final_data = Task(task_id, result_endpoint).wait()
|
|
135
|
-
return final_data
|
simile/resource_population.py
DELETED
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
# simile/resource_population.py
|
|
2
|
-
"""
|
|
3
|
-
Implements Population-related methods.
|
|
4
|
-
Some are synchronous; get_sub_population is async but we now hide the wait.
|
|
5
|
-
"""
|
|
6
|
-
|
|
7
|
-
from .api_requestor import request
|
|
8
|
-
from .task import Task
|
|
9
|
-
from .error import RequestError
|
|
10
|
-
|
|
11
|
-
class Population:
|
|
12
|
-
@staticmethod
|
|
13
|
-
def create(name, read_permission="private", write_permission="private", readme=""):
|
|
14
|
-
"""
|
|
15
|
-
Synchronously create a population via POST /create_population/.
|
|
16
|
-
|
|
17
|
-
Required fields:
|
|
18
|
-
- name
|
|
19
|
-
- read_permission
|
|
20
|
-
- write_permission
|
|
21
|
-
Optional:
|
|
22
|
-
- readme
|
|
23
|
-
|
|
24
|
-
Returns:
|
|
25
|
-
{
|
|
26
|
-
"status": "success",
|
|
27
|
-
"population_id": "..."
|
|
28
|
-
}
|
|
29
|
-
or raises an error.
|
|
30
|
-
"""
|
|
31
|
-
if not name:
|
|
32
|
-
raise ValueError("name is required.")
|
|
33
|
-
if not read_permission:
|
|
34
|
-
raise ValueError("read_permission is required.")
|
|
35
|
-
if not write_permission:
|
|
36
|
-
raise ValueError("write_permission is required.")
|
|
37
|
-
|
|
38
|
-
payload = {
|
|
39
|
-
"name": name,
|
|
40
|
-
"read_permission": read_permission,
|
|
41
|
-
"write_permission": write_permission,
|
|
42
|
-
"readme": readme
|
|
43
|
-
}
|
|
44
|
-
resp = request("POST", "/create_population/", json=payload)
|
|
45
|
-
return resp.json()
|
|
46
|
-
|
|
47
|
-
@staticmethod
|
|
48
|
-
def get_agents(population_id):
|
|
49
|
-
"""
|
|
50
|
-
Synchronously get the agents in a population via GET /get_population_agents/.
|
|
51
|
-
Returns { "agent_ids": [ ... ] }
|
|
52
|
-
"""
|
|
53
|
-
params = {"population_id": population_id}
|
|
54
|
-
resp = request("GET", "/get_population_agents/", params=params)
|
|
55
|
-
return resp.json()
|
|
56
|
-
|
|
57
|
-
@staticmethod
|
|
58
|
-
def add_agent(population_id, agent_id):
|
|
59
|
-
"""
|
|
60
|
-
Synchronously add an agent to a population via POST /population_add_agent/.
|
|
61
|
-
Returns { "status": "...", "message": "..." } or raises an error.
|
|
62
|
-
"""
|
|
63
|
-
payload = {
|
|
64
|
-
"population_id": population_id,
|
|
65
|
-
"agent_id": agent_id
|
|
66
|
-
}
|
|
67
|
-
resp = request("POST", "/population_add_agent/", json=payload)
|
|
68
|
-
return resp.json()
|
|
69
|
-
|
|
70
|
-
@staticmethod
|
|
71
|
-
def remove_agent(population_id, agent_id):
|
|
72
|
-
"""
|
|
73
|
-
Synchronously remove an agent from a population via DELETE /population_remove_agent/.
|
|
74
|
-
Returns { "status": "...", "message": "..." } or raises an error.
|
|
75
|
-
"""
|
|
76
|
-
payload = {
|
|
77
|
-
"population_id": population_id,
|
|
78
|
-
"agent_id": agent_id
|
|
79
|
-
}
|
|
80
|
-
resp = request("DELETE", "/population_remove_agent/", json=payload)
|
|
81
|
-
return resp.json()
|
|
82
|
-
|
|
83
|
-
@staticmethod
|
|
84
|
-
def delete(population_id):
|
|
85
|
-
"""
|
|
86
|
-
Synchronously delete a population via DELETE /delete_population/.
|
|
87
|
-
Returns { "status": "...", "message": "..." }
|
|
88
|
-
"""
|
|
89
|
-
payload = {"population_id": population_id}
|
|
90
|
-
resp = request("DELETE", "/delete_population/", json=payload)
|
|
91
|
-
return resp.json()
|
|
92
|
-
|
|
93
|
-
@staticmethod
|
|
94
|
-
def get_sub_population(population_id="", n=1):
|
|
95
|
-
"""
|
|
96
|
-
Initiates a sub-population retrieval/generation (blocking call) by sampling
|
|
97
|
-
from an existing population (if population_id is provided) or from all
|
|
98
|
-
agents if no population_id is given.
|
|
99
|
-
|
|
100
|
-
Endpoint: POST /get_sub_population/
|
|
101
|
-
Waits until the async task completes, then returns final result, typically
|
|
102
|
-
containing "new_population_id".
|
|
103
|
-
"""
|
|
104
|
-
payload = {
|
|
105
|
-
"population_id": population_id,
|
|
106
|
-
"n": n
|
|
107
|
-
}
|
|
108
|
-
resp = request("POST", "/get_sub_population/", json=payload)
|
|
109
|
-
data = resp.json()
|
|
110
|
-
task_id = data.get("task_id")
|
|
111
|
-
if not task_id:
|
|
112
|
-
raise RequestError("No 'task_id' returned from get_sub_population endpoint.")
|
|
113
|
-
|
|
114
|
-
# The result endpoint is /get_sub_population_result/<task_id>/
|
|
115
|
-
result_endpoint = "/get_sub_population_result/{task_id}/"
|
|
116
|
-
|
|
117
|
-
# Wait for completion and return the final result
|
|
118
|
-
final_data = Task(task_id, result_endpoint).wait()
|
|
119
|
-
return final_data
|
simile/task.py
DELETED
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
# simile/task.py
|
|
2
|
-
import time
|
|
3
|
-
from .api_requestor import request
|
|
4
|
-
|
|
5
|
-
class Task:
|
|
6
|
-
"""
|
|
7
|
-
Represents an asynchronous Celery-like task.
|
|
8
|
-
Contains logic for polling the result endpoint until completion or failure.
|
|
9
|
-
Used internally to hide the async nature from the end user.
|
|
10
|
-
"""
|
|
11
|
-
def __init__(self, task_id, result_endpoint):
|
|
12
|
-
self.task_id = task_id
|
|
13
|
-
self.result_endpoint = result_endpoint # e.g. '/generate_agent_response_result/{task_id}/'
|
|
14
|
-
self._last_status = None
|
|
15
|
-
self._last_result = None
|
|
16
|
-
self._finished = False
|
|
17
|
-
|
|
18
|
-
@property
|
|
19
|
-
def last_status(self):
|
|
20
|
-
"""Returns the last known status from the server."""
|
|
21
|
-
return self._last_status
|
|
22
|
-
|
|
23
|
-
@property
|
|
24
|
-
def result(self):
|
|
25
|
-
"""If the task has finished successfully, returns the result payload."""
|
|
26
|
-
if self._finished and self._last_status == "SUCCESS":
|
|
27
|
-
return self._last_result
|
|
28
|
-
return None
|
|
29
|
-
|
|
30
|
-
@property
|
|
31
|
-
def error(self):
|
|
32
|
-
"""If the task has failed, returns the error message."""
|
|
33
|
-
if self._finished and self._last_status == "FAILURE":
|
|
34
|
-
return self._last_result
|
|
35
|
-
return None
|
|
36
|
-
|
|
37
|
-
def poll(self):
|
|
38
|
-
"""
|
|
39
|
-
Perform a single poll to the result endpoint,
|
|
40
|
-
storing the status in self._last_status and marking self._finished if done.
|
|
41
|
-
"""
|
|
42
|
-
url = self.result_endpoint.format(task_id=self.task_id)
|
|
43
|
-
resp = request("GET", url)
|
|
44
|
-
data = resp.json()
|
|
45
|
-
|
|
46
|
-
status_ = data.get("status")
|
|
47
|
-
self._last_status = status_
|
|
48
|
-
|
|
49
|
-
if status_ == "PENDING":
|
|
50
|
-
# still running
|
|
51
|
-
pass
|
|
52
|
-
elif status_ == "SUCCESS":
|
|
53
|
-
self._finished = True
|
|
54
|
-
self._last_result = data.get("result") or data.get("data")
|
|
55
|
-
elif status_ == "FAILURE":
|
|
56
|
-
self._finished = True
|
|
57
|
-
self._last_result = data.get("error")
|
|
58
|
-
else:
|
|
59
|
-
# Some other custom statuses are treated as "still running"
|
|
60
|
-
pass
|
|
61
|
-
|
|
62
|
-
def wait(self, interval=2, timeout=300):
|
|
63
|
-
"""
|
|
64
|
-
Poll in a loop until the task finishes or times out.
|
|
65
|
-
Returns the final result on success, or raises an exception on failure or timeout.
|
|
66
|
-
"""
|
|
67
|
-
start = time.time()
|
|
68
|
-
while True:
|
|
69
|
-
self.poll()
|
|
70
|
-
if self._finished:
|
|
71
|
-
break
|
|
72
|
-
if time.time() - start > timeout:
|
|
73
|
-
raise TimeoutError(
|
|
74
|
-
f"Task {self.task_id} did not complete within {timeout} seconds."
|
|
75
|
-
)
|
|
76
|
-
time.sleep(interval)
|
|
77
|
-
|
|
78
|
-
if self._last_status == "SUCCESS":
|
|
79
|
-
return self._last_result
|
|
80
|
-
else:
|
|
81
|
-
raise RuntimeError(f"Task {self.task_id} failed with error: {self._last_result}")
|
simile/utils.py
DELETED
simile-0.1.1.dist-info/METADATA
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.2
|
|
2
|
-
Name: simile
|
|
3
|
-
Version: 0.1.1
|
|
4
|
-
Summary: A Python client library for interacting with my Agent & Population endpoints
|
|
5
|
-
Home-page: https://github.com/simile-team/simile
|
|
6
|
-
Author: Joon Sung Park
|
|
7
|
-
Author-email: joon.s.pk@gmail.com
|
|
8
|
-
Classifier: Programming Language :: Python :: 3
|
|
9
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
-
Classifier: Operating System :: OS Independent
|
|
11
|
-
Requires-Python: >=3.7
|
|
12
|
-
Description-Content-Type: text/markdown
|
|
13
|
-
License-File: LICENSE
|
|
14
|
-
Requires-Dist: requests>=2.22.0
|
|
15
|
-
Requires-Dist: urllib3>=1.26.0
|
|
16
|
-
Dynamic: author
|
|
17
|
-
Dynamic: author-email
|
|
18
|
-
Dynamic: classifier
|
|
19
|
-
Dynamic: description
|
|
20
|
-
Dynamic: description-content-type
|
|
21
|
-
Dynamic: home-page
|
|
22
|
-
Dynamic: requires-dist
|
|
23
|
-
Dynamic: requires-python
|
|
24
|
-
Dynamic: summary
|
|
25
|
-
|
|
26
|
-
# Simile
|
|
27
|
-
|
|
28
|
-
**Simile** is a Python client library for interacting with your Agent & Population endpoints. It provides a simple interface for creating and managing agents, managing populations, and performing asynchronous tasks such as generating agent responses or creating sub-populations.
|
|
29
|
-
|
|
30
|
-
## Features
|
|
31
|
-
|
|
32
|
-
- **Agent Management**: Create, delete, retrieve details for agents.
|
|
33
|
-
- **Population Management**: Create populations, add/remove agents, delete, or create sub-populations.
|
|
34
|
-
- **Asynchronous Tasks**: Returns a `Task` object that can be polled or waited upon for long-running operations.
|
|
35
|
-
|
|
36
|
-
## Installation
|
|
37
|
-
|
|
38
|
-
Install via **pip** (once you've published to PyPI):
|
|
39
|
-
|
|
40
|
-
```bash
|
|
41
|
-
pip install simile
|
simile-0.1.1.dist-info/RECORD
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
simile/__init__.py,sha256=ru0KrsAf-hMJLigoRePoGt8rIA_q8GAaq5FgO42RD-U,1193
|
|
2
|
-
simile/api_requestor.py,sha256=03SWFV5Nrc9w-4ZCJ29hWTJSN8paR26isTLLrwL0h_0,1546
|
|
3
|
-
simile/config.py,sha256=q9twMCyF7jmzxWI0u1KDEXY-MBhHzcy3EiggwzAl-wU,624
|
|
4
|
-
simile/error.py,sha256=Kw6qAtqp1xugiRmA0PuX5q8Rq_RoeP7c7nXuepD86Dk,377
|
|
5
|
-
simile/resource_agent.py,sha256=ZwFYRfRTIxjMFwZ8eFHMgArzFt8MJIUl7DTmhVrBtPU,4579
|
|
6
|
-
simile/resource_population.py,sha256=SHyyBNfuwdrLtOdhLLVUyAs_8y-hs1sPcE6kbWjwWBA,4011
|
|
7
|
-
simile/task.py,sha256=Fn40AHX5FYRDuGdIzWMtMOAjI5O_GHkFpE-li5Cpwck,2737
|
|
8
|
-
simile/utils.py,sha256=1m3IIUY4kGOsy3nMijGWXVqy6MFekEl2IvSsaevNARQ,195
|
|
9
|
-
simile-0.1.1.dist-info/LICENSE,sha256=SwJ_Xw9Vk_7LCC8ttVixbpNxJumTBv04H_gizLbDjkc,1071
|
|
10
|
-
simile-0.1.1.dist-info/METADATA,sha256=klrHynWpxXPIS8I4vLaqwDvlsIVuUvFybfP3Wr2rud4,1421
|
|
11
|
-
simile-0.1.1.dist-info/WHEEL,sha256=52BFRY2Up02UkjOa29eZOS2VxUrpPORXg1pkohGGUS8,91
|
|
12
|
-
simile-0.1.1.dist-info/top_level.txt,sha256=41lJneubAG4-ZOAs5qn7iDtDb-MDxa6DdvgBKwNX84M,7
|
|
13
|
-
simile-0.1.1.dist-info/RECORD,,
|
|
File without changes
|