simile 0.1.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.

simile-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Joon Sung Park
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.
@@ -0,0 +1,2 @@
1
+ include README.md
2
+ include LICENSE
simile-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,41 @@
1
+ Metadata-Version: 2.2
2
+ Name: simile
3
+ Version: 0.1.0
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.0/README.md ADDED
@@ -0,0 +1,16 @@
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.0/setup.cfg ADDED
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
simile-0.1.0/setup.py ADDED
@@ -0,0 +1,26 @@
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.0",
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
+ )
@@ -0,0 +1,38 @@
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)
@@ -0,0 +1,48 @@
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
@@ -0,0 +1,21 @@
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
@@ -0,0 +1,16 @@
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
@@ -0,0 +1,105 @@
1
+ # simile/resource_agent.py
2
+ """
3
+ Implements Agent-related methods analogous to how you might use openai.Completion or similar classes.
4
+ """
5
+
6
+ from .api_requestor import request
7
+ from .task import Task
8
+ from .error import RequestError
9
+
10
+ class Agent:
11
+ @staticmethod
12
+ def create(
13
+ first_name,
14
+ last_name,
15
+ forked_agent_id="",
16
+ speech_pattern="",
17
+ self_description="",
18
+ population_id="",
19
+ read_permission="private",
20
+ write_permission="private",
21
+ agent_data=None
22
+ ):
23
+ """
24
+ Asynchronously create an agent via POST /create_single_agent/
25
+ Returns a Task object that you can poll or wait on.
26
+
27
+ Usage:
28
+ from simile import Agent
29
+ task = Agent.create("John", "Doe")
30
+ # block until done:
31
+ result = task.wait() # => {"agent_id": "..."}
32
+ new_agent_id = result["agent_id"]
33
+ """
34
+ if agent_data is None:
35
+ agent_data = []
36
+
37
+ payload = {
38
+ "first_name": first_name,
39
+ "last_name": last_name,
40
+ "forked_agent_id": forked_agent_id,
41
+ "speech_pattern": speech_pattern,
42
+ "self_description": self_description,
43
+ "population_id": population_id,
44
+ "read_permission": read_permission,
45
+ "write_permission": write_permission,
46
+ "agent_data": agent_data
47
+ }
48
+
49
+ resp = request("POST", "/create_single_agent/", json=payload)
50
+ data = resp.json()
51
+ task_id = data.get("task_id")
52
+ if not task_id:
53
+ raise RequestError("No 'task_id' returned from create_single_agent endpoint.")
54
+
55
+ # The result endpoint is /create_single_agent_result/<task_id>/
56
+ result_endpoint = "/create_single_agent_result/{task_id}/"
57
+ return Task(task_id, result_endpoint)
58
+
59
+ @staticmethod
60
+ def retrieve_details(agent_id):
61
+ """
62
+ Synchronously retrieve agent details via GET /get_agent_details/.
63
+ Returns a dict with details or raises RequestError on failure.
64
+ """
65
+ params = {"agent_id": agent_id}
66
+ resp = request("GET", "/get_agent_details/", params=params)
67
+ return resp.json()
68
+
69
+ @staticmethod
70
+ def delete(agent_id):
71
+ """
72
+ Synchronously delete an agent via POST /delete_agent/.
73
+ Returns a dict with {status, message} or raises RequestError.
74
+ """
75
+ payload = {"agent_id": agent_id}
76
+ resp = request("POST", "/delete_agent/", json=payload)
77
+ return resp.json()
78
+
79
+ @staticmethod
80
+ def generate_response(agent_id, question_type, question_payload):
81
+ """
82
+ Asynchronously generate an agent's response via /generate_agent_response/.
83
+ question_type can be 'categorical', 'numerical', or 'chat'.
84
+ question_payload is a dict. E.g. { "question": "...", "options": [...] }, etc.
85
+
86
+ Returns a Task object for polling or waiting.
87
+ Usage:
88
+ from simile import Agent
89
+ task = Agent.generate_response("a_123", "chat", {...})
90
+ result = task.wait()
91
+ """
92
+ payload = {
93
+ "agent_id": agent_id,
94
+ "question_type": question_type,
95
+ "question": question_payload
96
+ }
97
+ resp = request("POST", "/generate_agent_response/", json=payload)
98
+ data = resp.json()
99
+ task_id = data.get("task_id")
100
+ if not task_id:
101
+ raise RequestError("No 'task_id' returned from generate_agent_response endpoint.")
102
+
103
+ # The result endpoint is /generate_agent_response_result/<task_id>/
104
+ result_endpoint = "/generate_agent_response_result/{task_id}/"
105
+ return Task(task_id, result_endpoint)
@@ -0,0 +1,87 @@
1
+ # simile/resource_population.py
2
+ """
3
+ Implements Population-related methods: create, get_agents, add_agent, remove_agent, delete, etc.
4
+ """
5
+
6
+ from .api_requestor import request
7
+ from .task import Task
8
+ from .error import RequestError
9
+
10
+ class Population:
11
+ @staticmethod
12
+ def create(name="New Population"):
13
+ """
14
+ Synchronously create a population via POST /create_population/.
15
+ Returns a dict { "status": "success", "population_id": "..." } or raises an error.
16
+ """
17
+ payload = {"name": name}
18
+ resp = request("POST", "/create_population/", json=payload)
19
+ return resp.json()
20
+
21
+ @staticmethod
22
+ def get_agents(population_id):
23
+ """
24
+ Synchronously get the agents in a population via GET /get_population_agents/.
25
+ Returns { "agent_ids": [ ... ] }
26
+ """
27
+ params = {"population_id": population_id}
28
+ resp = request("GET", "/get_population_agents/", params=params)
29
+ return resp.json()
30
+
31
+ @staticmethod
32
+ def add_agent(population_id, agent_id):
33
+ """
34
+ Synchronously add an agent to a population via POST /population_add_agent/.
35
+ Returns { "status": "...", "message": "..." } or raises an error.
36
+ """
37
+ payload = {
38
+ "population_id": population_id,
39
+ "agent_id": agent_id
40
+ }
41
+ resp = request("POST", "/population_add_agent/", json=payload)
42
+ return resp.json()
43
+
44
+ @staticmethod
45
+ def remove_agent(population_id, agent_id):
46
+ """
47
+ Synchronously remove an agent from a population via DELETE /population_remove_agent/.
48
+ Returns { "status": "...", "message": "..." } or raises an error.
49
+ """
50
+ payload = {
51
+ "population_id": population_id,
52
+ "agent_id": agent_id
53
+ }
54
+ resp = request("DELETE", "/population_remove_agent/", json=payload)
55
+ return resp.json()
56
+
57
+ @staticmethod
58
+ def delete(population_id):
59
+ """
60
+ Synchronously delete a population via DELETE /delete_population/.
61
+ Returns { "status": "...", "message": "..." }
62
+ """
63
+ payload = {"population_id": population_id}
64
+ resp = request("DELETE", "/delete_population/", json=payload)
65
+ return resp.json()
66
+
67
+ @staticmethod
68
+ def create_sub_population(population_id="", n=1):
69
+ """
70
+ Asynchronously create a sub-population by sampling from an existing population
71
+ or from all agents if no population_id is given.
72
+ Endpoint: POST /create_sub_population/
73
+ Returns a Task object. On success, final data should have "new_population_id".
74
+ """
75
+ payload = {
76
+ "population_id": population_id,
77
+ "n": n
78
+ }
79
+ resp = request("POST", "/create_sub_population/", json=payload)
80
+ data = resp.json()
81
+ task_id = data.get("task_id")
82
+ if not task_id:
83
+ raise RequestError("No 'task_id' returned from create_sub_population endpoint.")
84
+
85
+ # The result endpoint is /create_sub_population_result/<task_id>/
86
+ result_endpoint = "/create_sub_population_result/{task_id}/"
87
+ return Task(task_id, result_endpoint)
@@ -0,0 +1,79 @@
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
+ """
10
+ def __init__(self, task_id, result_endpoint):
11
+ self.task_id = task_id
12
+ self.result_endpoint = result_endpoint # e.g. '/generate_agent_response_result/{task_id}/'
13
+ self._last_status = None
14
+ self._last_result = None
15
+ self._finished = False
16
+
17
+ @property
18
+ def last_status(self):
19
+ """Returns the last known status from the server."""
20
+ return self._last_status
21
+
22
+ @property
23
+ def result(self):
24
+ """If the task has finished successfully, returns the result payload."""
25
+ if self._finished and self._last_status == "SUCCESS":
26
+ return self._last_result
27
+ return None
28
+
29
+ @property
30
+ def error(self):
31
+ """If the task has failed, returns the error message."""
32
+ if self._finished and self._last_status == "FAILURE":
33
+ return self._last_result
34
+ return None
35
+
36
+ def poll(self):
37
+ """
38
+ Perform a single poll to the result endpoint,
39
+ storing the status in self._last_status and marking self._finished if done.
40
+ """
41
+ url = self.result_endpoint.format(task_id=self.task_id)
42
+ resp = request("GET", url)
43
+ data = resp.json()
44
+
45
+ status_ = data.get("status")
46
+ self._last_status = status_
47
+
48
+ if status_ == "PENDING":
49
+ # still running
50
+ pass
51
+ elif status_ == "SUCCESS":
52
+ self._finished = True
53
+ self._last_result = data.get("result") or data.get("data")
54
+ elif status_ == "FAILURE":
55
+ self._finished = True
56
+ self._last_result = data.get("error")
57
+ else:
58
+ # Some other custom statuses
59
+ # We'll treat them like "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(f"Task {self.task_id} did not complete within {timeout} seconds.")
74
+ time.sleep(interval)
75
+
76
+ if self._last_status == "SUCCESS":
77
+ return self._last_result
78
+ else:
79
+ raise RuntimeError(f"Task {self.task_id} failed with error: {self._last_result}")
@@ -0,0 +1,8 @@
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
@@ -0,0 +1,41 @@
1
+ Metadata-Version: 2.2
2
+ Name: simile
3
+ Version: 0.1.0
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
@@ -0,0 +1,17 @@
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
@@ -0,0 +1,2 @@
1
+ requests>=2.22.0
2
+ urllib3>=1.26.0
@@ -0,0 +1 @@
1
+ simile