simile 0.1.1__tar.gz → 0.2.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.

Potentially problematic release.


This version of simile might be problematic. Click here for more details.

@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2025 Joon Sung Park
3
+ Copyright (c) 2025 Simile AI
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
simile-0.2.0/PKG-INFO ADDED
@@ -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
+ ```
simile-0.2.0/README.md ADDED
@@ -0,0 +1,22 @@
1
+ # Simile API Python Client
2
+
3
+ A Python client for interacting with the Simile API server.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pip install simile
9
+ ```
10
+
11
+ ## Dependencies
12
+
13
+ - `httpx>=0.20.0`
14
+ - `pydantic>=2.0.0`
15
+
16
+ ## Usage
17
+
18
+ ```python
19
+ from simile import Simile
20
+
21
+ client = Simile(api_key="your_api_key")
22
+ ```
@@ -0,0 +1,35 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "simile"
7
+ version = "0.2.0"
8
+ authors = [
9
+ { name="Simile AI", email="cqz@simile.ai" },
10
+ ]
11
+ description = "Package for interfacing with Simile AI agents for simulation"
12
+ readme = "README.md"
13
+ requires-python = ">=3.8"
14
+ license = { text = "MIT" }
15
+ keywords = ["api", "sdk", "simile", "ai-agent", "simulation"]
16
+ classifiers = [
17
+ "Development Status :: 3 - Alpha",
18
+ "Intended Audience :: Developers",
19
+ "Programming Language :: Python :: 3",
20
+ "Programming Language :: Python :: 3.8",
21
+ "Programming Language :: Python :: 3.9",
22
+ "Programming Language :: Python :: 3.10",
23
+ "Programming Language :: Python :: 3.11",
24
+ "Programming Language :: Python :: 3.12",
25
+ "Operating System :: OS Independent",
26
+ "Topic :: Software Development :: Libraries :: Python Modules",
27
+ ]
28
+
29
+ dependencies = [
30
+ "httpx>=0.20.0",
31
+ "pydantic>=2.0.0",
32
+ ]
33
+
34
+ [project.urls]
35
+ "Homepage" = "https://github.com/simile-team/simile-sdk"
simile-0.2.0/setup.py ADDED
@@ -0,0 +1,4 @@
1
+ from setuptools import setup
2
+
3
+ if __name__ == "__main__":
4
+ setup()
@@ -0,0 +1,28 @@
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
+ )
17
+
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
+ ]
27
+
28
+ __version__ = "0.1.0"
@@ -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()
@@ -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)
@@ -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,13 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ setup.py
5
+ simile/__init__.py
6
+ simile/client.py
7
+ simile/exceptions.py
8
+ simile/models.py
9
+ simile.egg-info/PKG-INFO
10
+ simile.egg-info/SOURCES.txt
11
+ simile.egg-info/dependency_links.txt
12
+ simile.egg-info/requires.txt
13
+ simile.egg-info/top_level.txt
@@ -0,0 +1,2 @@
1
+ httpx>=0.20.0
2
+ pydantic>=2.0.0
simile-0.1.1/MANIFEST.in DELETED
@@ -1,2 +0,0 @@
1
- include README.md
2
- include LICENSE
simile-0.1.1/PKG-INFO 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/README.md DELETED
@@ -1,16 +0,0 @@
1
- # Simile
2
-
3
- **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.
4
-
5
- ## Features
6
-
7
- - **Agent Management**: Create, delete, retrieve details for agents.
8
- - **Population Management**: Create populations, add/remove agents, delete, or create sub-populations.
9
- - **Asynchronous Tasks**: Returns a `Task` object that can be polled or waited upon for long-running operations.
10
-
11
- ## Installation
12
-
13
- Install via **pip** (once you've published to PyPI):
14
-
15
- ```bash
16
- pip install simile
simile-0.1.1/setup.py DELETED
@@ -1,26 +0,0 @@
1
- import setuptools
2
-
3
- with open("README.md", "r", encoding="utf-8") as fh:
4
- long_description = fh.read()
5
-
6
- setuptools.setup(
7
- name="simile", # Replace with your desired package name
8
- version="0.1.1",
9
- author="Joon Sung Park",
10
- author_email="joon.s.pk@gmail.com",
11
- description="A Python client library for interacting with my Agent & Population endpoints",
12
- long_description=long_description,
13
- long_description_content_type="text/markdown",
14
- url="https://github.com/simile-team/simile", # or your repo link
15
- packages=setuptools.find_packages(),
16
- install_requires=[
17
- "requests>=2.22.0",
18
- "urllib3>=1.26.0"
19
- ],
20
- classifiers=[
21
- "Programming Language :: Python :: 3",
22
- "License :: OSI Approved :: MIT License", # or your choice
23
- "Operating System :: OS Independent",
24
- ],
25
- python_requires='>=3.7',
26
- )
@@ -1,38 +0,0 @@
1
- # simile/__init__.py
2
- import sys
3
- from . import config
4
- from .resource_agent import Agent
5
- from .resource_population import Population
6
- from .task import Task
7
- from .config import configure
8
-
9
- class _SimileModuleProxy:
10
- def __init__(self, real_module):
11
- self._real_module = real_module
12
-
13
- def __getattr__(self, name):
14
- # If user says simile.api_key → return config.api_key
15
- if name == "api_key":
16
- return config.api_key
17
- elif name == "api_base":
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)
33
-
34
- # Grab the current module object
35
- _this_module = sys.modules[__name__]
36
-
37
- # Replace it with our proxy
38
- sys.modules[__name__] = _SimileModuleProxy(_this_module)
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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}")
@@ -1,8 +0,0 @@
1
- # simile/utils.py
2
- """
3
- Optional helper functions. You might or might not need this, depending on how you structure your code.
4
- For now, it's just a placeholder.
5
- """
6
-
7
- def example_helper():
8
- pass
@@ -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
@@ -1,17 +0,0 @@
1
- LICENSE
2
- MANIFEST.in
3
- README.md
4
- setup.py
5
- simile/__init__.py
6
- simile/api_requestor.py
7
- simile/config.py
8
- simile/error.py
9
- simile/resource_agent.py
10
- simile/resource_population.py
11
- simile/task.py
12
- simile/utils.py
13
- simile.egg-info/PKG-INFO
14
- simile.egg-info/SOURCES.txt
15
- simile.egg-info/dependency_links.txt
16
- simile.egg-info/requires.txt
17
- simile.egg-info/top_level.txt
@@ -1,2 +0,0 @@
1
- requests>=2.22.0
2
- urllib3>=1.26.0
File without changes