osmosis-ai 0.1.8__tar.gz → 0.1.9__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 osmosis-ai might be problematic. Click here for more details.
- {osmosis_ai-0.1.8 → osmosis_ai-0.1.9}/LICENSE +1 -1
- osmosis_ai-0.1.9/PKG-INFO +143 -0
- osmosis_ai-0.1.9/README.md +107 -0
- osmosis_ai-0.1.9/osmosis_ai/consts.py +3 -0
- osmosis_ai-0.1.9/osmosis_ai/utils.py +62 -0
- osmosis_ai-0.1.9/osmosis_ai.egg-info/SOURCES.txt +10 -0
- osmosis_ai-0.1.9/pyproject.toml +24 -0
- osmosis_ai-0.1.8/.env.sample +0 -24
- osmosis_ai-0.1.8/PKG-INFO +0 -281
- osmosis_ai-0.1.8/README.md +0 -222
- osmosis_ai-0.1.8/osmosis_ai/adapters/__init__.py +0 -9
- osmosis_ai-0.1.8/osmosis_ai/adapters/anthropic.py +0 -502
- osmosis_ai-0.1.8/osmosis_ai/adapters/langchain.py +0 -674
- osmosis_ai-0.1.8/osmosis_ai/adapters/langchain_anthropic.py +0 -338
- osmosis_ai-0.1.8/osmosis_ai/adapters/langchain_openai.py +0 -596
- osmosis_ai-0.1.8/osmosis_ai/adapters/openai.py +0 -900
- osmosis_ai-0.1.8/osmosis_ai/consts.py +0 -17
- osmosis_ai-0.1.8/osmosis_ai/logger.py +0 -77
- osmosis_ai-0.1.8/osmosis_ai/utils.py +0 -120
- osmosis_ai-0.1.8/osmosis_ai.egg-info/SOURCES.txt +0 -20
- osmosis_ai-0.1.8/pyproject.toml +0 -42
- osmosis_ai-0.1.8/setup.py +0 -6
- osmosis_ai-0.1.8/setup_env.sh +0 -29
- {osmosis_ai-0.1.8 → osmosis_ai-0.1.9}/MANIFEST.in +0 -0
- {osmosis_ai-0.1.8 → osmosis_ai-0.1.9}/osmosis_ai/__init__.py +0 -0
- {osmosis_ai-0.1.8 → osmosis_ai-0.1.9}/pytest.ini +0 -0
- {osmosis_ai-0.1.8 → osmosis_ai-0.1.9}/requirements.txt +0 -0
- {osmosis_ai-0.1.8 → osmosis_ai-0.1.9}/setup.cfg +0 -0
- {osmosis_ai-0.1.8 → osmosis_ai-0.1.9}/setup_env.bat +0 -0
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: osmosis-ai
|
|
3
|
+
Version: 0.1.9
|
|
4
|
+
Summary: Adds reward functionality to LLM client libraries
|
|
5
|
+
Author-email: Osmosis AI <jake@osmosis.ai>
|
|
6
|
+
License: MIT License
|
|
7
|
+
|
|
8
|
+
Copyright (c) 2025 Gulp AI
|
|
9
|
+
|
|
10
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
11
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
12
|
+
in the Software without restriction, including without limitation the rights
|
|
13
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
14
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
15
|
+
furnished to do so, subject to the following conditions:
|
|
16
|
+
|
|
17
|
+
The above copyright notice and this permission notice shall be included in all
|
|
18
|
+
copies or substantial portions of the Software.
|
|
19
|
+
|
|
20
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
22
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
23
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
24
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
25
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
26
|
+
SOFTWARE.
|
|
27
|
+
Project-URL: Homepage, https://github.com/Osmosis-AI/osmosis-sdk-python
|
|
28
|
+
Project-URL: Issues, https://github.com/Osmosis-AI/osmosis-sdk-python/issues
|
|
29
|
+
Classifier: Programming Language :: Python :: 3
|
|
30
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
31
|
+
Classifier: Operating System :: OS Independent
|
|
32
|
+
Requires-Python: >=3.6
|
|
33
|
+
Description-Content-Type: text/markdown
|
|
34
|
+
License-File: LICENSE
|
|
35
|
+
Dynamic: license-file
|
|
36
|
+
|
|
37
|
+
# osmosis-ai
|
|
38
|
+
|
|
39
|
+
A Python library that provides reward functionality for LLM applications with strict type enforcement.
|
|
40
|
+
|
|
41
|
+
## Installation
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
pip install osmosis-ai
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
For development:
|
|
48
|
+
```bash
|
|
49
|
+
git clone https://github.com/Osmosis-AI/osmosis-sdk-python
|
|
50
|
+
cd osmosis-sdk-python
|
|
51
|
+
pip install -e .
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Quick Start
|
|
55
|
+
|
|
56
|
+
```python
|
|
57
|
+
from osmosis_ai import osmosis_reward
|
|
58
|
+
|
|
59
|
+
@osmosis_reward
|
|
60
|
+
def simple_reward(solution_str: str, ground_truth: str, extra_info: dict = None) -> float:
|
|
61
|
+
"""Basic exact match reward function."""
|
|
62
|
+
return 1.0 if solution_str.strip() == ground_truth.strip() else 0.0
|
|
63
|
+
|
|
64
|
+
# Use the reward function
|
|
65
|
+
score = simple_reward("hello world", "hello world") # Returns 1.0
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Required Function Signature
|
|
69
|
+
|
|
70
|
+
All functions decorated with `@osmosis_reward` must have exactly this signature:
|
|
71
|
+
|
|
72
|
+
```python
|
|
73
|
+
@osmosis_reward
|
|
74
|
+
def your_function(solution_str: str, ground_truth: str, extra_info: dict = None) -> float:
|
|
75
|
+
# Your reward logic here
|
|
76
|
+
return float_score
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Parameters
|
|
80
|
+
|
|
81
|
+
- **`solution_str: str`** - The solution string to evaluate (required)
|
|
82
|
+
- **`ground_truth: str`** - The correct/expected answer (required)
|
|
83
|
+
- **`extra_info: dict = None`** - Optional dictionary for additional configuration
|
|
84
|
+
|
|
85
|
+
### Return Value
|
|
86
|
+
|
|
87
|
+
- **`-> float`** - Must return a float value representing the reward score
|
|
88
|
+
|
|
89
|
+
The decorator will raise a `TypeError` if the function doesn't match this exact signature or doesn't return a float.
|
|
90
|
+
|
|
91
|
+
## Examples
|
|
92
|
+
|
|
93
|
+
See the [`examples/`](examples/) directory for complete examples:
|
|
94
|
+
|
|
95
|
+
```python
|
|
96
|
+
@osmosis_reward
|
|
97
|
+
def case_insensitive_match(solution_str: str, ground_truth: str, extra_info: dict = None) -> float:
|
|
98
|
+
"""Case-insensitive string matching with partial credit."""
|
|
99
|
+
match = solution_str.lower().strip() == ground_truth.lower().strip()
|
|
100
|
+
|
|
101
|
+
if extra_info and 'partial_credit' in extra_info:
|
|
102
|
+
if not match and extra_info['partial_credit']:
|
|
103
|
+
len_diff = abs(len(solution_str) - len(ground_truth))
|
|
104
|
+
if len_diff <= 2:
|
|
105
|
+
return 0.5
|
|
106
|
+
|
|
107
|
+
return 1.0 if match else 0.0
|
|
108
|
+
|
|
109
|
+
@osmosis_reward
|
|
110
|
+
def numeric_tolerance(solution_str: str, ground_truth: str, extra_info: dict = None) -> float:
|
|
111
|
+
"""Numeric comparison with configurable tolerance."""
|
|
112
|
+
try:
|
|
113
|
+
solution_num = float(solution_str.strip())
|
|
114
|
+
truth_num = float(ground_truth.strip())
|
|
115
|
+
|
|
116
|
+
tolerance = extra_info.get('tolerance', 0.01) if extra_info else 0.01
|
|
117
|
+
return 1.0 if abs(solution_num - truth_num) <= tolerance else 0.0
|
|
118
|
+
except ValueError:
|
|
119
|
+
return 0.0
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## Running Examples
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
python examples/reward_functions.py
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## License
|
|
129
|
+
|
|
130
|
+
MIT License - see [LICENSE](LICENSE) file for details.
|
|
131
|
+
|
|
132
|
+
## Contributing
|
|
133
|
+
|
|
134
|
+
1. Fork the repository
|
|
135
|
+
2. Create a feature branch
|
|
136
|
+
3. Make your changes
|
|
137
|
+
4. Run tests and examples
|
|
138
|
+
5. Submit a pull request
|
|
139
|
+
|
|
140
|
+
## Links
|
|
141
|
+
|
|
142
|
+
- [Homepage](https://github.com/Osmosis-AI/osmosis-sdk-python)
|
|
143
|
+
- [Issues](https://github.com/Osmosis-AI/osmosis-sdk-python/issues)
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# osmosis-ai
|
|
2
|
+
|
|
3
|
+
A Python library that provides reward functionality for LLM applications with strict type enforcement.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install osmosis-ai
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
For development:
|
|
12
|
+
```bash
|
|
13
|
+
git clone https://github.com/Osmosis-AI/osmosis-sdk-python
|
|
14
|
+
cd osmosis-sdk-python
|
|
15
|
+
pip install -e .
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Quick Start
|
|
19
|
+
|
|
20
|
+
```python
|
|
21
|
+
from osmosis_ai import osmosis_reward
|
|
22
|
+
|
|
23
|
+
@osmosis_reward
|
|
24
|
+
def simple_reward(solution_str: str, ground_truth: str, extra_info: dict = None) -> float:
|
|
25
|
+
"""Basic exact match reward function."""
|
|
26
|
+
return 1.0 if solution_str.strip() == ground_truth.strip() else 0.0
|
|
27
|
+
|
|
28
|
+
# Use the reward function
|
|
29
|
+
score = simple_reward("hello world", "hello world") # Returns 1.0
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Required Function Signature
|
|
33
|
+
|
|
34
|
+
All functions decorated with `@osmosis_reward` must have exactly this signature:
|
|
35
|
+
|
|
36
|
+
```python
|
|
37
|
+
@osmosis_reward
|
|
38
|
+
def your_function(solution_str: str, ground_truth: str, extra_info: dict = None) -> float:
|
|
39
|
+
# Your reward logic here
|
|
40
|
+
return float_score
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Parameters
|
|
44
|
+
|
|
45
|
+
- **`solution_str: str`** - The solution string to evaluate (required)
|
|
46
|
+
- **`ground_truth: str`** - The correct/expected answer (required)
|
|
47
|
+
- **`extra_info: dict = None`** - Optional dictionary for additional configuration
|
|
48
|
+
|
|
49
|
+
### Return Value
|
|
50
|
+
|
|
51
|
+
- **`-> float`** - Must return a float value representing the reward score
|
|
52
|
+
|
|
53
|
+
The decorator will raise a `TypeError` if the function doesn't match this exact signature or doesn't return a float.
|
|
54
|
+
|
|
55
|
+
## Examples
|
|
56
|
+
|
|
57
|
+
See the [`examples/`](examples/) directory for complete examples:
|
|
58
|
+
|
|
59
|
+
```python
|
|
60
|
+
@osmosis_reward
|
|
61
|
+
def case_insensitive_match(solution_str: str, ground_truth: str, extra_info: dict = None) -> float:
|
|
62
|
+
"""Case-insensitive string matching with partial credit."""
|
|
63
|
+
match = solution_str.lower().strip() == ground_truth.lower().strip()
|
|
64
|
+
|
|
65
|
+
if extra_info and 'partial_credit' in extra_info:
|
|
66
|
+
if not match and extra_info['partial_credit']:
|
|
67
|
+
len_diff = abs(len(solution_str) - len(ground_truth))
|
|
68
|
+
if len_diff <= 2:
|
|
69
|
+
return 0.5
|
|
70
|
+
|
|
71
|
+
return 1.0 if match else 0.0
|
|
72
|
+
|
|
73
|
+
@osmosis_reward
|
|
74
|
+
def numeric_tolerance(solution_str: str, ground_truth: str, extra_info: dict = None) -> float:
|
|
75
|
+
"""Numeric comparison with configurable tolerance."""
|
|
76
|
+
try:
|
|
77
|
+
solution_num = float(solution_str.strip())
|
|
78
|
+
truth_num = float(ground_truth.strip())
|
|
79
|
+
|
|
80
|
+
tolerance = extra_info.get('tolerance', 0.01) if extra_info else 0.01
|
|
81
|
+
return 1.0 if abs(solution_num - truth_num) <= tolerance else 0.0
|
|
82
|
+
except ValueError:
|
|
83
|
+
return 0.0
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Running Examples
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
python examples/reward_functions.py
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## License
|
|
93
|
+
|
|
94
|
+
MIT License - see [LICENSE](LICENSE) file for details.
|
|
95
|
+
|
|
96
|
+
## Contributing
|
|
97
|
+
|
|
98
|
+
1. Fork the repository
|
|
99
|
+
2. Create a feature branch
|
|
100
|
+
3. Make your changes
|
|
101
|
+
4. Run tests and examples
|
|
102
|
+
5. Submit a pull request
|
|
103
|
+
|
|
104
|
+
## Links
|
|
105
|
+
|
|
106
|
+
- [Homepage](https://github.com/Osmosis-AI/osmosis-sdk-python)
|
|
107
|
+
- [Issues](https://github.com/Osmosis-AI/osmosis-sdk-python/issues)
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
|
|
2
|
+
import functools
|
|
3
|
+
import inspect
|
|
4
|
+
from typing import Callable
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def osmosis_reward(func: Callable) -> Callable:
|
|
8
|
+
"""
|
|
9
|
+
Decorator for reward functions that enforces the signature:
|
|
10
|
+
(solution_str: str, ground_truth: str, extra_info: dict = None) -> float
|
|
11
|
+
|
|
12
|
+
Args:
|
|
13
|
+
func: The reward function to be wrapped
|
|
14
|
+
|
|
15
|
+
Returns:
|
|
16
|
+
The wrapped function
|
|
17
|
+
|
|
18
|
+
Raises:
|
|
19
|
+
TypeError: If the function doesn't have the required signature or doesn't return a float
|
|
20
|
+
|
|
21
|
+
Example:
|
|
22
|
+
@osmosis_reward
|
|
23
|
+
def calculate_reward(solution_str: str, ground_truth: str, extra_info: dict = None) -> float:
|
|
24
|
+
return some_calculation(solution_str, ground_truth)
|
|
25
|
+
"""
|
|
26
|
+
# Validate function signature
|
|
27
|
+
sig = inspect.signature(func)
|
|
28
|
+
params = list(sig.parameters.values())
|
|
29
|
+
|
|
30
|
+
# Check parameter count
|
|
31
|
+
if len(params) < 2 or len(params) > 3:
|
|
32
|
+
raise TypeError(f"Function {func.__name__} must have 2-3 parameters, got {len(params)}")
|
|
33
|
+
|
|
34
|
+
# Check first parameter: solution_str: str
|
|
35
|
+
if params[0].name != 'solution_str':
|
|
36
|
+
raise TypeError(f"First parameter must be named 'solution_str', got '{params[0].name}'")
|
|
37
|
+
if params[0].annotation != str:
|
|
38
|
+
raise TypeError(f"First parameter 'solution_str' must be annotated as str, got {params[0].annotation}")
|
|
39
|
+
|
|
40
|
+
# Check second parameter: ground_truth: str
|
|
41
|
+
if params[1].name != 'ground_truth':
|
|
42
|
+
raise TypeError(f"Second parameter must be named 'ground_truth', got '{params[1].name}'")
|
|
43
|
+
if params[1].annotation != str:
|
|
44
|
+
raise TypeError(f"Second parameter 'ground_truth' must be annotated as str, got {params[1].annotation}")
|
|
45
|
+
|
|
46
|
+
# Check third parameter if present: extra_info: dict = None
|
|
47
|
+
if len(params) == 3:
|
|
48
|
+
if params[2].name != 'extra_info':
|
|
49
|
+
raise TypeError(f"Third parameter must be named 'extra_info', got '{params[2].name}'")
|
|
50
|
+
if params[2].annotation != dict:
|
|
51
|
+
raise TypeError(f"Third parameter 'extra_info' must be annotated as dict, got {params[2].annotation}")
|
|
52
|
+
if params[2].default is inspect.Parameter.empty:
|
|
53
|
+
raise TypeError("Third parameter 'extra_info' must have a default value of None")
|
|
54
|
+
|
|
55
|
+
@functools.wraps(func)
|
|
56
|
+
def wrapper(*args, **kwargs):
|
|
57
|
+
result = func(*args, **kwargs)
|
|
58
|
+
if not isinstance(result, float):
|
|
59
|
+
raise TypeError(f"Function {func.__name__} must return a float, got {type(result).__name__}")
|
|
60
|
+
return result
|
|
61
|
+
|
|
62
|
+
return wrapper
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=42", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "osmosis-ai"
|
|
7
|
+
version = "0.1.9"
|
|
8
|
+
description = "Adds reward functionality to LLM client libraries"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
authors = [
|
|
11
|
+
{name = "Osmosis AI", email = "jake@osmosis.ai"}
|
|
12
|
+
]
|
|
13
|
+
license = {file = "LICENSE"}
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Programming Language :: Python :: 3",
|
|
16
|
+
"License :: OSI Approved :: MIT License",
|
|
17
|
+
"Operating System :: OS Independent",
|
|
18
|
+
]
|
|
19
|
+
requires-python = ">=3.6"
|
|
20
|
+
dependencies = []
|
|
21
|
+
|
|
22
|
+
[project.urls]
|
|
23
|
+
Homepage = "https://github.com/Osmosis-AI/osmosis-sdk-python"
|
|
24
|
+
Issues = "https://github.com/Osmosis-AI/osmosis-sdk-python/issues"
|
osmosis_ai-0.1.8/.env.sample
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
# API Keys for LLM Providers
|
|
2
|
-
# Remove the .sample extension and fill in your actual API keys
|
|
3
|
-
|
|
4
|
-
# Anthropic API Key
|
|
5
|
-
ANTHROPIC_API_KEY=your_anthropic_api_key_here
|
|
6
|
-
|
|
7
|
-
# OpenAI API Key
|
|
8
|
-
OPENAI_API_KEY=your_openai_api_key_here
|
|
9
|
-
|
|
10
|
-
# OSMOSIS API Key (required for logging LLM usage)
|
|
11
|
-
OSMOSIS_API_KEY=your_osmosis_api_key_here
|
|
12
|
-
|
|
13
|
-
# Optional Configuration
|
|
14
|
-
# Uncomment to enable logging to stderr instead of stdout
|
|
15
|
-
# OSMOSIS_USE_STDERR=true
|
|
16
|
-
|
|
17
|
-
# Uncomment to disable pretty printing of JSON
|
|
18
|
-
# OSMOSIS_PRETTY_PRINT=false
|
|
19
|
-
|
|
20
|
-
# Uncomment to change JSON indentation level
|
|
21
|
-
# OSMOSIS_INDENT=4
|
|
22
|
-
|
|
23
|
-
# Uncomment to disable response printing (requests will still be printed)
|
|
24
|
-
# OSMOSIS_PRINT_RESPONSES=false
|
osmosis_ai-0.1.8/PKG-INFO
DELETED
|
@@ -1,281 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: osmosis-ai
|
|
3
|
-
Version: 0.1.8
|
|
4
|
-
Summary: Monkey patches LLM client libraries to print all prompts and responses
|
|
5
|
-
Author-email: Gulp AI <jake@gulp.ai>
|
|
6
|
-
License: MIT License
|
|
7
|
-
|
|
8
|
-
Copyright (c) 2024 Gulp AI
|
|
9
|
-
|
|
10
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
11
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
12
|
-
in the Software without restriction, including without limitation the rights
|
|
13
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
14
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
15
|
-
furnished to do so, subject to the following conditions:
|
|
16
|
-
|
|
17
|
-
The above copyright notice and this permission notice shall be included in all
|
|
18
|
-
copies or substantial portions of the Software.
|
|
19
|
-
|
|
20
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
22
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
23
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
24
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
25
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
26
|
-
SOFTWARE.
|
|
27
|
-
Project-URL: Homepage, https://github.com/Gulp-AI/osmosis-sdk-python
|
|
28
|
-
Project-URL: Issues, https://github.com/Gulp-AI/osmosis-sdk-python/issues
|
|
29
|
-
Classifier: Programming Language :: Python :: 3
|
|
30
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
31
|
-
Classifier: Operating System :: OS Independent
|
|
32
|
-
Requires-Python: >=3.6
|
|
33
|
-
Description-Content-Type: text/markdown
|
|
34
|
-
License-File: LICENSE
|
|
35
|
-
Requires-Dist: python-dotenv>=0.19.0
|
|
36
|
-
Requires-Dist: requests>=2.25.0
|
|
37
|
-
Requires-Dist: xxhash>=3.4.1
|
|
38
|
-
Provides-Extra: anthropic
|
|
39
|
-
Requires-Dist: anthropic>=0.5.0; extra == "anthropic"
|
|
40
|
-
Provides-Extra: openai
|
|
41
|
-
Requires-Dist: openai>=0.27.0; extra == "openai"
|
|
42
|
-
Provides-Extra: langchain
|
|
43
|
-
Requires-Dist: langchain>=0.0.200; extra == "langchain"
|
|
44
|
-
Provides-Extra: langchain-openai
|
|
45
|
-
Requires-Dist: langchain>=0.0.200; extra == "langchain-openai"
|
|
46
|
-
Requires-Dist: langchain-openai>=0.0.200; extra == "langchain-openai"
|
|
47
|
-
Requires-Dist: openai>=0.27.0; extra == "langchain-openai"
|
|
48
|
-
Provides-Extra: langchain-anthropic
|
|
49
|
-
Requires-Dist: langchain>=0.0.200; extra == "langchain-anthropic"
|
|
50
|
-
Requires-Dist: langchain-anthropic>=0.0.200; extra == "langchain-anthropic"
|
|
51
|
-
Requires-Dist: anthropic>=0.5.0; extra == "langchain-anthropic"
|
|
52
|
-
Provides-Extra: all
|
|
53
|
-
Requires-Dist: anthropic>=0.5.0; extra == "all"
|
|
54
|
-
Requires-Dist: openai>=0.27.0; extra == "all"
|
|
55
|
-
Requires-Dist: langchain>=0.0.200; extra == "all"
|
|
56
|
-
Requires-Dist: langchain-openai>=0.0.200; extra == "all"
|
|
57
|
-
Requires-Dist: langchain-anthropic>=0.0.200; extra == "all"
|
|
58
|
-
Dynamic: license-file
|
|
59
|
-
|
|
60
|
-
[](https://github.com/Gulp-AI/osmosis-sdk-python/actions/workflows/test.yml)
|
|
61
|
-
|
|
62
|
-
# Osmosis
|
|
63
|
-
|
|
64
|
-
A Python library that monkey patches LLM client libraries to send all prompts and responses to the Osmosis API for logging and monitoring.
|
|
65
|
-
|
|
66
|
-
## Supported Libraries
|
|
67
|
-
|
|
68
|
-
- **Anthropic**: Logs all Claude API requests and responses (both sync and async clients)
|
|
69
|
-
- **OpenAI**: Logs all OpenAI API requests and responses (supports v1 and v2 API versions, both sync and async clients)
|
|
70
|
-
- **LangChain**: Currently supports prompt template logging (LLM and ChatModel support varies by LangChain version)
|
|
71
|
-
|
|
72
|
-
## Installation
|
|
73
|
-
|
|
74
|
-
[pypi](https://pypi.org/project/osmosis-ai/)
|
|
75
|
-
|
|
76
|
-
```bash
|
|
77
|
-
# Basic installation with minimal dependencies
|
|
78
|
-
pip install osmosis-ai
|
|
79
|
-
|
|
80
|
-
# Install with specific provider support
|
|
81
|
-
pip install "osmosis-ai[openai]" # Only OpenAI support
|
|
82
|
-
pip install "osmosis-ai[anthropic]" # Only Anthropic support
|
|
83
|
-
|
|
84
|
-
# Install with LangChain support
|
|
85
|
-
pip install "osmosis-ai[langchain]" # Base LangChain support
|
|
86
|
-
pip install "osmosis-ai[langchain-openai]" # LangChain + OpenAI support
|
|
87
|
-
pip install "osmosis-ai[langchain-anthropic]" # LangChain + Anthropic support
|
|
88
|
-
|
|
89
|
-
# Install with all dependencies
|
|
90
|
-
pip install "osmosis-ai[all]"
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
Or install from source:
|
|
94
|
-
|
|
95
|
-
```bash
|
|
96
|
-
git clone https://github.com/your-username/osmosis-sdk-python.git
|
|
97
|
-
cd osmosis-ai
|
|
98
|
-
pip install -e .
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
For development, you can install all dependencies using:
|
|
102
|
-
|
|
103
|
-
```bash
|
|
104
|
-
pip install -r requirements.txt
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
## Environment Setup
|
|
108
|
-
|
|
109
|
-
osmosisrequires a OSMOSIS API key to log LLM usage. Create a `.env` file in your project directory:
|
|
110
|
-
|
|
111
|
-
```bash
|
|
112
|
-
# Copy the sample .env file
|
|
113
|
-
cp .env.sample .env
|
|
114
|
-
|
|
115
|
-
# Edit the .env file with your API keys
|
|
116
|
-
```
|
|
117
|
-
|
|
118
|
-
Edit the `.env` file to add your API keys:
|
|
119
|
-
|
|
120
|
-
```
|
|
121
|
-
# Required for logging
|
|
122
|
-
OSMOSIS_API_KEY=your_osmosis_api_key_here
|
|
123
|
-
|
|
124
|
-
# Optional: Only needed if you're using these services
|
|
125
|
-
ANTHROPIC_API_KEY=your_anthropic_key_here
|
|
126
|
-
OPENAI_API_KEY=your_openai_key_here
|
|
127
|
-
```
|
|
128
|
-
|
|
129
|
-
## Usage
|
|
130
|
-
|
|
131
|
-
First, import and initialize osmosiswith your OSMOSIS API key:
|
|
132
|
-
|
|
133
|
-
```python
|
|
134
|
-
import os
|
|
135
|
-
import osmosis_ai
|
|
136
|
-
|
|
137
|
-
# Initialize with your OSMOSIS API key
|
|
138
|
-
osmosis_ai.init("your-osmosis-api-key")
|
|
139
|
-
|
|
140
|
-
# Or load from environment variable
|
|
141
|
-
osmosis_api_key = os.environ.get("OSMOSIS_API_KEY")
|
|
142
|
-
osmosis_ai.init(osmosis_api_key)
|
|
143
|
-
```
|
|
144
|
-
|
|
145
|
-
Once you import `osmosis_ai` and initialize it, the library automatically patches the supported LLM clients. You can then use your LLM clients normally, and all API calls will be logged to OSMOSIS:
|
|
146
|
-
|
|
147
|
-
### Anthropic Example
|
|
148
|
-
|
|
149
|
-
```python
|
|
150
|
-
# Import osmosis_ai first and initialize it
|
|
151
|
-
import osmosis_ai
|
|
152
|
-
osmosis_ai.init(os.environ.get("OSMOSIS_API_KEY"))
|
|
153
|
-
|
|
154
|
-
# Then import and use Anthropic as normal
|
|
155
|
-
from anthropic import Anthropic
|
|
156
|
-
|
|
157
|
-
# Create and use the Anthropic client as usual - it's already patched
|
|
158
|
-
client = Anthropic(api_key=os.environ.get("ANTHROPIC_API_KEY"))
|
|
159
|
-
|
|
160
|
-
# All API calls will now be logged to OSMOSIS automatically
|
|
161
|
-
response = client.messages.create(
|
|
162
|
-
model="claude-3-haiku-20240307",
|
|
163
|
-
max_tokens=1000,
|
|
164
|
-
messages=[
|
|
165
|
-
{"role": "user", "content": "Hello, Claude!"}
|
|
166
|
-
]
|
|
167
|
-
)
|
|
168
|
-
|
|
169
|
-
# Async client is also supported and automatically patched
|
|
170
|
-
from anthropic import AsyncAnthropic
|
|
171
|
-
import asyncio
|
|
172
|
-
|
|
173
|
-
async def call_claude_async():
|
|
174
|
-
async_client = AsyncAnthropic(api_key=os.environ.get("ANTHROPIC_API_KEY"))
|
|
175
|
-
response = await async_client.messages.create(
|
|
176
|
-
model="claude-3-haiku-20240307",
|
|
177
|
-
max_tokens=1000,
|
|
178
|
-
messages=[
|
|
179
|
-
{"role": "user", "content": "Hello, async Claude!"}
|
|
180
|
-
]
|
|
181
|
-
)
|
|
182
|
-
return response
|
|
183
|
-
|
|
184
|
-
# All async API calls will be logged to OSMOSIS as well
|
|
185
|
-
asyncio.run(call_claude_async())
|
|
186
|
-
```
|
|
187
|
-
|
|
188
|
-
### OpenAI Example
|
|
189
|
-
|
|
190
|
-
```python
|
|
191
|
-
# Import osmosis_ai first and initialize it
|
|
192
|
-
import osmosis_ai
|
|
193
|
-
osmosis_ai.init(os.environ.get("OSMOSIS_API_KEY"))
|
|
194
|
-
|
|
195
|
-
# Then import and use OpenAI as normal
|
|
196
|
-
from openai import OpenAI
|
|
197
|
-
|
|
198
|
-
# Create and use the OpenAI client as usual - it's already patched
|
|
199
|
-
client = OpenAI(api_key=os.environ.get("OPENAI_API_KEY"))
|
|
200
|
-
|
|
201
|
-
# All API calls will now be logged to OSMOSIS automatically
|
|
202
|
-
response = client.chat.completions.create(
|
|
203
|
-
model="gpt-4o-mini",
|
|
204
|
-
max_tokens=150,
|
|
205
|
-
messages=[
|
|
206
|
-
{"role": "user", "content": "Hello, GPT!"}
|
|
207
|
-
]
|
|
208
|
-
)
|
|
209
|
-
|
|
210
|
-
# Async client is also supported and automatically patched
|
|
211
|
-
from openai import AsyncOpenAI
|
|
212
|
-
import asyncio
|
|
213
|
-
|
|
214
|
-
async def call_openai_async():
|
|
215
|
-
async_client = AsyncOpenAI(api_key=os.environ.get("OPENAI_API_KEY"))
|
|
216
|
-
response = await async_client.chat.completions.create(
|
|
217
|
-
model="gpt-4o-mini",
|
|
218
|
-
max_tokens=150,
|
|
219
|
-
messages=[
|
|
220
|
-
{"role": "user", "content": "Hello, async GPT!"}
|
|
221
|
-
]
|
|
222
|
-
)
|
|
223
|
-
return response
|
|
224
|
-
|
|
225
|
-
# All async API calls will be logged to OSMOSIS as well
|
|
226
|
-
asyncio.run(call_openai_async())
|
|
227
|
-
```
|
|
228
|
-
|
|
229
|
-
### LangChain Example
|
|
230
|
-
|
|
231
|
-
```python
|
|
232
|
-
# Import osmosis_ai first and initialize it
|
|
233
|
-
import osmosis_ai
|
|
234
|
-
osmosis_ai.init(os.environ.get("OSMOSIS_API_KEY"))
|
|
235
|
-
|
|
236
|
-
# Then use LangChain as normal
|
|
237
|
-
from langchain_core.prompts import PromptTemplate
|
|
238
|
-
|
|
239
|
-
# Use LangChain prompt templates as usual
|
|
240
|
-
template = PromptTemplate(
|
|
241
|
-
input_variables=["topic"],
|
|
242
|
-
template="Write a short paragraph about {topic}."
|
|
243
|
-
)
|
|
244
|
-
|
|
245
|
-
# Formatting the prompt will be logged to OSMOSIS automatically
|
|
246
|
-
formatted_prompt = template.format(topic="artificial intelligence")
|
|
247
|
-
print(f"Formatted prompt: {formatted_prompt}")
|
|
248
|
-
|
|
249
|
-
# Multiple prompt templates are also captured
|
|
250
|
-
template2 = PromptTemplate(
|
|
251
|
-
input_variables=["name", "profession"],
|
|
252
|
-
template="My name is {name} and I work as a {profession}."
|
|
253
|
-
)
|
|
254
|
-
formatted_prompt2 = template2.format(name="Alice", profession="data scientist")
|
|
255
|
-
print(f"Formatted prompt 2: {formatted_prompt2}")
|
|
256
|
-
```
|
|
257
|
-
|
|
258
|
-
## Configuration
|
|
259
|
-
|
|
260
|
-
You can configure the behavior of the library by modifying the following variables:
|
|
261
|
-
|
|
262
|
-
```python
|
|
263
|
-
import osmosis_ai
|
|
264
|
-
|
|
265
|
-
# Disable logging to OSMOSIS (default: True)
|
|
266
|
-
osmosis_ai.enabled = False
|
|
267
|
-
```
|
|
268
|
-
|
|
269
|
-
## How it Works
|
|
270
|
-
|
|
271
|
-
This library uses monkey patching to override the LLM clients' methods that make API calls. When you import the `osmosis_ai` module, it automatically patches the supported LLM client libraries. When methods are called on these clients, the library intercepts the calls and sends the request parameters and response data to the OSMOSIS API for logging and monitoring.
|
|
272
|
-
|
|
273
|
-
The data sent to OSMOSIS includes:
|
|
274
|
-
- Timestamp (UTC)
|
|
275
|
-
- Request parameters
|
|
276
|
-
- Response data
|
|
277
|
-
- HTTP status code
|
|
278
|
-
|
|
279
|
-
## License
|
|
280
|
-
|
|
281
|
-
MIT
|