chinf 0.0.1__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.
- chinf-0.0.1/LICENSE +21 -0
- chinf-0.0.1/PKG-INFO +161 -0
- chinf-0.0.1/README.md +145 -0
- chinf-0.0.1/pyproject.toml +27 -0
- chinf-0.0.1/setup.cfg +4 -0
- chinf-0.0.1/src/chinf/__init__.py +34 -0
- chinf-0.0.1/src/chinf/chat.py +191 -0
- chinf-0.0.1/src/chinf/completion.py +59 -0
- chinf-0.0.1/src/chinf/messages.py +96 -0
- chinf-0.0.1/src/chinf/resp_simplified.py +41 -0
- chinf-0.0.1/src/chinf/responses.py +85 -0
- chinf-0.0.1/src/chinf/utils.py +131 -0
- chinf-0.0.1/src/chinf.egg-info/PKG-INFO +161 -0
- chinf-0.0.1/src/chinf.egg-info/SOURCES.txt +15 -0
- chinf-0.0.1/src/chinf.egg-info/dependency_links.txt +1 -0
- chinf-0.0.1/src/chinf.egg-info/requires.txt +1 -0
- chinf-0.0.1/src/chinf.egg-info/top_level.txt +1 -0
chinf-0.0.1/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Alexander Fedotov
|
|
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.
|
chinf-0.0.1/PKG-INFO
ADDED
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: chinf
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: Package description
|
|
5
|
+
Author-email: Machina Ratiocinatrix <machina.ratio@gmail.com>, Alexander Fedotov <alex.fedotov@aol.com>
|
|
6
|
+
Project-URL: Homepage, https://github.com/alxfed/chinf
|
|
7
|
+
Keywords: chinf
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Requires-Python: >=3.10
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
License-File: LICENSE
|
|
14
|
+
Requires-Dist: pyyaml==6.0.3
|
|
15
|
+
Dynamic: license-file
|
|
16
|
+
|
|
17
|
+
# Chinf
|
|
18
|
+
API calls to Cheap Inference without dependencies.
|
|
19
|
+
<pre>
|
|
20
|
+
pip install chinf
|
|
21
|
+
</pre>
|
|
22
|
+
Then:
|
|
23
|
+
```Python
|
|
24
|
+
# Python
|
|
25
|
+
from yaml import safe_load as yl
|
|
26
|
+
from chinf.chat import chat_complete as cc
|
|
27
|
+
|
|
28
|
+
kwargs = """ # this is a string in YAML format
|
|
29
|
+
max_tokens: 32000
|
|
30
|
+
stop_sequences:
|
|
31
|
+
- STOP
|
|
32
|
+
- "\nTitle"
|
|
33
|
+
temperature: 1.0
|
|
34
|
+
top_k: 10
|
|
35
|
+
top_p: 0.5
|
|
36
|
+
reasoning_effort: high
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
instruction = 'You are a helpful assistant. Do not use markdown or lists in your responses.'
|
|
40
|
+
|
|
41
|
+
weather_tool = """ # YAML definition of a function (old format)
|
|
42
|
+
type: function
|
|
43
|
+
function:
|
|
44
|
+
name: get_weather
|
|
45
|
+
description: Determine weather in a location
|
|
46
|
+
parameters:
|
|
47
|
+
type: object
|
|
48
|
+
properties:
|
|
49
|
+
location:
|
|
50
|
+
type: string
|
|
51
|
+
description: The city and state, e.g. San Francisco, CA
|
|
52
|
+
additionalProperties: false
|
|
53
|
+
required:
|
|
54
|
+
- location
|
|
55
|
+
"""
|
|
56
|
+
|
|
57
|
+
tools = [yl(weather_tool)]
|
|
58
|
+
|
|
59
|
+
msgs = [{'role': 'user', 'content': 'What is the weather in Chicago, IL and Paris, France?'}]
|
|
60
|
+
|
|
61
|
+
thoughts, text = cc(
|
|
62
|
+
messages=msgs,
|
|
63
|
+
instructions=instruction,
|
|
64
|
+
tools=tools,
|
|
65
|
+
**yl(kwargs)
|
|
66
|
+
)
|
|
67
|
+
```
|
|
68
|
+
or
|
|
69
|
+
```Python
|
|
70
|
+
from yaml import safe_load as yl
|
|
71
|
+
from chinf.messages import message
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
kwargs = """ # this is a string in YAML format
|
|
75
|
+
max_tokens: 32000
|
|
76
|
+
stop_sequences:
|
|
77
|
+
- STOP
|
|
78
|
+
- "\nTitle"
|
|
79
|
+
temperature: 1.0
|
|
80
|
+
top_k: 10
|
|
81
|
+
top_p: 0.5
|
|
82
|
+
thinking:
|
|
83
|
+
type: enabled
|
|
84
|
+
budget_tokens: 24576
|
|
85
|
+
display: summarized
|
|
86
|
+
tool_choice:
|
|
87
|
+
type: auto
|
|
88
|
+
disable_parallel_tool_use: false
|
|
89
|
+
"""
|
|
90
|
+
|
|
91
|
+
instruction = 'You are a helpful assistant. Do not use markdown or lists in your responses.'
|
|
92
|
+
|
|
93
|
+
get_weather_tool_str = """ # YAML definition of a function
|
|
94
|
+
name: get_weather
|
|
95
|
+
description: Determine weather in a location
|
|
96
|
+
input_schema:
|
|
97
|
+
type: object
|
|
98
|
+
properties:
|
|
99
|
+
location:
|
|
100
|
+
type: string
|
|
101
|
+
description: The city and state, e.g. San Francisco, CA
|
|
102
|
+
additionalProperties: true
|
|
103
|
+
required:
|
|
104
|
+
- location
|
|
105
|
+
"""
|
|
106
|
+
|
|
107
|
+
tools = [yl(get_weather_tool_str)]
|
|
108
|
+
|
|
109
|
+
msg = [{'role': 'user', 'content': 'What is the weather in Chicago, IL and Paris, France?'}]
|
|
110
|
+
|
|
111
|
+
thoughts, text = message(
|
|
112
|
+
messages=msg,
|
|
113
|
+
instructions=instruction,
|
|
114
|
+
tools=tools,
|
|
115
|
+
**yl(kwargs)
|
|
116
|
+
)
|
|
117
|
+
```
|
|
118
|
+
or
|
|
119
|
+
|
|
120
|
+
```Python
|
|
121
|
+
from yaml import safe_load as yl
|
|
122
|
+
from chinf.responses import respond
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
kwargs = """ # this is a string in YAML format
|
|
126
|
+
max_tokens: 64000
|
|
127
|
+
temperature: 1.0
|
|
128
|
+
"""
|
|
129
|
+
|
|
130
|
+
msgs = [{'role': 'user', 'content': 'What is the weather in Chicago, IL and Paris, France?'}]
|
|
131
|
+
|
|
132
|
+
weather_tool = """ # YAML definition of a function (new format)
|
|
133
|
+
type: function
|
|
134
|
+
name: get_weather
|
|
135
|
+
description: Determine weather in a location
|
|
136
|
+
parameters:
|
|
137
|
+
type: object
|
|
138
|
+
properties:
|
|
139
|
+
location:
|
|
140
|
+
type: string
|
|
141
|
+
description: The city and state, e.g. San Francisco, CA
|
|
142
|
+
additionalProperties: false
|
|
143
|
+
required:
|
|
144
|
+
- location
|
|
145
|
+
"""
|
|
146
|
+
|
|
147
|
+
tools = [yl(weather_tool)]
|
|
148
|
+
|
|
149
|
+
instructions = """
|
|
150
|
+
You are a helpful assistant.
|
|
151
|
+
Rubric: respond in plain text without any markdown, emphasis or lists;
|
|
152
|
+
all paragraphs except the first one should begin with a newline and a tab.
|
|
153
|
+
"""
|
|
154
|
+
|
|
155
|
+
thougts, text = respond(
|
|
156
|
+
messages=msgs,
|
|
157
|
+
instructions=instructions,
|
|
158
|
+
tools=tools,
|
|
159
|
+
**yl(kwargs)
|
|
160
|
+
)
|
|
161
|
+
```
|
chinf-0.0.1/README.md
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# Chinf
|
|
2
|
+
API calls to Cheap Inference without dependencies.
|
|
3
|
+
<pre>
|
|
4
|
+
pip install chinf
|
|
5
|
+
</pre>
|
|
6
|
+
Then:
|
|
7
|
+
```Python
|
|
8
|
+
# Python
|
|
9
|
+
from yaml import safe_load as yl
|
|
10
|
+
from chinf.chat import chat_complete as cc
|
|
11
|
+
|
|
12
|
+
kwargs = """ # this is a string in YAML format
|
|
13
|
+
max_tokens: 32000
|
|
14
|
+
stop_sequences:
|
|
15
|
+
- STOP
|
|
16
|
+
- "\nTitle"
|
|
17
|
+
temperature: 1.0
|
|
18
|
+
top_k: 10
|
|
19
|
+
top_p: 0.5
|
|
20
|
+
reasoning_effort: high
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
instruction = 'You are a helpful assistant. Do not use markdown or lists in your responses.'
|
|
24
|
+
|
|
25
|
+
weather_tool = """ # YAML definition of a function (old format)
|
|
26
|
+
type: function
|
|
27
|
+
function:
|
|
28
|
+
name: get_weather
|
|
29
|
+
description: Determine weather in a location
|
|
30
|
+
parameters:
|
|
31
|
+
type: object
|
|
32
|
+
properties:
|
|
33
|
+
location:
|
|
34
|
+
type: string
|
|
35
|
+
description: The city and state, e.g. San Francisco, CA
|
|
36
|
+
additionalProperties: false
|
|
37
|
+
required:
|
|
38
|
+
- location
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
tools = [yl(weather_tool)]
|
|
42
|
+
|
|
43
|
+
msgs = [{'role': 'user', 'content': 'What is the weather in Chicago, IL and Paris, France?'}]
|
|
44
|
+
|
|
45
|
+
thoughts, text = cc(
|
|
46
|
+
messages=msgs,
|
|
47
|
+
instructions=instruction,
|
|
48
|
+
tools=tools,
|
|
49
|
+
**yl(kwargs)
|
|
50
|
+
)
|
|
51
|
+
```
|
|
52
|
+
or
|
|
53
|
+
```Python
|
|
54
|
+
from yaml import safe_load as yl
|
|
55
|
+
from chinf.messages import message
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
kwargs = """ # this is a string in YAML format
|
|
59
|
+
max_tokens: 32000
|
|
60
|
+
stop_sequences:
|
|
61
|
+
- STOP
|
|
62
|
+
- "\nTitle"
|
|
63
|
+
temperature: 1.0
|
|
64
|
+
top_k: 10
|
|
65
|
+
top_p: 0.5
|
|
66
|
+
thinking:
|
|
67
|
+
type: enabled
|
|
68
|
+
budget_tokens: 24576
|
|
69
|
+
display: summarized
|
|
70
|
+
tool_choice:
|
|
71
|
+
type: auto
|
|
72
|
+
disable_parallel_tool_use: false
|
|
73
|
+
"""
|
|
74
|
+
|
|
75
|
+
instruction = 'You are a helpful assistant. Do not use markdown or lists in your responses.'
|
|
76
|
+
|
|
77
|
+
get_weather_tool_str = """ # YAML definition of a function
|
|
78
|
+
name: get_weather
|
|
79
|
+
description: Determine weather in a location
|
|
80
|
+
input_schema:
|
|
81
|
+
type: object
|
|
82
|
+
properties:
|
|
83
|
+
location:
|
|
84
|
+
type: string
|
|
85
|
+
description: The city and state, e.g. San Francisco, CA
|
|
86
|
+
additionalProperties: true
|
|
87
|
+
required:
|
|
88
|
+
- location
|
|
89
|
+
"""
|
|
90
|
+
|
|
91
|
+
tools = [yl(get_weather_tool_str)]
|
|
92
|
+
|
|
93
|
+
msg = [{'role': 'user', 'content': 'What is the weather in Chicago, IL and Paris, France?'}]
|
|
94
|
+
|
|
95
|
+
thoughts, text = message(
|
|
96
|
+
messages=msg,
|
|
97
|
+
instructions=instruction,
|
|
98
|
+
tools=tools,
|
|
99
|
+
**yl(kwargs)
|
|
100
|
+
)
|
|
101
|
+
```
|
|
102
|
+
or
|
|
103
|
+
|
|
104
|
+
```Python
|
|
105
|
+
from yaml import safe_load as yl
|
|
106
|
+
from chinf.responses import respond
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
kwargs = """ # this is a string in YAML format
|
|
110
|
+
max_tokens: 64000
|
|
111
|
+
temperature: 1.0
|
|
112
|
+
"""
|
|
113
|
+
|
|
114
|
+
msgs = [{'role': 'user', 'content': 'What is the weather in Chicago, IL and Paris, France?'}]
|
|
115
|
+
|
|
116
|
+
weather_tool = """ # YAML definition of a function (new format)
|
|
117
|
+
type: function
|
|
118
|
+
name: get_weather
|
|
119
|
+
description: Determine weather in a location
|
|
120
|
+
parameters:
|
|
121
|
+
type: object
|
|
122
|
+
properties:
|
|
123
|
+
location:
|
|
124
|
+
type: string
|
|
125
|
+
description: The city and state, e.g. San Francisco, CA
|
|
126
|
+
additionalProperties: false
|
|
127
|
+
required:
|
|
128
|
+
- location
|
|
129
|
+
"""
|
|
130
|
+
|
|
131
|
+
tools = [yl(weather_tool)]
|
|
132
|
+
|
|
133
|
+
instructions = """
|
|
134
|
+
You are a helpful assistant.
|
|
135
|
+
Rubric: respond in plain text without any markdown, emphasis or lists;
|
|
136
|
+
all paragraphs except the first one should begin with a newline and a tab.
|
|
137
|
+
"""
|
|
138
|
+
|
|
139
|
+
thougts, text = respond(
|
|
140
|
+
messages=msgs,
|
|
141
|
+
instructions=instructions,
|
|
142
|
+
tools=tools,
|
|
143
|
+
**yl(kwargs)
|
|
144
|
+
)
|
|
145
|
+
```
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=67.0"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
[project]
|
|
5
|
+
name = "chinf"
|
|
6
|
+
version = "0.0.1"
|
|
7
|
+
authors = [
|
|
8
|
+
{name="Machina Ratiocinatrix", email="machina.ratio@gmail.com"},
|
|
9
|
+
{name="Alexander Fedotov", email="alex.fedotov@aol.com"}
|
|
10
|
+
]
|
|
11
|
+
description = "Package description"
|
|
12
|
+
readme = "README.md"
|
|
13
|
+
requires-python = ">=3.10"
|
|
14
|
+
classifiers=[
|
|
15
|
+
"Programming Language :: Python :: 3",
|
|
16
|
+
"License :: OSI Approved :: MIT License",
|
|
17
|
+
"Operating System :: OS Independent",
|
|
18
|
+
]
|
|
19
|
+
|
|
20
|
+
keywords = ["chinf"]
|
|
21
|
+
|
|
22
|
+
dependencies = [
|
|
23
|
+
"pyyaml == 6.0.3"
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
[project.urls]
|
|
27
|
+
"Homepage" = "https://github.com/alxfed/chinf"
|
chinf-0.0.1/setup.cfg
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# Python
|
|
3
|
+
|
|
4
|
+
"""Copyright (c) Alexander Fedotov.
|
|
5
|
+
This source code is licensed under the license found in the
|
|
6
|
+
LICENSE file in the root directory of this source tree.
|
|
7
|
+
"""
|
|
8
|
+
from .utils import (query,
|
|
9
|
+
headers,
|
|
10
|
+
get_function,
|
|
11
|
+
get_func_args,
|
|
12
|
+
call_function,
|
|
13
|
+
decode_output,
|
|
14
|
+
default_model)
|
|
15
|
+
from .chat import chat_complete
|
|
16
|
+
from .completion import complete
|
|
17
|
+
from .responses import respond
|
|
18
|
+
from .messages import message
|
|
19
|
+
|
|
20
|
+
__all__ = [
|
|
21
|
+
"chat_complete",
|
|
22
|
+
"complete",
|
|
23
|
+
"respond",
|
|
24
|
+
"message",
|
|
25
|
+
# The API calling
|
|
26
|
+
"query",
|
|
27
|
+
"headers",
|
|
28
|
+
# and all the function calling stuff
|
|
29
|
+
"get_function",
|
|
30
|
+
"get_func_args",
|
|
31
|
+
"call_function",
|
|
32
|
+
"decode_output",
|
|
33
|
+
"default_model"
|
|
34
|
+
]
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# Python
|
|
3
|
+
|
|
4
|
+
"""Copyright (c) Alexander Fedotov.
|
|
5
|
+
This source code is licensed under the license found in the
|
|
6
|
+
LICENSE file in the root directory of this source tree.
|
|
7
|
+
"""
|
|
8
|
+
import json
|
|
9
|
+
from os import environ
|
|
10
|
+
from .utils import (query,
|
|
11
|
+
default_model,
|
|
12
|
+
get_function,
|
|
13
|
+
get_func_args,
|
|
14
|
+
call_function)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def get_weather(location):
|
|
18
|
+
print(f"Executing weather tool for location: {location}")
|
|
19
|
+
return {"temperature": "72F", "condition": "Sunny"}
|
|
20
|
+
#
|
|
21
|
+
#
|
|
22
|
+
# def query(payload):
|
|
23
|
+
# # Convert data dictionary to JSON and encode it to bytes
|
|
24
|
+
# data_bytes = json.dumps(payload).encode('utf-8')
|
|
25
|
+
# # Create the Request object
|
|
26
|
+
# req = urllib.request.Request(
|
|
27
|
+
# f'{api_base}/chat/completions',
|
|
28
|
+
# data=data_bytes,
|
|
29
|
+
# headers=headers,
|
|
30
|
+
# method="POST")
|
|
31
|
+
# # Try to query
|
|
32
|
+
# try:
|
|
33
|
+
# # Execute the request
|
|
34
|
+
# with urllib.request.urlopen(req, timeout=3000) as response:
|
|
35
|
+
# response_data = response.read().decode('utf-8')
|
|
36
|
+
# output = json.loads(response_data)
|
|
37
|
+
# return output
|
|
38
|
+
#
|
|
39
|
+
# except urllib.error.HTTPError as e:
|
|
40
|
+
# # Handle HTTP errors (e.g., 401 Unauthorized, 400 Bad Request)
|
|
41
|
+
# error_info = e.read().decode('utf-8', errors='ignore')
|
|
42
|
+
# print(f"HTTP Error {e.code}: {e.reason}")
|
|
43
|
+
# print(f"Error Details: {error_info}")
|
|
44
|
+
# return {}
|
|
45
|
+
#
|
|
46
|
+
# except urllib.error.URLError as e:
|
|
47
|
+
# # Handle network/connection errors
|
|
48
|
+
# print(f"Failed to reach the server: {e.reason}")
|
|
49
|
+
# return {}
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def chat_complete(messages=None, instructions=None, tools=None, **kwargs):
|
|
53
|
+
""" All parameters should be in kwargs, but they are optional
|
|
54
|
+
"""
|
|
55
|
+
# Receive the instruction
|
|
56
|
+
instruction = kwargs.get('system_instruction', instructions)
|
|
57
|
+
first_message = [dict(role='system', content=instruction)] if instruction else []
|
|
58
|
+
|
|
59
|
+
# add contents and user text to the first (instruction) message
|
|
60
|
+
first_message.extend(messages)
|
|
61
|
+
instruction_and_contents = first_message
|
|
62
|
+
|
|
63
|
+
# Define the initial payload
|
|
64
|
+
payload = {
|
|
65
|
+
"model": kwargs.get("model", default_model),
|
|
66
|
+
"messages": instruction_and_contents,
|
|
67
|
+
"max_tokens": kwargs.get("max_tokens", 132000),
|
|
68
|
+
"reasoning_effort": "max",
|
|
69
|
+
}
|
|
70
|
+
# Tools if there are some
|
|
71
|
+
if tools:
|
|
72
|
+
payload['tools'] = tools
|
|
73
|
+
payload['tool_choice'] = 'auto'
|
|
74
|
+
|
|
75
|
+
while True:
|
|
76
|
+
# Query the API
|
|
77
|
+
result = query(payload, '/chat/completions')
|
|
78
|
+
message = result['choices'][0]['message']
|
|
79
|
+
instruction_and_contents.append(message)
|
|
80
|
+
thoughts = message['reasoning_content']
|
|
81
|
+
text = message['content']
|
|
82
|
+
function_calls = message.get('tool_calls', [])
|
|
83
|
+
|
|
84
|
+
if function_calls:
|
|
85
|
+
for function_call in function_calls:
|
|
86
|
+
call_id = function_call.get('id')
|
|
87
|
+
func = function_call.get('function')
|
|
88
|
+
func_name = func.get('name')
|
|
89
|
+
func_args_str = func.get('arguments', '{}')
|
|
90
|
+
|
|
91
|
+
try:
|
|
92
|
+
if isinstance(func_args_str, str):
|
|
93
|
+
func_args = json.loads(func_args_str)
|
|
94
|
+
else:
|
|
95
|
+
func_args = func_args_str
|
|
96
|
+
except Exception as e:
|
|
97
|
+
func_args = {}
|
|
98
|
+
print(f"Error parsing tool arguments for {func_name}: {e}")
|
|
99
|
+
|
|
100
|
+
# Look up tool by name in globals and caller frames
|
|
101
|
+
func = globals().get(func_name)
|
|
102
|
+
# if not func:
|
|
103
|
+
# import inspect
|
|
104
|
+
# frame = inspect.currentframe().f_back
|
|
105
|
+
# while frame:
|
|
106
|
+
# if func_name in frame.f_globals:
|
|
107
|
+
# func = frame.f_globals[func_name]
|
|
108
|
+
# break
|
|
109
|
+
# frame = frame.f_back
|
|
110
|
+
|
|
111
|
+
if func and callable(func):
|
|
112
|
+
try:
|
|
113
|
+
tool_result = func(**func_args)
|
|
114
|
+
if isinstance(tool_result, (dict, list)):
|
|
115
|
+
result = json.dumps(tool_result)
|
|
116
|
+
else:
|
|
117
|
+
result = str(tool_result)
|
|
118
|
+
except Exception as e:
|
|
119
|
+
result = f"Error executing tool {func_name}: {str(e)}"
|
|
120
|
+
print(result)
|
|
121
|
+
else:
|
|
122
|
+
result = f"Error: Tool function {func_name} not found."
|
|
123
|
+
print(result)
|
|
124
|
+
|
|
125
|
+
tool_message = {
|
|
126
|
+
"role": "tool",
|
|
127
|
+
"tool_call_id": call_id,
|
|
128
|
+
"content": result
|
|
129
|
+
}
|
|
130
|
+
# Add the response
|
|
131
|
+
instruction_and_contents.append(tool_message)
|
|
132
|
+
else:
|
|
133
|
+
break
|
|
134
|
+
return thoughts, text
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
if __name__ == "__main__":
|
|
138
|
+
|
|
139
|
+
def get_weather(location):
|
|
140
|
+
print(f"Executing weather tool for location: {location}")
|
|
141
|
+
return {"temperature": "72F", "condition": "Sunny"}
|
|
142
|
+
|
|
143
|
+
get_weather_tool = {
|
|
144
|
+
"type": "function",
|
|
145
|
+
"function": {
|
|
146
|
+
"name": "get_weather",
|
|
147
|
+
"description": "Determine weather in my location",
|
|
148
|
+
"parameters": {
|
|
149
|
+
"type": "object",
|
|
150
|
+
"properties": {
|
|
151
|
+
"location": {
|
|
152
|
+
"type": "string",
|
|
153
|
+
"description": "The city and state, e.g. San Francisco, CA"
|
|
154
|
+
},
|
|
155
|
+
},
|
|
156
|
+
"additionalProperties": False,
|
|
157
|
+
"required": [
|
|
158
|
+
"location"
|
|
159
|
+
]
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
tools = [get_weather_tool]
|
|
165
|
+
messages = [
|
|
166
|
+
{"role": "user", "content": "Compare the weather in Oakland, CA and weather in Paris, France. Use the tool for learning both."}
|
|
167
|
+
]
|
|
168
|
+
instructions = "You are a helpful assistant with tools."
|
|
169
|
+
|
|
170
|
+
thought, txt = respond(messages, instructions, tools)
|
|
171
|
+
print(thought, txt)
|
|
172
|
+
...
|
|
173
|
+
"""
|
|
174
|
+
{
|
|
175
|
+
"type": "function",
|
|
176
|
+
"function": {
|
|
177
|
+
"name": "submit_arbitrary_data",
|
|
178
|
+
"description": "CRITICAL: You must invent and generate all keys for this payload based on the context. Do not send an empty object. Every key you create must map to a string value.",
|
|
179
|
+
"strict": false,
|
|
180
|
+
"parameters": {
|
|
181
|
+
"type": "object",
|
|
182
|
+
"properties": {},
|
|
183
|
+
"additionalProperties": {
|
|
184
|
+
"type": "string"
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
Payload Rule: When executing the submit_arbitrary_data tool, you must dynamically generate the entire payload structure yourself. Analyze the user's input, extract all relevant variables, invent descriptive key names for them, and assign them values. Every single value must be a string.
|
|
191
|
+
"""
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# Python
|
|
3
|
+
|
|
4
|
+
"""Copyright (c) Alexander Fedotov.
|
|
5
|
+
This source code is licensed under the license found in the
|
|
6
|
+
LICENSE file in the root directory of this source tree.
|
|
7
|
+
"""
|
|
8
|
+
from .utils import (default_model,
|
|
9
|
+
query)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def complete(text, **kwargs):
|
|
13
|
+
"""A completions endpoint call through requests.
|
|
14
|
+
kwargs:
|
|
15
|
+
temperature = 0 to 1.0
|
|
16
|
+
top_p = 0.0 to 1.0
|
|
17
|
+
n = 1 to 128
|
|
18
|
+
best_of = 4
|
|
19
|
+
frequency_penalty = -2.0 to 2.0
|
|
20
|
+
presence_penalty = -2.0 to 2.0
|
|
21
|
+
max_tokens = number of tokens
|
|
22
|
+
logprobs = number up to 5
|
|
23
|
+
stop = ["stop"] array of up to 4 sequences
|
|
24
|
+
logit_bias = map token: bias -1.0 to 1.0 (restrictive -100 to 100)
|
|
25
|
+
"""
|
|
26
|
+
responses = []
|
|
27
|
+
payload = {
|
|
28
|
+
"model": kwargs.get("model", default_model),
|
|
29
|
+
"prompt": kwargs.get("prompt", text),
|
|
30
|
+
"response_format": kwargs.get('response_format', {'type': 'text'}),
|
|
31
|
+
"reasoning_effort": kwargs.get("reasoning_effort", "high"),
|
|
32
|
+
"reasoning_history":kwargs.get("reasoning_history", "interleaved"),
|
|
33
|
+
"thinking": kwargs.get("thinking", None),
|
|
34
|
+
"max_tokens": kwargs.get("max_tokens", 5),
|
|
35
|
+
"n": kwargs.get("n", 1),
|
|
36
|
+
"stop": kwargs.get("stop_sequences", ["stop"]),
|
|
37
|
+
# "seed": kwargs.get("seed", None),
|
|
38
|
+
"frequency_penalty":kwargs.get("frequency_penalty", 0),
|
|
39
|
+
"presence_penalty": kwargs.get("presence_penalty", 0),
|
|
40
|
+
# "logit_bias": kwargs.get("logit_bias", None),
|
|
41
|
+
"logprobs": kwargs.get("logprobs", None),
|
|
42
|
+
# "top_logprobs": kwargs.get("top_logprobs", None),
|
|
43
|
+
"temperature": kwargs.get("temperature", 1),
|
|
44
|
+
"top_p": kwargs.get("top_p", 1),
|
|
45
|
+
'top_k': kwargs.get('top_k', 50),
|
|
46
|
+
'stream': False,
|
|
47
|
+
# "user": kwargs.get("user", None)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
responses = query(payload, '/completions')
|
|
51
|
+
response = responses['choices'][0]
|
|
52
|
+
text = response['text']
|
|
53
|
+
thoughts = ''
|
|
54
|
+
|
|
55
|
+
return thoughts, text
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
if __name__ == '__main__':
|
|
59
|
+
...
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# Python
|
|
3
|
+
|
|
4
|
+
"""Copyright (c) Alexander Fedotov.
|
|
5
|
+
This source code is licensed under the license found in the
|
|
6
|
+
LICENSE file in the root directory of this source tree.
|
|
7
|
+
"""
|
|
8
|
+
from .utils import (query,
|
|
9
|
+
decode,
|
|
10
|
+
default_model,
|
|
11
|
+
get_function,
|
|
12
|
+
get_func_args,
|
|
13
|
+
call_function)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def get_weather(location):
|
|
17
|
+
# print(f"Executing weather tool for location: {location}")
|
|
18
|
+
return {"temperature": "72F", "condition": "Sunny"}
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def message(messages=None, instructions=None, tools=None, **kwargs):
|
|
22
|
+
"""A continuation of text with a given context and instruction.
|
|
23
|
+
kwargs:
|
|
24
|
+
temperature = 0 to 1.0
|
|
25
|
+
top_p = 0.0 to 1.0
|
|
26
|
+
top_k = The maximum number of tokens to consider when sampling.
|
|
27
|
+
n = 1 to ...
|
|
28
|
+
max_tokens = number of tokens
|
|
29
|
+
stop = ['stop'] array of up to 4 sequences
|
|
30
|
+
"""
|
|
31
|
+
# instruction = kwargs.get('system_instruction', instructions)
|
|
32
|
+
# first_message = [dict(role='system', content=instruction)] if instruction else []
|
|
33
|
+
|
|
34
|
+
# contents can come in kwards or as an argument
|
|
35
|
+
messages = kwargs.get('messages', messages)
|
|
36
|
+
|
|
37
|
+
# add contents and user text to the first (instruction) message
|
|
38
|
+
# first_message.extend(messages)
|
|
39
|
+
# instruction_and_contents = first_message
|
|
40
|
+
|
|
41
|
+
payload = {
|
|
42
|
+
'model': kwargs.get('model', default_model),
|
|
43
|
+
'system': kwargs.get('system', instructions),
|
|
44
|
+
'messages': kwargs.get('messages', messages),
|
|
45
|
+
'output_config': kwargs.get('output_config',{'effort': 'high'}),
|
|
46
|
+
'thinking': kwargs.get('thinking', {
|
|
47
|
+
'type': 'enabled',
|
|
48
|
+
'budget_tokens': 10000,
|
|
49
|
+
}),
|
|
50
|
+
'tool_choice': kwargs.get('tool_choice', {'type': 'auto', 'disable_parallel_tool_use': False}),
|
|
51
|
+
'max_tokens': kwargs.get('max_tokens', 4096),
|
|
52
|
+
'prompt_truncate_len': kwargs.get('prompt_truncate_len', 100000),
|
|
53
|
+
'n': kwargs.get('n', 1),
|
|
54
|
+
'top_p': kwargs.get('top_p', 0.9),
|
|
55
|
+
'top_k': kwargs.get('top_k', 10),
|
|
56
|
+
'stream': False
|
|
57
|
+
}
|
|
58
|
+
if tools:
|
|
59
|
+
payload['tools'] = tools
|
|
60
|
+
payload['parallel_tool_calls'] = True
|
|
61
|
+
payload['tool_choice'] = 'auto'
|
|
62
|
+
|
|
63
|
+
while True:
|
|
64
|
+
result = query(payload, '/messages')
|
|
65
|
+
completion_message = result['content']
|
|
66
|
+
thoughts, text, function_calls = decode(completion_message)
|
|
67
|
+
if function_calls:
|
|
68
|
+
payload['messages'].append({"role": "assistant", "content": completion_message})
|
|
69
|
+
tools_results = []
|
|
70
|
+
# Call all requested functions and create response messages.
|
|
71
|
+
for function_call in function_calls:
|
|
72
|
+
call_id = function_call.get('id')
|
|
73
|
+
func_name = function_call.get('name', '')
|
|
74
|
+
func_args_def = function_call.get('input', '{}')
|
|
75
|
+
# Look up tool by name in globals and caller frames
|
|
76
|
+
func = get_function(func_name)
|
|
77
|
+
func_args = get_func_args(func_args_def)
|
|
78
|
+
result = call_function(func, func_args)
|
|
79
|
+
tool_message = {
|
|
80
|
+
"type": "tool_result",
|
|
81
|
+
"tool_use_id": call_id,
|
|
82
|
+
"content": result
|
|
83
|
+
}
|
|
84
|
+
tools_results.append(tool_message)
|
|
85
|
+
|
|
86
|
+
# Add results to payload and make a query.
|
|
87
|
+
payload['messages'].append({"role": "user", "content": tools_results})
|
|
88
|
+
|
|
89
|
+
else:
|
|
90
|
+
break
|
|
91
|
+
|
|
92
|
+
return thoughts, text
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
if __name__ == '__main__':
|
|
96
|
+
...
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# Python
|
|
3
|
+
|
|
4
|
+
"""Copyright (c) Alexander Fedotov.
|
|
5
|
+
This source code is licensed under the license found in the
|
|
6
|
+
LICENSE file in the root directory of this source tree.
|
|
7
|
+
"""
|
|
8
|
+
from .utils import (query,
|
|
9
|
+
default_model,
|
|
10
|
+
decode_output)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def respond(messages=None, instructions=None, **kwargs):
|
|
14
|
+
""" All parameters should be in kwargs, but they are optional
|
|
15
|
+
"""
|
|
16
|
+
# Receive the instruction
|
|
17
|
+
instruction = kwargs.get('system_instruction', instructions)
|
|
18
|
+
|
|
19
|
+
# Define the initial payload
|
|
20
|
+
payload = {
|
|
21
|
+
"model": kwargs.get("model", default_model),
|
|
22
|
+
"instructions": instruction,
|
|
23
|
+
"input": messages,
|
|
24
|
+
"previous_response_id": kwargs.get("previous_response_id", None),
|
|
25
|
+
"max_output_tokens": kwargs.get("max_tokens", 132000),
|
|
26
|
+
"prompt_cache_retention": "in_memory",
|
|
27
|
+
"include": ["reasoning.encrypted_content"],
|
|
28
|
+
"reasoning": {
|
|
29
|
+
"effort": "high",
|
|
30
|
+
"summary": "detailed"
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
# Query the API
|
|
34
|
+
result = query(payload, '/responses')
|
|
35
|
+
thoughts, text, _ = decode_output(result.get('output', {}))
|
|
36
|
+
|
|
37
|
+
return thoughts, text
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
if __name__ == "__main__":
|
|
41
|
+
...
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# Python
|
|
3
|
+
|
|
4
|
+
"""Copyright (c) Alexander Fedotov.
|
|
5
|
+
This source code is licensed under the license found in the
|
|
6
|
+
LICENSE file in the root directory of this source tree.
|
|
7
|
+
"""
|
|
8
|
+
from .utils import (query,
|
|
9
|
+
default_model,
|
|
10
|
+
get_function,
|
|
11
|
+
get_func_args,
|
|
12
|
+
call_function,
|
|
13
|
+
decode_output)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def get_weather(location):
|
|
17
|
+
# print(f"Executing weather tool for location: {location}")
|
|
18
|
+
return {"temperature": "72F", "condition": "Sunny"}
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def respond(messages=None, instructions=None, tools=None, **kwargs):
|
|
22
|
+
""" All parameters should be in kwargs, but they are optional
|
|
23
|
+
"""
|
|
24
|
+
# Receive the instruction
|
|
25
|
+
instruction = kwargs.get('system_instruction', instructions)
|
|
26
|
+
|
|
27
|
+
# Define the initial payload
|
|
28
|
+
payload = {
|
|
29
|
+
"model": kwargs.get("model", default_model),
|
|
30
|
+
"instructions": instruction,
|
|
31
|
+
"input": messages,
|
|
32
|
+
"previous_response_id": kwargs.get("previous_response_id", None),
|
|
33
|
+
"max_output_tokens": kwargs.get("max_tokens", 132000),
|
|
34
|
+
"prompt_cache_retention": "in_memory",
|
|
35
|
+
"include": ["reasoning.encrypted_content"],
|
|
36
|
+
"reasoning": {
|
|
37
|
+
"effort": "high",
|
|
38
|
+
"summary": "detailed"
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
# Tools if there are some
|
|
42
|
+
if tools:
|
|
43
|
+
payload['tools'] = tools
|
|
44
|
+
payload['parallel_tool_calls'] = True
|
|
45
|
+
payload['max_tool_calls'] = kwargs.get("max_tool_calls", None)
|
|
46
|
+
payload['tool_choice'] = 'auto'
|
|
47
|
+
|
|
48
|
+
while True:
|
|
49
|
+
# Query the API
|
|
50
|
+
result = query(payload, '/responses')
|
|
51
|
+
# id of the response
|
|
52
|
+
response_id = result['id']
|
|
53
|
+
thoughts, text, function_calls = decode_output(result.get('output', {}))
|
|
54
|
+
|
|
55
|
+
if function_calls:
|
|
56
|
+
function_outputs_messages = []
|
|
57
|
+
for function_call in function_calls:
|
|
58
|
+
call_id = function_call.get('call_id')
|
|
59
|
+
func_name = function_call.get('name')
|
|
60
|
+
func_args_str = function_call.get('arguments', {})
|
|
61
|
+
|
|
62
|
+
# Look up tool by name in globals and in caller frames
|
|
63
|
+
func = get_function(func_name)
|
|
64
|
+
func_args = get_func_args(func_args_str)
|
|
65
|
+
result = call_function(func, func_args)
|
|
66
|
+
|
|
67
|
+
tool_message = {
|
|
68
|
+
"type": "function_call_output",
|
|
69
|
+
"call_id": call_id,
|
|
70
|
+
"output": result
|
|
71
|
+
}
|
|
72
|
+
function_outputs_messages.append(tool_message)
|
|
73
|
+
|
|
74
|
+
# Now that all responses have been gathered
|
|
75
|
+
# we can change the payload and send them back
|
|
76
|
+
payload['previous_response_id'] = response_id
|
|
77
|
+
payload['input'] = function_outputs_messages
|
|
78
|
+
else:
|
|
79
|
+
break
|
|
80
|
+
|
|
81
|
+
return thoughts, text
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
if __name__ == "__main__":
|
|
85
|
+
...
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# Python
|
|
3
|
+
|
|
4
|
+
"""Copyright (c) Alexander Fedotov.
|
|
5
|
+
This source code is licensed under the license found in the
|
|
6
|
+
LICENSE file in the root directory of this source tree.
|
|
7
|
+
"""
|
|
8
|
+
import json
|
|
9
|
+
import urllib.request
|
|
10
|
+
import urllib.error
|
|
11
|
+
from os import environ
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
# The configuration.
|
|
15
|
+
api_key = environ.get("CHINF_API_KEY", '')
|
|
16
|
+
default_model = environ.get("CHINF_DEFAULT_MODEL", 'gpt-5.6-luna')
|
|
17
|
+
api_base = environ.get("CHINF_API_BASE", "https://api.cheaperinference.com/v1")
|
|
18
|
+
|
|
19
|
+
# Set the mandatory headers
|
|
20
|
+
headers = {
|
|
21
|
+
"Content-Type": "application/json",
|
|
22
|
+
"Authorization": f"Bearer {api_key}",
|
|
23
|
+
"User-Agent": "chinf"
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def get_function(func_name):
|
|
28
|
+
# Look up tool by name in globals
|
|
29
|
+
func = globals().get(func_name)
|
|
30
|
+
# Look up in the caller frames
|
|
31
|
+
if not func:
|
|
32
|
+
import inspect
|
|
33
|
+
frame = inspect.currentframe().f_back
|
|
34
|
+
while frame:
|
|
35
|
+
if func_name in frame.f_globals:
|
|
36
|
+
func = frame.f_globals[func_name]
|
|
37
|
+
break
|
|
38
|
+
frame = frame.f_back
|
|
39
|
+
|
|
40
|
+
return func
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def get_func_args(func_args_str):
|
|
44
|
+
try:
|
|
45
|
+
if isinstance(func_args_str, str):
|
|
46
|
+
func_args = json.loads(func_args_str)
|
|
47
|
+
else:
|
|
48
|
+
func_args = func_args_str
|
|
49
|
+
except Exception as e:
|
|
50
|
+
func_args = {}
|
|
51
|
+
print(f"Error parsing tool arguments: {e}")
|
|
52
|
+
|
|
53
|
+
return func_args
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def call_function(func, func_args):
|
|
57
|
+
if func and callable(func):
|
|
58
|
+
try:
|
|
59
|
+
tool_result = func(**func_args)
|
|
60
|
+
if isinstance(tool_result, (dict, list)):
|
|
61
|
+
result = json.dumps(tool_result)
|
|
62
|
+
else:
|
|
63
|
+
result = str(tool_result)
|
|
64
|
+
except Exception as e:
|
|
65
|
+
result = f"Error executing tool: {str(e)}"
|
|
66
|
+
print(result)
|
|
67
|
+
else:
|
|
68
|
+
result = f"Error: Tool function not callable."
|
|
69
|
+
print(result)
|
|
70
|
+
|
|
71
|
+
return result
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def query(payload, url_suffix):
|
|
75
|
+
# Convert data dictionary to JSON and encode it to bytes
|
|
76
|
+
data_bytes = json.dumps(payload).encode('utf-8')
|
|
77
|
+
# Create the Request object
|
|
78
|
+
req = urllib.request.Request(
|
|
79
|
+
f'{api_base}{url_suffix}',
|
|
80
|
+
data=data_bytes,
|
|
81
|
+
headers=headers,
|
|
82
|
+
method="POST")
|
|
83
|
+
# Try to query
|
|
84
|
+
try:
|
|
85
|
+
# Execute the request
|
|
86
|
+
with urllib.request.urlopen(req, timeout=3000) as response:
|
|
87
|
+
response_data = response.read().decode('utf-8')
|
|
88
|
+
output = json.loads(response_data)
|
|
89
|
+
return output
|
|
90
|
+
|
|
91
|
+
except urllib.error.HTTPError as e:
|
|
92
|
+
# Handle HTTP errors (e.g., 401 Unauthorized, 400 Bad Request)
|
|
93
|
+
error_info = e.read().decode('utf-8', errors='ignore')
|
|
94
|
+
print(f"HTTP Error {e.code}: {e.reason}")
|
|
95
|
+
print(f"Error Details: {error_info}")
|
|
96
|
+
return {}
|
|
97
|
+
|
|
98
|
+
except urllib.error.URLError as e:
|
|
99
|
+
# Handle network/connection errors
|
|
100
|
+
print(f"Failed to reach the server: {e.reason}")
|
|
101
|
+
return {}
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def decode_output(output):
|
|
105
|
+
# Parse the result
|
|
106
|
+
text = ''; thoughts = ''
|
|
107
|
+
for part in output:
|
|
108
|
+
part_type = part.get('type', None)
|
|
109
|
+
if part_type == 'message':
|
|
110
|
+
text = " ".join([chunk['text'] for chunk in part['content'] if chunk['type'] == 'output_text'])
|
|
111
|
+
elif part_type == 'reasoning':
|
|
112
|
+
thoughts = " ".join([chunk['text'] for chunk in part['summary'] if chunk['type'] == 'summary_text'])
|
|
113
|
+
function_calls = [part for part in output if part['type'] == 'function_call']
|
|
114
|
+
return thoughts, text, function_calls
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def decode(output):
|
|
118
|
+
text = ''
|
|
119
|
+
thoughts = ''
|
|
120
|
+
for chunk in output:
|
|
121
|
+
chunk_type = chunk.get('type', '')
|
|
122
|
+
if chunk_type == 'text':
|
|
123
|
+
addition = chunk.get('text', '')
|
|
124
|
+
if addition not in ('\n\n', '\n'):
|
|
125
|
+
text += addition
|
|
126
|
+
|
|
127
|
+
elif chunk_type == 'thinking':
|
|
128
|
+
thoughts += chunk.get('thinking', '')
|
|
129
|
+
function_calls = [part for part in output if part['type'] == 'tool_use']
|
|
130
|
+
|
|
131
|
+
return thoughts, text, function_calls
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: chinf
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: Package description
|
|
5
|
+
Author-email: Machina Ratiocinatrix <machina.ratio@gmail.com>, Alexander Fedotov <alex.fedotov@aol.com>
|
|
6
|
+
Project-URL: Homepage, https://github.com/alxfed/chinf
|
|
7
|
+
Keywords: chinf
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Requires-Python: >=3.10
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
License-File: LICENSE
|
|
14
|
+
Requires-Dist: pyyaml==6.0.3
|
|
15
|
+
Dynamic: license-file
|
|
16
|
+
|
|
17
|
+
# Chinf
|
|
18
|
+
API calls to Cheap Inference without dependencies.
|
|
19
|
+
<pre>
|
|
20
|
+
pip install chinf
|
|
21
|
+
</pre>
|
|
22
|
+
Then:
|
|
23
|
+
```Python
|
|
24
|
+
# Python
|
|
25
|
+
from yaml import safe_load as yl
|
|
26
|
+
from chinf.chat import chat_complete as cc
|
|
27
|
+
|
|
28
|
+
kwargs = """ # this is a string in YAML format
|
|
29
|
+
max_tokens: 32000
|
|
30
|
+
stop_sequences:
|
|
31
|
+
- STOP
|
|
32
|
+
- "\nTitle"
|
|
33
|
+
temperature: 1.0
|
|
34
|
+
top_k: 10
|
|
35
|
+
top_p: 0.5
|
|
36
|
+
reasoning_effort: high
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
instruction = 'You are a helpful assistant. Do not use markdown or lists in your responses.'
|
|
40
|
+
|
|
41
|
+
weather_tool = """ # YAML definition of a function (old format)
|
|
42
|
+
type: function
|
|
43
|
+
function:
|
|
44
|
+
name: get_weather
|
|
45
|
+
description: Determine weather in a location
|
|
46
|
+
parameters:
|
|
47
|
+
type: object
|
|
48
|
+
properties:
|
|
49
|
+
location:
|
|
50
|
+
type: string
|
|
51
|
+
description: The city and state, e.g. San Francisco, CA
|
|
52
|
+
additionalProperties: false
|
|
53
|
+
required:
|
|
54
|
+
- location
|
|
55
|
+
"""
|
|
56
|
+
|
|
57
|
+
tools = [yl(weather_tool)]
|
|
58
|
+
|
|
59
|
+
msgs = [{'role': 'user', 'content': 'What is the weather in Chicago, IL and Paris, France?'}]
|
|
60
|
+
|
|
61
|
+
thoughts, text = cc(
|
|
62
|
+
messages=msgs,
|
|
63
|
+
instructions=instruction,
|
|
64
|
+
tools=tools,
|
|
65
|
+
**yl(kwargs)
|
|
66
|
+
)
|
|
67
|
+
```
|
|
68
|
+
or
|
|
69
|
+
```Python
|
|
70
|
+
from yaml import safe_load as yl
|
|
71
|
+
from chinf.messages import message
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
kwargs = """ # this is a string in YAML format
|
|
75
|
+
max_tokens: 32000
|
|
76
|
+
stop_sequences:
|
|
77
|
+
- STOP
|
|
78
|
+
- "\nTitle"
|
|
79
|
+
temperature: 1.0
|
|
80
|
+
top_k: 10
|
|
81
|
+
top_p: 0.5
|
|
82
|
+
thinking:
|
|
83
|
+
type: enabled
|
|
84
|
+
budget_tokens: 24576
|
|
85
|
+
display: summarized
|
|
86
|
+
tool_choice:
|
|
87
|
+
type: auto
|
|
88
|
+
disable_parallel_tool_use: false
|
|
89
|
+
"""
|
|
90
|
+
|
|
91
|
+
instruction = 'You are a helpful assistant. Do not use markdown or lists in your responses.'
|
|
92
|
+
|
|
93
|
+
get_weather_tool_str = """ # YAML definition of a function
|
|
94
|
+
name: get_weather
|
|
95
|
+
description: Determine weather in a location
|
|
96
|
+
input_schema:
|
|
97
|
+
type: object
|
|
98
|
+
properties:
|
|
99
|
+
location:
|
|
100
|
+
type: string
|
|
101
|
+
description: The city and state, e.g. San Francisco, CA
|
|
102
|
+
additionalProperties: true
|
|
103
|
+
required:
|
|
104
|
+
- location
|
|
105
|
+
"""
|
|
106
|
+
|
|
107
|
+
tools = [yl(get_weather_tool_str)]
|
|
108
|
+
|
|
109
|
+
msg = [{'role': 'user', 'content': 'What is the weather in Chicago, IL and Paris, France?'}]
|
|
110
|
+
|
|
111
|
+
thoughts, text = message(
|
|
112
|
+
messages=msg,
|
|
113
|
+
instructions=instruction,
|
|
114
|
+
tools=tools,
|
|
115
|
+
**yl(kwargs)
|
|
116
|
+
)
|
|
117
|
+
```
|
|
118
|
+
or
|
|
119
|
+
|
|
120
|
+
```Python
|
|
121
|
+
from yaml import safe_load as yl
|
|
122
|
+
from chinf.responses import respond
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
kwargs = """ # this is a string in YAML format
|
|
126
|
+
max_tokens: 64000
|
|
127
|
+
temperature: 1.0
|
|
128
|
+
"""
|
|
129
|
+
|
|
130
|
+
msgs = [{'role': 'user', 'content': 'What is the weather in Chicago, IL and Paris, France?'}]
|
|
131
|
+
|
|
132
|
+
weather_tool = """ # YAML definition of a function (new format)
|
|
133
|
+
type: function
|
|
134
|
+
name: get_weather
|
|
135
|
+
description: Determine weather in a location
|
|
136
|
+
parameters:
|
|
137
|
+
type: object
|
|
138
|
+
properties:
|
|
139
|
+
location:
|
|
140
|
+
type: string
|
|
141
|
+
description: The city and state, e.g. San Francisco, CA
|
|
142
|
+
additionalProperties: false
|
|
143
|
+
required:
|
|
144
|
+
- location
|
|
145
|
+
"""
|
|
146
|
+
|
|
147
|
+
tools = [yl(weather_tool)]
|
|
148
|
+
|
|
149
|
+
instructions = """
|
|
150
|
+
You are a helpful assistant.
|
|
151
|
+
Rubric: respond in plain text without any markdown, emphasis or lists;
|
|
152
|
+
all paragraphs except the first one should begin with a newline and a tab.
|
|
153
|
+
"""
|
|
154
|
+
|
|
155
|
+
thougts, text = respond(
|
|
156
|
+
messages=msgs,
|
|
157
|
+
instructions=instructions,
|
|
158
|
+
tools=tools,
|
|
159
|
+
**yl(kwargs)
|
|
160
|
+
)
|
|
161
|
+
```
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
src/chinf/__init__.py
|
|
5
|
+
src/chinf/chat.py
|
|
6
|
+
src/chinf/completion.py
|
|
7
|
+
src/chinf/messages.py
|
|
8
|
+
src/chinf/resp_simplified.py
|
|
9
|
+
src/chinf/responses.py
|
|
10
|
+
src/chinf/utils.py
|
|
11
|
+
src/chinf.egg-info/PKG-INFO
|
|
12
|
+
src/chinf.egg-info/SOURCES.txt
|
|
13
|
+
src/chinf.egg-info/dependency_links.txt
|
|
14
|
+
src/chinf.egg-info/requires.txt
|
|
15
|
+
src/chinf.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
pyyaml==6.0.3
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
chinf
|