python-fastllm 0.0.31__py3-none-any.whl → 0.0.33__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- fastllm/__init__.py +1 -1
- fastllm/_modidx.py +1 -30
- fastllm/acomplete.py +1 -0
- fastllm/anthropic.py +1 -0
- fastllm/chat.py +25 -169
- fastllm/gemini.py +1 -0
- fastllm/openai_chat.py +1 -0
- fastllm/openai_responses.py +1 -0
- fastllm/streaming.py +1 -0
- fastllm/types.py +14 -149
- {python_fastllm-0.0.31.dist-info → python_fastllm-0.0.33.dist-info}/METADATA +3 -1
- python_fastllm-0.0.33.dist-info/RECORD +22 -0
- python_fastllm-0.0.31.dist-info/RECORD +0 -22
- {python_fastllm-0.0.31.dist-info → python_fastllm-0.0.33.dist-info}/WHEEL +0 -0
- {python_fastllm-0.0.31.dist-info → python_fastllm-0.0.33.dist-info}/entry_points.txt +0 -0
- {python_fastllm-0.0.31.dist-info → python_fastllm-0.0.33.dist-info}/top_level.txt +0 -0
fastllm/__init__.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "0.0.
|
|
1
|
+
__version__ = "0.0.33"
|
fastllm/_modidx.py
CHANGED
|
@@ -78,14 +78,9 @@ d = { 'settings': { 'branch': 'main',
|
|
|
78
78
|
'fastllm.chat.FenceToolStop': ('chat.html#fencetoolstop', 'fastllm/chat.py'),
|
|
79
79
|
'fastllm.chat.FenceToolStop.__call__': ('chat.html#fencetoolstop.__call__', 'fastllm/chat.py'),
|
|
80
80
|
'fastllm.chat.FenceToolStop.__init__': ('chat.html#fencetoolstop.__init__', 'fastllm/chat.py'),
|
|
81
|
-
'fastllm.chat.FullResponse': ('chat.html#fullresponse', 'fastllm/chat.py'),
|
|
82
|
-
'fastllm.chat.MediaUrl': ('chat.html#mediaurl', 'fastllm/chat.py'),
|
|
83
|
-
'fastllm.chat.MediaUrl.__init__': ('chat.html#mediaurl.__init__', 'fastllm/chat.py'),
|
|
84
|
-
'fastllm.chat.Msg.text': ('chat.html#msg.text', 'fastllm/chat.py'),
|
|
85
81
|
'fastllm.chat.StopReasonCallback': ('chat.html#stopreasoncallback', 'fastllm/chat.py'),
|
|
86
82
|
'fastllm.chat.StopReasonCallback.after_acomplete': ( 'chat.html#stopreasoncallback.after_acomplete',
|
|
87
83
|
'fastllm/chat.py'),
|
|
88
|
-
'fastllm.chat.StopResponse': ('chat.html#stopresponse', 'fastllm/chat.py'),
|
|
89
84
|
'fastllm.chat.StopSequencesCallback': ('chat.html#stopsequencescallback', 'fastllm/chat.py'),
|
|
90
85
|
'fastllm.chat.StopSequencesCallback.__init__': ( 'chat.html#stopsequencescallback.__init__',
|
|
91
86
|
'fastllm/chat.py'),
|
|
@@ -113,7 +108,6 @@ d = { 'settings': { 'branch': 'main',
|
|
|
113
108
|
'fastllm.chat._apply_cache_idxs': ('chat.html#_apply_cache_idxs', 'fastllm/chat.py'),
|
|
114
109
|
'fastllm.chat._bytes2content': ('chat.html#_bytes2content', 'fastllm/chat.py'),
|
|
115
110
|
'fastllm.chat._call_func': ('chat.html#_call_func', 'fastllm/chat.py'),
|
|
116
|
-
'fastllm.chat._extract_tool_parts': ('chat.html#_extract_tool_parts', 'fastllm/chat.py'),
|
|
117
111
|
'fastllm.chat._handle_stop_reason': ('chat.html#_handle_stop_reason', 'fastllm/chat.py'),
|
|
118
112
|
'fastllm.chat._has_cache': ('chat.html#_has_cache', 'fastllm/chat.py'),
|
|
119
113
|
'fastllm.chat._has_search': ('chat.html#_has_search', 'fastllm/chat.py'),
|
|
@@ -123,15 +117,10 @@ d = { 'settings': { 'branch': 'main',
|
|
|
123
117
|
'fastllm.chat._mime2part_type': ('chat.html#_mime2part_type', 'fastllm/chat.py'),
|
|
124
118
|
'fastllm.chat._mk_content': ('chat.html#_mk_content', 'fastllm/chat.py'),
|
|
125
119
|
'fastllm.chat._mk_prefill': ('chat.html#_mk_prefill', 'fastllm/chat.py'),
|
|
126
|
-
'fastllm.chat._mk_result_fence': ('chat.html#_mk_result_fence', 'fastllm/chat.py'),
|
|
127
120
|
'fastllm.chat._mk_tool_result': ('chat.html#_mk_tool_result', 'fastllm/chat.py'),
|
|
128
|
-
'fastllm.chat._split_fence_msgs': ('chat.html#_split_fence_msgs', 'fastllm/chat.py'),
|
|
129
|
-
'fastllm.chat._split_msg_on_fences': ('chat.html#_split_msg_on_fences', 'fastllm/chat.py'),
|
|
130
121
|
'fastllm.chat._tc_summary': ('chat.html#_tc_summary', 'fastllm/chat.py'),
|
|
131
122
|
'fastllm.chat._think_kw': ('chat.html#_think_kw', 'fastllm/chat.py'),
|
|
132
|
-
'fastllm.chat._trunc_content': ('chat.html#_trunc_content', 'fastllm/chat.py'),
|
|
133
123
|
'fastllm.chat._trunc_param': ('chat.html#_trunc_param', 'fastllm/chat.py'),
|
|
134
|
-
'fastllm.chat._trunc_str': ('chat.html#_trunc_str', 'fastllm/chat.py'),
|
|
135
124
|
'fastllm.chat._url2content': ('chat.html#_url2content', 'fastllm/chat.py'),
|
|
136
125
|
'fastllm.chat._usrtools': ('chat.html#_usrtools', 'fastllm/chat.py'),
|
|
137
126
|
'fastllm.chat.add_warning': ('chat.html#add_warning', 'fastllm/chat.py'),
|
|
@@ -140,17 +129,13 @@ d = { 'settings': { 'branch': 'main',
|
|
|
140
129
|
'fastllm.chat.cite_footnote': ('chat.html#cite_footnote', 'fastllm/chat.py'),
|
|
141
130
|
'fastllm.chat.contents': ('chat.html#contents', 'fastllm/chat.py'),
|
|
142
131
|
'fastllm.chat.extract_fence_call': ('chat.html#extract_fence_call', 'fastllm/chat.py'),
|
|
143
|
-
'fastllm.chat.fmt2hist': ('chat.html#fmt2hist', 'fastllm/chat.py'),
|
|
144
|
-
'fastllm.chat.hist2fmt': ('chat.html#hist2fmt', 'fastllm/chat.py'),
|
|
145
132
|
'fastllm.chat.lite_mk_func': ('chat.html#lite_mk_func', 'fastllm/chat.py'),
|
|
146
133
|
'fastllm.chat.mk_msg': ('chat.html#mk_msg', 'fastllm/chat.py'),
|
|
147
134
|
'fastllm.chat.mk_msgs': ('chat.html#mk_msgs', 'fastllm/chat.py'),
|
|
148
|
-
'fastllm.chat.mk_tr_details': ('chat.html#mk_tr_details', 'fastllm/chat.py'),
|
|
149
135
|
'fastllm.chat.postproc': ('chat.html#postproc', 'fastllm/chat.py'),
|
|
150
136
|
'fastllm.chat.remove_cache_ckpts': ('chat.html#remove_cache_ckpts', 'fastllm/chat.py'),
|
|
151
137
|
'fastllm.chat.run_fence_tool': ('chat.html#run_fence_tool', 'fastllm/chat.py'),
|
|
152
138
|
'fastllm.chat.search_count': ('chat.html#search_count', 'fastllm/chat.py'),
|
|
153
|
-
'fastllm.chat.split_tools': ('chat.html#split_tools', 'fastllm/chat.py'),
|
|
154
139
|
'fastllm.chat.stop_reason': ('chat.html#stop_reason', 'fastllm/chat.py'),
|
|
155
140
|
'fastllm.chat.stop_sequences': ('chat.html#stop_sequences', 'fastllm/chat.py'),
|
|
156
141
|
'fastllm.chat.structured': ('chat.html#structured', 'fastllm/chat.py')},
|
|
@@ -273,18 +258,8 @@ d = { 'settings': { 'branch': 'main',
|
|
|
273
258
|
'fastllm.types.Completion': ('types.html#completion', 'fastllm/types.py'),
|
|
274
259
|
'fastllm.types.Completion._repr_markdown_': ('types.html#completion._repr_markdown_', 'fastllm/types.py'),
|
|
275
260
|
'fastllm.types.Completion.cost': ('types.html#completion.cost', 'fastllm/types.py'),
|
|
276
|
-
'fastllm.types.Msg': ('types.html#msg', 'fastllm/types.py'),
|
|
277
|
-
'fastllm.types.Msg._repr_markdown_': ('types.html#msg._repr_markdown_', 'fastllm/types.py'),
|
|
278
|
-
'fastllm.types.Part': ('types.html#part', 'fastllm/types.py'),
|
|
279
|
-
'fastllm.types.Part._repr_markdown_': ('types.html#part._repr_markdown_', 'fastllm/types.py'),
|
|
280
|
-
'fastllm.types.ToolCall': ('types.html#toolcall', 'fastllm/types.py'),
|
|
281
|
-
'fastllm.types.ToolCall._repr_markdown_': ('types.html#toolcall._repr_markdown_', 'fastllm/types.py'),
|
|
282
261
|
'fastllm.types.Usage': ('types.html#usage', 'fastllm/types.py'),
|
|
283
|
-
'fastllm.types._fetch_url_partial': ('types.html#_fetch_url_partial', 'fastllm/types.py'),
|
|
284
|
-
'fastllm.types._trunc_strs': ('types.html#_trunc_strs', 'fastllm/types.py'),
|
|
285
262
|
'fastllm.types.approx_pricing': ('types.html#approx_pricing', 'fastllm/types.py'),
|
|
286
|
-
'fastllm.types.data_url': ('types.html#data_url', 'fastllm/types.py'),
|
|
287
|
-
'fastllm.types.display_list': ('types.html#display_list', 'fastllm/types.py'),
|
|
288
263
|
'fastllm.types.fn_schema': ('types.html#fn_schema', 'fastllm/types.py'),
|
|
289
264
|
'fastllm.types.get_api_key': ('types.html#get_api_key', 'fastllm/types.py'),
|
|
290
265
|
'fastllm.types.get_model_info': ('types.html#get_model_info', 'fastllm/types.py'),
|
|
@@ -293,11 +268,7 @@ d = { 'settings': { 'branch': 'main',
|
|
|
293
268
|
'fastllm.types.infer_api_name': ('types.html#infer_api_name', 'fastllm/types.py'),
|
|
294
269
|
'fastllm.types.is_deepseek_peak_hour': ('types.html#is_deepseek_peak_hour', 'fastllm/types.py'),
|
|
295
270
|
'fastllm.types.mk_completion': ('types.html#mk_completion', 'fastllm/types.py'),
|
|
296
|
-
'fastllm.types.mk_tool_res_msg': ('types.html#mk_tool_res_msg', 'fastllm/types.py'),
|
|
297
271
|
'fastllm.types.model_prices_meta': ('types.html#model_prices_meta', 'fastllm/types.py'),
|
|
298
|
-
'fastllm.types.part_txt': ('types.html#part_txt', 'fastllm/types.py'),
|
|
299
272
|
'fastllm.types.payload_kwargs': ('types.html#payload_kwargs', 'fastllm/types.py'),
|
|
300
273
|
'fastllm.types.register_model_info': ('types.html#register_model_info', 'fastllm/types.py'),
|
|
301
|
-
'fastllm.types.resize_b64': ('types.html#resize_b64', 'fastllm/types.py')
|
|
302
|
-
'fastllm.types.sys_text': ('types.html#sys_text', 'fastllm/types.py'),
|
|
303
|
-
'fastllm.types.url_mime': ('types.html#url_mime', 'fastllm/types.py')}}}
|
|
274
|
+
'fastllm.types.resize_b64': ('types.html#resize_b64', 'fastllm/types.py')}}}
|
fastllm/acomplete.py
CHANGED
fastllm/anthropic.py
CHANGED
fastllm/chat.py
CHANGED
|
@@ -3,33 +3,28 @@
|
|
|
3
3
|
# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/07_chat.ipynb.
|
|
4
4
|
|
|
5
5
|
# %% auto #0
|
|
6
|
-
__all__ = ['
|
|
7
|
-
'
|
|
8
|
-
'
|
|
9
|
-
'
|
|
10
|
-
'
|
|
11
|
-
'StopReasonCallback', 'run_fence_tool', 'FenceToolCallback', 'ToolReminderCallback', 'stop_sequences',
|
|
12
|
-
'StopSequencesCallback', 'mk_tr_details', 'hist2fmt', 'StreamFormatter', 'AsyncStreamFormatter',
|
|
13
|
-
'adisplay_stream']
|
|
6
|
+
__all__ = ['effort', 'remove_cache_ckpts', 'contents', 'stop_reason', 'mk_msg', 'FenceToolStop', 'extract_fence_call', 'mk_msgs',
|
|
7
|
+
'cite_footnote', 'postproc', 'lite_mk_func', 'ToolResponse', 'structured', 'search_count', 'UsageStats',
|
|
8
|
+
'AsyncChat', 'astream_with_complete', 'ChatCallback', 'DeepseekMsgsCallback', 'DeepseekPrefillCallback',
|
|
9
|
+
'add_warning', 'StopReasonCallback', 'run_fence_tool', 'FenceToolCallback', 'ToolReminderCallback',
|
|
10
|
+
'stop_sequences', 'StopSequencesCallback', 'StreamFormatter', 'AsyncStreamFormatter', 'adisplay_stream']
|
|
14
11
|
|
|
15
12
|
# %% ../nbs/07_chat.ipynb #d5a3bc1f
|
|
16
|
-
import base64, json
|
|
17
13
|
from typing import Optional,Callable
|
|
18
|
-
from html import escape
|
|
19
14
|
from toolslm.funccall import mk_ns, call_func, call_func_async, get_schema
|
|
20
15
|
from fastcore.utils import *
|
|
21
16
|
from fastcore.meta import delegates
|
|
22
17
|
from dataclasses import dataclass
|
|
18
|
+
import base64
|
|
23
19
|
|
|
24
20
|
from .types import *
|
|
21
|
+
from fastcore.xtras import detect_mime
|
|
22
|
+
from aidialog.msg_parts import (Msg, Part, PartType, ToolCall, mk_tool_res_msg, mk_tr_details,
|
|
23
|
+
tool_info, usage_info, think_start, think_end, StopResponse, display_list, MediaUrl, url_mime, fmt2hist,
|
|
24
|
+
_mk_result_fence, _split_fence_msgs, _fence_back, _trunc_str)
|
|
25
25
|
from .acomplete import *
|
|
26
26
|
|
|
27
|
-
# %% ../nbs/07_chat.ipynb #
|
|
28
|
-
class MediaUrl(BasicRepr):
|
|
29
|
-
"Direct URL media reference"
|
|
30
|
-
def __init__(self, url, mime=None): self.url, self.mime = url, ifnone(mime, url_mime(url))
|
|
31
|
-
|
|
32
|
-
# %% ../nbs/07_chat.ipynb #eb557831
|
|
27
|
+
# %% ../nbs/07_chat.ipynb #4a37bae5
|
|
33
28
|
def _mime2part_type(mime):
|
|
34
29
|
"Map MIME string to canonical PartType"
|
|
35
30
|
if mime.startswith('image/'): return PartType.input_image
|
|
@@ -49,7 +44,7 @@ def _url2content(o):
|
|
|
49
44
|
mime = o.mime or url_mime(o.url)
|
|
50
45
|
return Part(type=_mime2part_type(mime), text=o.url, data=dict(mime=mime))
|
|
51
46
|
|
|
52
|
-
# %% ../nbs/07_chat.ipynb #
|
|
47
|
+
# %% ../nbs/07_chat.ipynb #43a55cda
|
|
53
48
|
def _add_cache_control(
|
|
54
49
|
msg, # LiteLLM formatted msg
|
|
55
50
|
ttl=None # Cache TTL: '5m' (default) or '1h'
|
|
@@ -78,6 +73,8 @@ def _mk_content(o):
|
|
|
78
73
|
elif isinstance(o, MediaUrl): return _url2content(o)
|
|
79
74
|
return o
|
|
80
75
|
|
|
76
|
+
|
|
77
|
+
# %% ../nbs/07_chat.ipynb #48c78e48
|
|
81
78
|
def contents(c):
|
|
82
79
|
"Get Msg object from Completion."
|
|
83
80
|
if not c.message: return ''
|
|
@@ -87,7 +84,7 @@ def stop_reason(c):
|
|
|
87
84
|
if not c.finish_reason: return 'unk'
|
|
88
85
|
return c.finish_reason
|
|
89
86
|
|
|
90
|
-
# %% ../nbs/07_chat.ipynb #
|
|
87
|
+
# %% ../nbs/07_chat.ipynb #4a1c44ea
|
|
91
88
|
def mk_msg(
|
|
92
89
|
content, # Content: str, bytes (image), list of mixed content, or dict w 'role' and 'content' fields
|
|
93
90
|
role="user", # Message role if content isn't already a dict/Message
|
|
@@ -105,20 +102,8 @@ def mk_msg(
|
|
|
105
102
|
msg = Msg(role=role, content=parts)
|
|
106
103
|
return _add_cache_control(msg, ttl=ttl) if cache else msg
|
|
107
104
|
|
|
108
|
-
# %% ../nbs/07_chat.ipynb #db466e1c
|
|
109
|
-
tool_dtls_tag = "<details class='tool-usage-details' markdown='1'>"
|
|
110
|
-
re_tools = re.compile(fr"^({tool_dtls_tag}\n*(?:<summary>(?P<summary>.*?)</summary>\n*)?\n*```json\n+(.*?)\n+```\n+</details>)",
|
|
111
|
-
flags=re.DOTALL|re.MULTILINE)
|
|
112
|
-
token_dtls_tag = "<details class='token-usage-details' markdown='1'>"
|
|
113
|
-
re_token = re.compile(fr"^{re.escape(token_dtls_tag)}\n*<summary>.*?</summary>\n*\n*`.*?`\n*\n*</details>\n?",
|
|
114
|
-
flags=re.DOTALL|re.MULTILINE)
|
|
115
|
-
think_start,think_end = '<!--think_start-->','<!--think_end-->'
|
|
116
|
-
re_think = re.compile(rf'{re.escape(think_start)}.*?{re.escape(think_end)}\n?', re.DOTALL)
|
|
117
|
-
|
|
118
105
|
# %% ../nbs/07_chat.ipynb #be998131
|
|
119
|
-
_fence_back = '`````'
|
|
120
106
|
_fence_re = re.compile(f'^{_fence_back}(py|bash)\n(.*?)\n{_fence_back}$', re.DOTALL | re.MULTILINE)
|
|
121
|
-
_result_re = re.compile(f'\n{_fence_back}result\n(.*?)\n{_fence_back}\n', re.DOTALL)
|
|
122
107
|
_lang2tool = dict(py='python', bash='bash')
|
|
123
108
|
|
|
124
109
|
class FenceToolStop:
|
|
@@ -136,83 +121,7 @@ def extract_fence_call(text):
|
|
|
136
121
|
m = ms[-1]
|
|
137
122
|
if not text[m.end():].strip(): return m.group(1), m.group(2)
|
|
138
123
|
|
|
139
|
-
# %% ../nbs/07_chat.ipynb #
|
|
140
|
-
@patch(as_prop=True)
|
|
141
|
-
def text(self:Msg): return ''.join(p.text or '' for p in self.content if p.type == PartType.text)
|
|
142
|
-
|
|
143
|
-
# %% ../nbs/07_chat.ipynb #1de7e4d2
|
|
144
|
-
def _mk_result_fence(output): return f"\n{_fence_back}result\n{output}\n{_fence_back}\n"
|
|
145
|
-
|
|
146
|
-
def _split_msg_on_fences(msg):
|
|
147
|
-
"Split an assistant Msg on result fences, return list of Msgs"
|
|
148
|
-
if msg.role != 'assistant': return [msg]
|
|
149
|
-
if not _result_re.search(msg.text): return [msg]
|
|
150
|
-
res, asst_parts, tool_parts = [], [], []
|
|
151
|
-
for msg_part in msg.content:
|
|
152
|
-
if msg_part.type == PartType.thinking: asst_parts.append(msg_part)
|
|
153
|
-
elif msg_part.type == PartType.tool_use: tool_parts.append(msg_part)
|
|
154
|
-
elif parts := _result_re.split(msg_part.text or ''):
|
|
155
|
-
for i,p in enumerate(parts):
|
|
156
|
-
if not p: continue
|
|
157
|
-
if i % 2 == 0: res.append(Msg(role='assistant', content=asst_parts+[Part(type=PartType.text, text=p.strip())]))
|
|
158
|
-
else: res.append(Msg(role='user', content=[Part(type=PartType.text, text=_mk_result_fence(p))]))
|
|
159
|
-
if tool_parts: res.append(Msg(role='assistant', content=tool_parts))
|
|
160
|
-
return res
|
|
161
|
-
|
|
162
|
-
def _split_fence_msgs(msgs):
|
|
163
|
-
"Split all assistant msgs on result fences for wire protocol"
|
|
164
|
-
res = []
|
|
165
|
-
for m in msgs: res.extend(_split_msg_on_fences(m))
|
|
166
|
-
return res
|
|
167
|
-
|
|
168
|
-
# %% ../nbs/07_chat.ipynb #45ada210
|
|
169
|
-
def _extract_tool_parts(text:str):
|
|
170
|
-
"Extract (tool_use_part, tool_result_part) from <details> json block"
|
|
171
|
-
try: d = json.loads(text.strip())
|
|
172
|
-
except: return None
|
|
173
|
-
call = d['call']
|
|
174
|
-
# Skip server tool calls in deserialization (round trip issues with Gemini/Anthropic)
|
|
175
|
-
if d.get('server'): return None
|
|
176
|
-
tu = Part(type=PartType.tool_use, text=None, data=dict(id=d['id'], name=call['function'], arguments=call['arguments']))
|
|
177
|
-
tr = Part(type=PartType.tool_result, text=str(d['result']), data={'id': d['id'], 'name': call['function']})
|
|
178
|
-
return tu, tr
|
|
179
|
-
|
|
180
|
-
def split_tools(s):
|
|
181
|
-
"Split formatted output into (text, summary, tooljson) chunks"
|
|
182
|
-
return [(txt,summ,tj) for txt,_,summ,tj in chunked(re_tools.split(s.strip()), 4, pad=True)]
|
|
183
|
-
|
|
184
|
-
# %% ../nbs/07_chat.ipynb #44060a78
|
|
185
|
-
def fmt2hist(outp:str)->list[Msg]:
|
|
186
|
-
"Transform a formatted output string into fastllm canonical Msgs"
|
|
187
|
-
if token_dtls_tag in outp: outp = re_token.sub('', outp)
|
|
188
|
-
if think_start in outp: outp = re_think.sub('', outp)
|
|
189
|
-
if tool_dtls_tag not in outp:
|
|
190
|
-
msg = Msg(role='assistant', content=[Part(type=PartType.text, text=outp.strip() or '.')])
|
|
191
|
-
return _split_msg_on_fences(msg)
|
|
192
|
-
hist, asst_parts, tool_parts = [], [], []
|
|
193
|
-
def flush():
|
|
194
|
-
if tool_parts:
|
|
195
|
-
hist.append(Msg(role='assistant', content=asst_parts.copy()))
|
|
196
|
-
hist.append(Msg(role='tool', content=tool_parts.copy()))
|
|
197
|
-
asst_parts.clear()
|
|
198
|
-
tool_parts.clear()
|
|
199
|
-
for txt,_,tj in split_tools(outp):
|
|
200
|
-
if txt and txt.strip():
|
|
201
|
-
if tool_parts: flush()
|
|
202
|
-
asst_parts.append(Part(type=PartType.text, text=txt.strip() or '.'))
|
|
203
|
-
if tj and (tp := _extract_tool_parts(tj)):
|
|
204
|
-
asst_parts.append(tp[0])
|
|
205
|
-
tool_parts.append(tp[1])
|
|
206
|
-
flush()
|
|
207
|
-
if asst_parts: hist.append(Msg(role='assistant', content=asst_parts))
|
|
208
|
-
result = []
|
|
209
|
-
for msg in hist:
|
|
210
|
-
if msg.role == 'assistant': result.extend(_split_msg_on_fences(msg))
|
|
211
|
-
else: result.append(msg)
|
|
212
|
-
if result[-1].role == 'tool': result.append(Msg(role='assistant', content=[Part(type=PartType.text, text='.')]))
|
|
213
|
-
return result
|
|
214
|
-
|
|
215
|
-
# %% ../nbs/07_chat.ipynb #8de5ce8d
|
|
124
|
+
# %% ../nbs/07_chat.ipynb #01bd81de
|
|
216
125
|
def _apply_cache_idxs(msgs, cache_idxs=[-1], ttl=None):
|
|
217
126
|
"Add cache control to `cache_idxs` after filtering tool-role msgs"
|
|
218
127
|
ms = [j for j,m in enumerate(msgs) if m.role != 'tool']
|
|
@@ -221,7 +130,7 @@ def _apply_cache_idxs(msgs, cache_idxs=[-1], ttl=None):
|
|
|
221
130
|
except IndexError: continue
|
|
222
131
|
_add_cache_control(msgs[idx], ttl)
|
|
223
132
|
|
|
224
|
-
# %% ../nbs/07_chat.ipynb #
|
|
133
|
+
# %% ../nbs/07_chat.ipynb #fcbb9f5d
|
|
225
134
|
def mk_msgs(
|
|
226
135
|
msgs, # List of messages (each: str, bytes, list, Msg, or Completion)
|
|
227
136
|
cache=False, # Enable Anthropic caching
|
|
@@ -231,7 +140,7 @@ def mk_msgs(
|
|
|
231
140
|
"Create a list of fastllm canonical Msgs."
|
|
232
141
|
if not msgs: return []
|
|
233
142
|
if not isinstance(msgs, list): msgs = [msgs]
|
|
234
|
-
msgs = L(msgs).map(lambda m: fmt2hist(m) if isinstance(m,str) and (
|
|
143
|
+
msgs = L(msgs).map(lambda m: fmt2hist(m) if isinstance(m,str) and (tool_info in m or usage_info in m) else [m]).concat()
|
|
235
144
|
res, role = [], 'user'
|
|
236
145
|
for m in msgs:
|
|
237
146
|
res.append(msg := remove_cache_ckpts(mk_msg(m, role=role)))
|
|
@@ -311,30 +220,8 @@ effort['x'] = 'max'
|
|
|
311
220
|
def _mk_prefill(pf): return dict(text=pf)
|
|
312
221
|
|
|
313
222
|
# %% ../nbs/07_chat.ipynb #dc17f844
|
|
314
|
-
class StopResponse(str): pass
|
|
315
|
-
class FullResponse(str): pass
|
|
316
|
-
|
|
317
223
|
def _has_stop(tres_parts): return any(isinstance(p.text, StopResponse) for p in tres_parts)
|
|
318
224
|
|
|
319
|
-
# %% ../nbs/07_chat.ipynb #f58ce348
|
|
320
|
-
def _trunc_str(s, mx=2000, skip=10, replace="TRUNCATED"):
|
|
321
|
-
"Truncate `s` to `mx` chars max, adding `replace` if truncated; `mx=None` disables truncation"
|
|
322
|
-
if mx is None or isinstance_str(s, ('FullResponse','Safe','PrettyString')): return s
|
|
323
|
-
if not isinstance(s, str): s = str(s)
|
|
324
|
-
s = type(s)(s.rstrip())
|
|
325
|
-
if len(s)>2 and s[0]=='𝍁' and s[-1]=='𝍁':
|
|
326
|
-
s = s[1:-1]
|
|
327
|
-
if replace: return s
|
|
328
|
-
if mx is None or len(s)<=mx: return s
|
|
329
|
-
s = s[skip:mx-skip]
|
|
330
|
-
ss = s.split(' ')
|
|
331
|
-
if len(ss[-1])>150: ss[-1] = ss[-1][:5]
|
|
332
|
-
s = ' '.join(ss)
|
|
333
|
-
if skip: s = f"…{s}"
|
|
334
|
-
s = f"{s}…"
|
|
335
|
-
if replace: s = f"<{replace}>{s}</{replace}>"
|
|
336
|
-
return s
|
|
337
|
-
|
|
338
225
|
# %% ../nbs/07_chat.ipynb #ca9e447e
|
|
339
226
|
_final_prompt = dict(role="user", content="You have used all your tool calls for this turn. Please summarize your findings. If you did not complete your goal, tell the user what further work is needed. You may use tools again on the next user message.")
|
|
340
227
|
|
|
@@ -379,8 +266,8 @@ class UsageStats:
|
|
|
379
266
|
|
|
380
267
|
def fmt(self):
|
|
381
268
|
if not self.total_tokens: return ''
|
|
382
|
-
|
|
383
|
-
return
|
|
269
|
+
d = {k:v for k,v in self.__dict__.items() if v and not k.startswith('_')}
|
|
270
|
+
return "\n\n" + fenced(dumps(d, ensure_ascii=False), usage_info) + "\n"
|
|
384
271
|
|
|
385
272
|
# %% ../nbs/07_chat.ipynb #cb3d7e77
|
|
386
273
|
class AsyncChat:
|
|
@@ -727,44 +614,13 @@ def _trunc_param(v, mx=40):
|
|
|
727
614
|
|
|
728
615
|
# %% ../nbs/07_chat.ipynb #80c0abdb
|
|
729
616
|
def _tc_summary(tr):
|
|
730
|
-
"Format tool call as func(params)
|
|
617
|
+
"Format tool call as a `func(params)→result` code span"
|
|
731
618
|
params = ', '.join(f"{k}={_trunc_param(v)}" for k,v in tr.data['arguments'].items())
|
|
732
619
|
res = f"→{_trunc_param(tr.text)}" if tr.text else ''
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
"Truncate tool result content, respecting '_full' flag"
|
|
738
|
-
if isinstance(content, dict) and '_full' in content and len(content)==1: return content['_full']
|
|
739
|
-
return _trunc_str(content, mx=mx)
|
|
740
|
-
|
|
741
|
-
# %% ../nbs/07_chat.ipynb #3602a033
|
|
742
|
-
def mk_tr_details(tr, mx=2000):
|
|
743
|
-
"Create <details> block for tool call as JSON; `mx=None` disables truncation"
|
|
744
|
-
args = {k:_trunc_str(v, mx=None if mx is None else mx*5) if isinstance(v, str) else v for k,v in tr.data['arguments'].items()}
|
|
745
|
-
res = {'id':tr.data['id'], 'server':tr.data.get('server', False),
|
|
746
|
-
'call':{'function': tr.data['name'], 'arguments': args},
|
|
747
|
-
'result':_trunc_content(tr.text, mx=mx),}
|
|
748
|
-
summ = f"<summary>{_tc_summary(tr)}</summary>"
|
|
749
|
-
return f"\n\n{tool_dtls_tag}\n{summ}\n\n```json\n{dumps(res, indent=2, ensure_ascii=False)}\n```\n\n</details>\n\n"
|
|
750
|
-
|
|
751
|
-
# %% ../nbs/07_chat.ipynb #ae9dfdb5
|
|
752
|
-
def hist2fmt(msgs:list[Msg], mx=2000)->str:
|
|
753
|
-
"Render assistant/tool `msgs` as one formatted output string, the inverse of `fmt2hist`"
|
|
754
|
-
tus, out = {}, []
|
|
755
|
-
for m in msgs:
|
|
756
|
-
if m.role == 'assistant':
|
|
757
|
-
for p in m.content:
|
|
758
|
-
if p.type == PartType.text and p.text: out.append(p.text.strip())
|
|
759
|
-
elif p.type == PartType.tool_use: tus[p.data['id']] = p
|
|
760
|
-
elif m.role == 'tool':
|
|
761
|
-
for p in m.content:
|
|
762
|
-
if p.type != PartType.tool_result: continue
|
|
763
|
-
tu = tus.get(p.data['id'])
|
|
764
|
-
d = dict(p.data, arguments=tu.data.get('arguments', {}) if tu else {})
|
|
765
|
-
out.append(mk_tr_details(Part(type=PartType.tool_result, text=p.text, data=d), mx=mx).strip())
|
|
766
|
-
else: raise ValueError(f"hist2fmt renders assistant and tool messages only, got {m.role!r}")
|
|
767
|
-
return '\n\n'.join(o for o in out if o)
|
|
620
|
+
txt = f"{tr.data['name']}({params}){res}"
|
|
621
|
+
ticks = '`'*(max(map(len, re.findall('`+', txt)), default=0)+1)
|
|
622
|
+
pad = ' ' if '`' in txt else ''
|
|
623
|
+
return f"{ticks}{pad}{txt}{pad}{ticks}"
|
|
768
624
|
|
|
769
625
|
# %% ../nbs/07_chat.ipynb #f0d984ec
|
|
770
626
|
class StreamFormatter:
|
fastllm/gemini.py
CHANGED
|
@@ -15,6 +15,7 @@ from fastcore.meta import *
|
|
|
15
15
|
from fastspec.errors import api_error_from_event
|
|
16
16
|
|
|
17
17
|
from .types import *
|
|
18
|
+
from aidialog.msg_parts import Part, PartType, Msg, ToolCall, sys_text, part_txt, data_url, url_mime
|
|
18
19
|
from .streaming import *
|
|
19
20
|
from .streaming import mk_acollect_stream
|
|
20
21
|
|
fastllm/openai_chat.py
CHANGED
|
@@ -14,6 +14,7 @@ from fastcore.meta import *
|
|
|
14
14
|
from fastspec.errors import api_error_from_event
|
|
15
15
|
|
|
16
16
|
from .types import *
|
|
17
|
+
from aidialog.msg_parts import Part, PartType, Msg, ToolCall, sys_text, part_txt, data_url
|
|
17
18
|
from .streaming import *
|
|
18
19
|
from .streaming import mk_acollect_stream
|
|
19
20
|
from .openai_responses import norm_usage
|
fastllm/openai_responses.py
CHANGED
|
@@ -15,6 +15,7 @@ from fastcore.meta import *
|
|
|
15
15
|
from fastspec.errors import api_error_from_event
|
|
16
16
|
|
|
17
17
|
from .types import *
|
|
18
|
+
from aidialog.msg_parts import Part, PartType, Msg, ToolCall, mk_tool_res_msg, sys_text, part_txt, data_url
|
|
18
19
|
from .streaming import *
|
|
19
20
|
from .streaming import mk_acollect_stream
|
|
20
21
|
|
fastllm/streaming.py
CHANGED
|
@@ -12,6 +12,7 @@ from fastcore.utils import *
|
|
|
12
12
|
from fastcore.meta import delegates
|
|
13
13
|
from fastspec.errors import *
|
|
14
14
|
from .types import *
|
|
15
|
+
from aidialog.msg_parts import Part, PartType, Msg, ToolCall, _fence_back
|
|
15
16
|
|
|
16
17
|
# %% ../nbs/01_streaming.ipynb #400d628a
|
|
17
18
|
@dataclass
|
fastllm/types.py
CHANGED
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/00_types.ipynb.
|
|
4
4
|
|
|
5
5
|
# %% auto #0
|
|
6
|
-
__all__ = ['
|
|
7
|
-
'
|
|
8
|
-
'model_info_registry', 'modern_llm', 'deepseek_v4_common', 'mimo_v25_common',
|
|
9
|
-
'
|
|
10
|
-
'
|
|
11
|
-
'
|
|
12
|
-
'
|
|
6
|
+
__all__ = ['FinishReason', 'api_registry', 'model_prices_url', 'haik45', 'sonn45', 'sonn46', 'sonn', 'sonn5', 'opus46', 'opus48',
|
|
7
|
+
'opus', 'opus5', 'fable', 'fable5', 'gpt54', 'gpt54m', 'gpt55', 'codex54', 'codex54m', 'codex55',
|
|
8
|
+
'codex53spark', 'model_info_registry', 'modern_llm', 'deepseek_v4_common', 'mimo_v25_common',
|
|
9
|
+
'codex_pricing', 'sol', 'terra', 'luna', 'gpt56s', 'Usage', 'Completion', 'APIRegistry', 'mk_completion',
|
|
10
|
+
'fn_schema', 'payload_kwargs', 'get_api_key', 'resize_b64', 'model_prices_meta', 'infer_api_name',
|
|
11
|
+
'get_model_meta', 'register_model_info', 'get_model_info', 'get_model_pricing', 'approx_pricing',
|
|
12
|
+
'is_deepseek_peak_hour']
|
|
13
13
|
|
|
14
14
|
# %% ../nbs/00_types.ipynb #b4d047fd
|
|
15
15
|
import httpx, base64, io
|
|
@@ -18,86 +18,8 @@ from datetime import datetime, timezone
|
|
|
18
18
|
from fastcore.net import urljson
|
|
19
19
|
from fastcore.utils import *
|
|
20
20
|
from PIL import Image as PImg
|
|
21
|
+
from aidialog.msg_parts import Part, PartType, Msg, ToolCall, data_url
|
|
21
22
|
|
|
22
|
-
# %% ../nbs/00_types.ipynb #e568bade
|
|
23
|
-
@dataclass
|
|
24
|
-
class Part:
|
|
25
|
-
"A normalized content part."
|
|
26
|
-
type: str
|
|
27
|
-
text: str = None
|
|
28
|
-
data: dict = None
|
|
29
|
-
|
|
30
|
-
# %% ../nbs/00_types.ipynb #aa3cfc23
|
|
31
|
-
PartType = str_enum('PartType', 'text', 'thinking', 'refusal', 'tool_use', 'server_tool_result', 'tool_result',
|
|
32
|
-
'input_image', 'input_audio', 'input_video', 'input_file')
|
|
33
|
-
|
|
34
|
-
# %% ../nbs/00_types.ipynb #2eeff103
|
|
35
|
-
def _trunc_strs(o, n=200):
|
|
36
|
-
"Truncate str or dict"
|
|
37
|
-
if not o: return o
|
|
38
|
-
if isinstance(o,str) and len(o)>n: return o[:100]+'...'
|
|
39
|
-
if isinstance(o,dict): return {k: (v[:100]+'...' if isinstance(v,str) and len(v)>n else v) for k,v in o.items()}
|
|
40
|
-
return o
|
|
41
|
-
|
|
42
|
-
@patch
|
|
43
|
-
def _repr_markdown_(self: Part):
|
|
44
|
-
body = _trunc_strs(self.text) if self.text else ''
|
|
45
|
-
data = _trunc_strs(self.data)
|
|
46
|
-
return f"""**Part** (`{self.type}`)
|
|
47
|
-
|
|
48
|
-
{body}
|
|
49
|
-
|
|
50
|
-
<details markdown='1'>
|
|
51
|
-
|
|
52
|
-
- data: `{data}`
|
|
53
|
-
|
|
54
|
-
</details>"""
|
|
55
|
-
|
|
56
|
-
# %% ../nbs/00_types.ipynb #afeb9eef
|
|
57
|
-
@dataclass
|
|
58
|
-
class Msg:
|
|
59
|
-
"A normalized message."
|
|
60
|
-
role: str
|
|
61
|
-
content: List[Part]
|
|
62
|
-
|
|
63
|
-
def _repr_markdown_(self):
|
|
64
|
-
return f"""**Msg**
|
|
65
|
-
|
|
66
|
-
- role: `{self.role}`
|
|
67
|
-
|
|
68
|
-
<contents>
|
|
69
|
-
|
|
70
|
-
{'\n\n'.join(p._repr_markdown_() for p in self.content)}
|
|
71
|
-
|
|
72
|
-
</contents>"""
|
|
73
|
-
|
|
74
|
-
# %% ../nbs/00_types.ipynb #f6d04920
|
|
75
|
-
@dataclass
|
|
76
|
-
class ToolCall:
|
|
77
|
-
"Normalized tool call."
|
|
78
|
-
id: str
|
|
79
|
-
name: str
|
|
80
|
-
arguments: dict = field(default_factory=dict)
|
|
81
|
-
server: bool = False
|
|
82
|
-
extra: dict = field(default_factory=dict)
|
|
83
|
-
|
|
84
|
-
# %% ../nbs/00_types.ipynb #509cfc99
|
|
85
|
-
@patch
|
|
86
|
-
def _repr_markdown_(self: ToolCall):
|
|
87
|
-
extra = _trunc_strs(self.extra)
|
|
88
|
-
return f"""🔧 **{self.name}**(`{self.arguments}`)
|
|
89
|
-
|
|
90
|
-
<details markdown='1'>
|
|
91
|
-
|
|
92
|
-
- id: `{self.id}`
|
|
93
|
-
- server: `{self.server}`
|
|
94
|
-
- extra: `{extra}`
|
|
95
|
-
|
|
96
|
-
</details>"""
|
|
97
|
-
|
|
98
|
-
def display_list(l):
|
|
99
|
-
from IPython.display import Markdown, display
|
|
100
|
-
display(Markdown('\n\n'.join(o._repr_markdown_() for o in l)))
|
|
101
23
|
|
|
102
24
|
# %% ../nbs/00_types.ipynb #802ad832
|
|
103
25
|
@dataclass(frozen=True)
|
|
@@ -177,15 +99,6 @@ def mk_completion(resp, model, api_name, vendor_name):
|
|
|
177
99
|
vendor_name=vendor_name,
|
|
178
100
|
raw=resp)
|
|
179
101
|
|
|
180
|
-
# %% ../nbs/00_types.ipynb #d5322db5
|
|
181
|
-
def mk_tool_res_msg(tool_calls:list[ToolCall], results:list[str|list]):
|
|
182
|
-
'A util to prepare parallel tool call with str or media list results'
|
|
183
|
-
parts = []
|
|
184
|
-
for tc,res in zip(tool_calls, results):
|
|
185
|
-
data = dict(id=tc.id, name=tc.name, arguments=tc.arguments, server=tc.server)
|
|
186
|
-
parts.append(Part(type=PartType.tool_result, text=res, data=data))
|
|
187
|
-
return Msg(role="tool", content=parts)
|
|
188
|
-
|
|
189
102
|
# %% ../nbs/00_types.ipynb #8a8e468b
|
|
190
103
|
def fn_schema(t):
|
|
191
104
|
"Extract (name, description, parameters) from any tool format."
|
|
@@ -196,46 +109,6 @@ def fn_schema(t):
|
|
|
196
109
|
return t.get('name',''), t.get('description',''), t.get('parameters', t.get('input_schema',{}))
|
|
197
110
|
return None
|
|
198
111
|
|
|
199
|
-
# %% ../nbs/00_types.ipynb #d1d48d91
|
|
200
|
-
def sys_text(system):
|
|
201
|
-
"Extract text from system (str or Part)."
|
|
202
|
-
if system is None: return None
|
|
203
|
-
return system if isinstance(system, str) else system.text
|
|
204
|
-
|
|
205
|
-
def part_txt(p): return p.text if isinstance(p,Part) else p
|
|
206
|
-
|
|
207
|
-
# %% ../nbs/00_types.ipynb #f3deb055
|
|
208
|
-
@flexicache(time_policy(24*3600))
|
|
209
|
-
def _fetch_url_partial(url, nbytes=512):
|
|
210
|
-
"Fetch remote media bytes, optionally only first `nbytes`."
|
|
211
|
-
try:
|
|
212
|
-
with httpx.stream('GET', url, headers={'Range': f'bytes=0-{nbytes-1}'}, follow_redirects=True) as r:
|
|
213
|
-
if r.status_code not in (200, 206): return
|
|
214
|
-
return r.read()
|
|
215
|
-
except (httpx.HTTPError, httpx.InvalidURL): return
|
|
216
|
-
|
|
217
|
-
# %% ../nbs/00_types.ipynb #70a9a0c3
|
|
218
|
-
_ext_mime = {
|
|
219
|
-
'.jpg':'image/jpeg', '.jpeg':'image/jpeg', '.png':'image/png', '.gif':'image/gif', '.webp':'image/webp',
|
|
220
|
-
'.pdf':'application/pdf',
|
|
221
|
-
'.mp3':'audio/mpeg', '.wav':'audio/wav', '.ogg':'audio/ogg', '.flac':'audio/flac', '.m4a':'audio/mp4',
|
|
222
|
-
'.mp4':'video/mp4', '.mov':'video/quicktime', '.webm':'video/webm',
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
def data_url(url):
|
|
226
|
-
"Parse data:mime;base64,data URL into (mime, b64_data), or None."
|
|
227
|
-
if not isinstance(url, str) or not url.startswith('data:') or ',' not in url: return None
|
|
228
|
-
header, body = url.split(',', 1)
|
|
229
|
-
if ';base64' not in header or not body: return None
|
|
230
|
-
return header[5:].split(';',1)[0].strip() or 'application/octet-stream', body
|
|
231
|
-
|
|
232
|
-
def url_mime(url, default='application/octet-stream'):
|
|
233
|
-
"Guess mime from URL extension, and optional bytes fallback."
|
|
234
|
-
if "youtube.com" in url or "youtu.be" in url: return "video/mp4"
|
|
235
|
-
ext = '.' + url.rsplit('.', 1)[-1].split('?')[0].lower() if '.' in url.split('?')[0].split('/')[-1] else ''
|
|
236
|
-
if (mime:=_ext_mime.get(ext)) is None: return detect_mime(_fetch_url_partial(url))
|
|
237
|
-
return ifnone(mime, default)
|
|
238
|
-
|
|
239
112
|
# %% ../nbs/00_types.ipynb #28c698fe
|
|
240
113
|
def payload_kwargs(msgs, model, stream=False, system=None, max_tokens=None, temperature=None, tools=None, tool_choice=None, reasoning_effort=None, web_search_options=None, stop_callables=None): pass
|
|
241
114
|
|
|
@@ -286,10 +159,12 @@ def get_model_meta(model, vendor_name=None, tfm=noop):
|
|
|
286
159
|
# %% ../nbs/00_types.ipynb #60607e23
|
|
287
160
|
haik45 = "claude-haiku-4-5"
|
|
288
161
|
sonn45 = "claude-sonnet-4-5"
|
|
289
|
-
|
|
290
|
-
sonn5 = "claude-sonnet-5"
|
|
162
|
+
sonn46 = "claude-sonnet-4-6"
|
|
163
|
+
sonn = sonn5 = "claude-sonnet-5"
|
|
291
164
|
opus46 = "claude-opus-4-6"
|
|
292
|
-
|
|
165
|
+
opus48 = "claude-opus-4-8"
|
|
166
|
+
opus = opus5 = "claude-opus-5"
|
|
167
|
+
fable = fable5 = 'claude-fable-5'
|
|
293
168
|
gpt54 = "gpt-5.4"
|
|
294
169
|
gpt54m = "gpt-5.4-mini"
|
|
295
170
|
gpt55 = "gpt-5.5"
|
|
@@ -314,9 +189,6 @@ def get_model_info(mn, vendor_name=None):
|
|
|
314
189
|
if 'search_context_cost_per_query' in info: info['supports_web_search'] = True
|
|
315
190
|
return dict2obj(info)
|
|
316
191
|
|
|
317
|
-
# %% ../nbs/00_types.ipynb #331c5d0a
|
|
318
|
-
register_model_info("claude-opus-4-8", vendor_name='anthropic', base="claude-opus-4-6")
|
|
319
|
-
|
|
320
192
|
# %% ../nbs/00_types.ipynb #b36178d4
|
|
321
193
|
modern_llm = dict(supports_function_calling=True, supports_tool_choice=True, supports_prompt_caching=True,
|
|
322
194
|
supports_parallel_function_calling=True, supports_native_streaming=True, supports_native_structured_output=True,
|
|
@@ -387,10 +259,6 @@ register_model_info('mimo-v2.5-pro-ultraspeed', vendor_name='mimo', **mimo_v25_c
|
|
|
387
259
|
# %% ../nbs/00_types.ipynb #defb1c5c
|
|
388
260
|
register_model_info('MiniMax-M3', vendor_name='minimax', **modern_llm, max_input_tokens=512_000, max_output_tokens=512_000, max_tokens=512_000, input_cost_per_token=0.3e-6, output_cost_per_token=1.2e-6, cache_read_input_token_cost=0.06e-6, supports_vision=True, supports_video_input=True)
|
|
389
261
|
|
|
390
|
-
register_model_info('claude-fable-5', vendor_name='anthropic', base="claude-opus-4-8",
|
|
391
|
-
input_cost_per_token=10e-6, cache_creation_input_token_cost=12.5e-6, output_cost_per_token=50e-6,
|
|
392
|
-
cache_read_input_token_cost=1e-6, search_context_cost_per_query=0.005)
|
|
393
|
-
|
|
394
262
|
# %% ../nbs/00_types.ipynb #4e1b40b3
|
|
395
263
|
register_model_info('muse-spark-1.1', vendor_name='meta_ai', **modern_llm,
|
|
396
264
|
max_input_tokens=1_048_576, max_output_tokens=128000, max_tokens=128000,
|
|
@@ -411,12 +279,9 @@ register_model_info(codex53spark, 'codex', **codex_pricing,
|
|
|
411
279
|
max_tokens=128000, max_input_tokens=128000, max_output_tokens=128000)
|
|
412
280
|
|
|
413
281
|
# %% ../nbs/00_types.ipynb #5d3e4720
|
|
414
|
-
for model in (haik45, sonn45, sonn46, sonn5, opus46,
|
|
282
|
+
for model in (haik45, sonn45, sonn46, sonn5, opus46, opus48, opus5, fable5):
|
|
415
283
|
register_model_info(model, 'claude_code', base=model, base_vendor_name='anthropic', **codex_pricing)
|
|
416
284
|
|
|
417
|
-
# %% ../nbs/00_types.ipynb #60630540
|
|
418
|
-
register_model_info(sonn5, base=sonn5, max_input_tokens=760_000)
|
|
419
|
-
|
|
420
285
|
# %% ../nbs/00_types.ipynb #bb0c4c2a
|
|
421
286
|
sol,terra,luna = gpt56s = 'gpt-5.6-sol gpt-5.6-terra gpt-5.6-luna'.split()
|
|
422
287
|
for model in ['gpt-5.6']+gpt56s:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-fastllm
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.33
|
|
4
4
|
Author-email: Kerem Turgutlu <keremturgutlu@gmail.com>
|
|
5
5
|
License: Apache-2.0
|
|
6
6
|
Project-URL: Repository, https://github.com/AnswerDotAI/fastllm
|
|
@@ -9,6 +9,8 @@ Classifier: Programming Language :: Python :: 3
|
|
|
9
9
|
Classifier: Programming Language :: Python :: 3 :: Only
|
|
10
10
|
Requires-Python: >=3.10
|
|
11
11
|
Description-Content-Type: text/markdown
|
|
12
|
+
Requires-Dist: fastcore>=2.1.11
|
|
13
|
+
Requires-Dist: aidialog>=0.0.3
|
|
12
14
|
Requires-Dist: fastspec>=0.0.11
|
|
13
15
|
Requires-Dist: toolslm
|
|
14
16
|
Requires-Dist: pillow
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
fastllm/__init__.py,sha256=AGWXI5DVsNfiiV5VgHNNK08ZPMOHqnJB3xLlEoyC3hg,23
|
|
2
|
+
fastllm/_modidx.py,sha256=4WFucmoHE-R_z1fXpcAIFu1dPG79f0qhVxadj9IECFs,32065
|
|
3
|
+
fastllm/acomplete.py,sha256=dkocdUEwHIfTW70XaBX2yQwl5qpvVbWkGRUOYVNphFA,10171
|
|
4
|
+
fastllm/anthropic.py,sha256=vlfXK9KotK0pUUwilSRMYDYS8qmE8n1ReQVu6fR0J-k,15524
|
|
5
|
+
fastllm/chat.py,sha256=Gma7TIsBqtaoDfkGQJabrT9lK97S2QNyQe6NdkCRePY,30957
|
|
6
|
+
fastllm/codex.py,sha256=HZchfrGUgdf8ayhtOFbIRmh9YmIqfQBwqviAEeir4Uo,161
|
|
7
|
+
fastllm/gemini.py,sha256=DXEKu7tlYJ0MCSHF2RKEjrT0-JDRVgZXmjt4JLYDR1A,15145
|
|
8
|
+
fastllm/openai_chat.py,sha256=mvmQQHgyZm7Cs1K2YQWzZQyXzA6gwximmwbYpAqk5-E,11056
|
|
9
|
+
fastllm/openai_responses.py,sha256=nWrGzPAmGauPHE52MeFSyBUu-HMB5dSmaCJR7jigbP0,13415
|
|
10
|
+
fastllm/streaming.py,sha256=WYDGfyVtCj-5VFTpbPa6jSvVFYRMSSSaks0AdPC5zqI,7671
|
|
11
|
+
fastllm/types.py,sha256=rtkutVi2-XsVXHnvdcdTLnnyRLagjm_uT7CuAz4ZjMs,16190
|
|
12
|
+
fastllm/specs/anthropic.json,sha256=VCgTjM2_HoDpCkeu3q_TCOEZLMHriJZLAG3LnDBAgGM,541035
|
|
13
|
+
fastllm/specs/anthropic.yml,sha256=3S3NAKdXB1Nwp-Sn9Gmh4tBnwhGGhMO3DXkGqPXPUYs,724122
|
|
14
|
+
fastllm/specs/gemini.json,sha256=zJGOdvZ2BvCiTENZt0-BDEvNBMl8h6EBmEskle_WBto,309331
|
|
15
|
+
fastllm/specs/openai.with-code-samples.json,sha256=Kto19AW1u8MfxVDJ4cFVBIdZQOIyy8NWylswo57eABU,1995929
|
|
16
|
+
fastllm/specs/openai.with-code-samples.yml,sha256=DlcWGdaeP4k7smVjt6UbyehJ-2XGU3rn3nCIBMDRfYU,2553630
|
|
17
|
+
fastllm/specs/spec_manifest.json,sha256=9tVFwojXFnNqsAxQzCRTP1lgSIM0fXixnrXdv4Cmb0c,653
|
|
18
|
+
python_fastllm-0.0.33.dist-info/METADATA,sha256=PljSw249JcQWy2eqhFRgs54NSCkkbWTm1Y33zxURbXc,19640
|
|
19
|
+
python_fastllm-0.0.33.dist-info/WHEEL,sha256=K260EYznzXsJYBQGqmI8VTxEdiZYNvDZwW9cBh9-_MA,91
|
|
20
|
+
python_fastllm-0.0.33.dist-info/entry_points.txt,sha256=_cVRbpVkvyxdZfR7UCXa0lIXZtTSsZQWoBPhDwMqrHs,80
|
|
21
|
+
python_fastllm-0.0.33.dist-info/top_level.txt,sha256=F8qodL7nEGUHGmzzqfhNKCTIr1i0D6cvudOnm3z7o0Y,8
|
|
22
|
+
python_fastllm-0.0.33.dist-info/RECORD,,
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
fastllm/__init__.py,sha256=YRrMDApG1V6fNZdI4BA631DmsqtamSXgI1yu0tnt4h0,23
|
|
2
|
-
fastllm/_modidx.py,sha256=WKjTRVleZUXLBysnrvwkWRkSMk09mnbUO1NSoxhM5Ng,35217
|
|
3
|
-
fastllm/acomplete.py,sha256=iVowR8SjiDtJsCnIWQuxkzGszG9S9aakPXo7EkxRu34,10103
|
|
4
|
-
fastllm/anthropic.py,sha256=OHyazPPsXro3ooS0dBy-tk2g8fwXaAS_Cq-7hnc4E6M,15453
|
|
5
|
-
fastllm/chat.py,sha256=j2COIPPRJUVy__y4BZgG73WmfWu68kmRlXMbRsBXG7w,37910
|
|
6
|
-
fastllm/codex.py,sha256=HZchfrGUgdf8ayhtOFbIRmh9YmIqfQBwqviAEeir4Uo,161
|
|
7
|
-
fastllm/gemini.py,sha256=Zw6zIsaQ0yht2qNyuntcaNFDPpGPO3sfi6v_izzXd_4,15044
|
|
8
|
-
fastllm/openai_chat.py,sha256=b3JHumjX-DAxLB02IeKjcUeUkpM7k4SLQ_qdvcfDcwk,10965
|
|
9
|
-
fastllm/openai_responses.py,sha256=5oUtrYtSd4WChkGhwmVC7LilPAguTx0EnpH4lEqYP40,13307
|
|
10
|
-
fastllm/streaming.py,sha256=mDyaK2JJ5mIjtS0SkAx-iFFL0cN4XkXcdWHaY8w5H3M,7597
|
|
11
|
-
fastllm/types.py,sha256=K0kg_ZCZXteSgrdhOF_K9S9dgcSKjAUhKUGhxRYrtmY,20790
|
|
12
|
-
fastllm/specs/anthropic.json,sha256=VCgTjM2_HoDpCkeu3q_TCOEZLMHriJZLAG3LnDBAgGM,541035
|
|
13
|
-
fastllm/specs/anthropic.yml,sha256=3S3NAKdXB1Nwp-Sn9Gmh4tBnwhGGhMO3DXkGqPXPUYs,724122
|
|
14
|
-
fastllm/specs/gemini.json,sha256=zJGOdvZ2BvCiTENZt0-BDEvNBMl8h6EBmEskle_WBto,309331
|
|
15
|
-
fastllm/specs/openai.with-code-samples.json,sha256=Kto19AW1u8MfxVDJ4cFVBIdZQOIyy8NWylswo57eABU,1995929
|
|
16
|
-
fastllm/specs/openai.with-code-samples.yml,sha256=DlcWGdaeP4k7smVjt6UbyehJ-2XGU3rn3nCIBMDRfYU,2553630
|
|
17
|
-
fastllm/specs/spec_manifest.json,sha256=9tVFwojXFnNqsAxQzCRTP1lgSIM0fXixnrXdv4Cmb0c,653
|
|
18
|
-
python_fastllm-0.0.31.dist-info/METADATA,sha256=PAIJ578D91vgJFwwnDGYDCsPDmMMM6HEZdpERIRYwcg,19577
|
|
19
|
-
python_fastllm-0.0.31.dist-info/WHEEL,sha256=K260EYznzXsJYBQGqmI8VTxEdiZYNvDZwW9cBh9-_MA,91
|
|
20
|
-
python_fastllm-0.0.31.dist-info/entry_points.txt,sha256=_cVRbpVkvyxdZfR7UCXa0lIXZtTSsZQWoBPhDwMqrHs,80
|
|
21
|
-
python_fastllm-0.0.31.dist-info/top_level.txt,sha256=F8qodL7nEGUHGmzzqfhNKCTIr1i0D6cvudOnm3z7o0Y,8
|
|
22
|
-
python_fastllm-0.0.31.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|