python-fastllm 0.0.22__tar.gz → 0.0.24__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.
- {python_fastllm-0.0.22 → python_fastllm-0.0.24}/PKG-INFO +1 -1
- python_fastllm-0.0.24/fastllm/__init__.py +1 -0
- {python_fastllm-0.0.22 → python_fastllm-0.0.24}/fastllm/acomplete.py +7 -1
- {python_fastllm-0.0.22 → python_fastllm-0.0.24}/fastllm/chat.py +28 -17
- {python_fastllm-0.0.22 → python_fastllm-0.0.24}/fastllm/types.py +4 -0
- {python_fastllm-0.0.22 → python_fastllm-0.0.24}/python_fastllm.egg-info/PKG-INFO +1 -1
- python_fastllm-0.0.22/fastllm/__init__.py +0 -1
- {python_fastllm-0.0.22 → python_fastllm-0.0.24}/README.md +0 -0
- {python_fastllm-0.0.22 → python_fastllm-0.0.24}/fastllm/_modidx.py +0 -0
- {python_fastllm-0.0.22 → python_fastllm-0.0.24}/fastllm/anthropic.py +0 -0
- {python_fastllm-0.0.22 → python_fastllm-0.0.24}/fastllm/codex.py +0 -0
- {python_fastllm-0.0.22 → python_fastllm-0.0.24}/fastllm/gemini.py +0 -0
- {python_fastllm-0.0.22 → python_fastllm-0.0.24}/fastllm/openai_chat.py +0 -0
- {python_fastllm-0.0.22 → python_fastllm-0.0.24}/fastllm/openai_responses.py +0 -0
- {python_fastllm-0.0.22 → python_fastllm-0.0.24}/fastllm/specs/anthropic.json +0 -0
- {python_fastllm-0.0.22 → python_fastllm-0.0.24}/fastllm/specs/anthropic.yml +0 -0
- {python_fastllm-0.0.22 → python_fastllm-0.0.24}/fastllm/specs/gemini.json +0 -0
- {python_fastllm-0.0.22 → python_fastllm-0.0.24}/fastllm/specs/openai.with-code-samples.json +0 -0
- {python_fastllm-0.0.22 → python_fastllm-0.0.24}/fastllm/specs/openai.with-code-samples.yml +0 -0
- {python_fastllm-0.0.22 → python_fastllm-0.0.24}/fastllm/specs/spec_manifest.json +0 -0
- {python_fastllm-0.0.22 → python_fastllm-0.0.24}/fastllm/streaming.py +0 -0
- {python_fastllm-0.0.22 → python_fastllm-0.0.24}/pyproject.toml +0 -0
- {python_fastllm-0.0.22 → python_fastllm-0.0.24}/python_fastllm.egg-info/SOURCES.txt +0 -0
- {python_fastllm-0.0.22 → python_fastllm-0.0.24}/python_fastllm.egg-info/dependency_links.txt +0 -0
- {python_fastllm-0.0.22 → python_fastllm-0.0.24}/python_fastllm.egg-info/entry_points.txt +0 -0
- {python_fastllm-0.0.22 → python_fastllm-0.0.24}/python_fastllm.egg-info/requires.txt +0 -0
- {python_fastllm-0.0.22 → python_fastllm-0.0.24}/python_fastllm.egg-info/top_level.txt +0 -0
- {python_fastllm-0.0.22 → python_fastllm-0.0.24}/setup.cfg +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.0.24"
|
|
@@ -144,6 +144,13 @@ async def acomplete(msgs, model, api_name=None, vendor_name=None, api_key=None,
|
|
|
144
144
|
base_url=None, xtra_body=None, xtra_hdrs=None, stream=False,
|
|
145
145
|
stop_callables=None, retries=2, retry_delay=0.5, **kwargs):
|
|
146
146
|
"Unified completion across different APIs."
|
|
147
|
+
if api_name == 'claude_code':
|
|
148
|
+
if not stream: raise NotImplementedError("claude_code backend supports stream=True only for now")
|
|
149
|
+
api = api_registry.apis[api_name]
|
|
150
|
+
payload = api.mk_payload(msgs, model, stream=stream, **kwargs)
|
|
151
|
+
async def _mk_gen():
|
|
152
|
+
async for o in api.acollect_stream(payload, model=model, vendor_name='claude_code', stop_callables=stop_callables): yield o
|
|
153
|
+
return _retry_stream(_mk_gen, retries, retry_delay)
|
|
147
154
|
cli, api_name, vendor_name = mk_client(model, vendor_name, api_name, api_key, base_url, xtra_hdrs)
|
|
148
155
|
api = api_registry.apis[api_name]
|
|
149
156
|
payload = api.mk_payload(msgs, model, stream=stream, **kwargs)
|
|
@@ -164,5 +171,4 @@ async def acomplete(msgs, model, api_name=None, vendor_name=None, api_key=None,
|
|
|
164
171
|
async def _mk_gen():
|
|
165
172
|
resp = await _call()
|
|
166
173
|
async for o in api.acollect_stream(resp, model=model, vendor_name=vendor_name, stop_callables=stop_callables): yield o
|
|
167
|
-
|
|
168
174
|
return _retry_stream(_mk_gen, retries, retry_delay)
|
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/07_chat.ipynb.
|
|
4
4
|
|
|
5
5
|
# %% auto #0
|
|
6
|
-
__all__ = ['tool_dtls_tag', 're_tools', 'token_dtls_tag', 're_token', '
|
|
7
|
-
'
|
|
8
|
-
'
|
|
9
|
-
'
|
|
10
|
-
'
|
|
11
|
-
'
|
|
12
|
-
'AsyncStreamFormatter', 'adisplay_stream']
|
|
6
|
+
__all__ = ['tool_dtls_tag', 're_tools', 'token_dtls_tag', 're_token', 'think_start', 'think_end', 're_think', 'effort',
|
|
7
|
+
'MediaUrl', 'remove_cache_ckpts', 'contents', 'stop_reason', 'mk_msg', 'FenceToolStop', 'extract_fence_call',
|
|
8
|
+
'split_tools', 'fmt2hist', 'mk_msgs', 'cite_footnote', 'postproc', 'lite_mk_func', 'ToolResponse',
|
|
9
|
+
'structured', 'StopResponse', 'FullResponse', 'search_count', 'UsageStats', 'AsyncChat',
|
|
10
|
+
'astream_with_complete', 'ChatCallback', 'DeepseekMsgsCallback', 'DeepseekPrefillCallback', 'add_warning',
|
|
11
|
+
'StopReasonCallback', 'run_fence_tool', 'FenceToolCallback', 'ToolReminderCallback', 'stop_sequences',
|
|
12
|
+
'StopSequencesCallback', 'mk_tr_details', 'StreamFormatter', 'AsyncStreamFormatter', 'adisplay_stream']
|
|
13
13
|
|
|
14
14
|
# %% ../nbs/07_chat.ipynb #d5a3bc1f
|
|
15
15
|
import asyncio, base64, json, mimetypes, random, string, ast, warnings
|
|
@@ -111,6 +111,8 @@ re_tools = re.compile(fr"^({tool_dtls_tag}\n*(?:<summary>(?P<summary>.*?)</summa
|
|
|
111
111
|
token_dtls_tag = "<details class='token-usage-details' markdown='1'>"
|
|
112
112
|
re_token = re.compile(fr"^{re.escape(token_dtls_tag)}\n*<summary>.*?</summary>\n*\n*`.*?`\n*\n*</details>\n?",
|
|
113
113
|
flags=re.DOTALL|re.MULTILINE)
|
|
114
|
+
think_start,think_end = '<!--think_start-->','<!--think_end-->'
|
|
115
|
+
re_think = re.compile(rf'{re.escape(think_start)}.*?{re.escape(think_end)}\n?', re.DOTALL)
|
|
114
116
|
|
|
115
117
|
# %% ../nbs/07_chat.ipynb #be998131
|
|
116
118
|
_fence_back = '`````'
|
|
@@ -182,6 +184,7 @@ def split_tools(s):
|
|
|
182
184
|
def fmt2hist(outp:str)->list[Msg]:
|
|
183
185
|
"Transform a formatted output string into fastllm canonical Msgs"
|
|
184
186
|
if token_dtls_tag in outp: outp = re_token.sub('', outp)
|
|
187
|
+
if think_start in outp: outp = re_think.sub('', outp)
|
|
185
188
|
if tool_dtls_tag not in outp:
|
|
186
189
|
msg = Msg(role='assistant', content=[Part(type=PartType.text, text=outp.strip() or '.')])
|
|
187
190
|
return _split_msg_on_fences(msg)
|
|
@@ -345,13 +348,13 @@ def search_count(r):
|
|
|
345
348
|
|
|
346
349
|
# %% ../nbs/07_chat.ipynb #61395e0d
|
|
347
350
|
class UsageStats:
|
|
348
|
-
def __init__(self, prompt_tokens=0, completion_tokens=0, total_tokens=0, cached_tokens=0, cache_creation_tokens=0, reasoning_tokens=0, web_search_requests=0, cost=0.0): store_attr()
|
|
351
|
+
def __init__(self, model='', prompt_tokens=0, completion_tokens=0, total_tokens=0, cached_tokens=0, cache_creation_tokens=0, reasoning_tokens=0, web_search_requests=0, cost=0.0): store_attr()
|
|
349
352
|
|
|
350
353
|
@classmethod
|
|
351
354
|
def from_response(cls, r):
|
|
352
355
|
u = r.usage
|
|
353
356
|
return cls(
|
|
354
|
-
prompt_tokens=u.prompt_tokens or 0, completion_tokens=u.completion_tokens or 0, total_tokens=u.total_tokens or 0,
|
|
357
|
+
model=r.model or '', prompt_tokens=u.prompt_tokens or 0, completion_tokens=u.completion_tokens or 0, total_tokens=u.total_tokens or 0,
|
|
355
358
|
cached_tokens=u.cached_tokens or 0, cache_creation_tokens=u.cache_creation_tokens or 0, reasoning_tokens=u.reasoning_tokens or 0,
|
|
356
359
|
web_search_requests=search_count(r), cost=r.cost)
|
|
357
360
|
|
|
@@ -359,7 +362,7 @@ class UsageStats:
|
|
|
359
362
|
if other is None: return self
|
|
360
363
|
return UsageStats(**{k: getattr(self, k, 0) + getattr(other, k, 0)
|
|
361
364
|
for k in ('prompt_tokens', 'completion_tokens', 'total_tokens', 'cached_tokens', 'cache_creation_tokens', 'reasoning_tokens', 'web_search_requests', 'cost')
|
|
362
|
-
})
|
|
365
|
+
}, model=other.model or self.model)
|
|
363
366
|
def __radd__(self, other): return self if other is None or other == 0 else self.__add__(other)
|
|
364
367
|
|
|
365
368
|
def __repr__(self):
|
|
@@ -369,6 +372,7 @@ class UsageStats:
|
|
|
369
372
|
if self.reasoning_tokens: parts.append(f"reasoning={self.reasoning_tokens:,}")
|
|
370
373
|
if getattr(self, 'web_search_requests', None): parts.append(f"searches={self.web_search_requests}")
|
|
371
374
|
if self.cost: parts.append(f"${self.cost:.4f}")
|
|
375
|
+
if self.model: parts.append(self.model.split('/')[-1])
|
|
372
376
|
return ' | '.join(parts)
|
|
373
377
|
|
|
374
378
|
def fmt(self):
|
|
@@ -740,35 +744,42 @@ def mk_tr_details(tr, mx=2000):
|
|
|
740
744
|
# %% ../nbs/07_chat.ipynb #f0d984ec
|
|
741
745
|
class StreamFormatter:
|
|
742
746
|
def __init__(self, mx=2000, debug=False, showthink=False):
|
|
743
|
-
self.outp,self.tcs = '',{}
|
|
747
|
+
self.outp,self.tcs,self._in_think = '',{},False
|
|
744
748
|
store_attr()
|
|
745
749
|
|
|
746
750
|
def format_item(self, o):
|
|
747
751
|
"Format a single item from the response stream."
|
|
748
752
|
res = ''
|
|
749
753
|
if self.debug: print(o)
|
|
754
|
+
is_think = isinstance(o, dict) and o.get('thinking')
|
|
755
|
+
if not is_think and self._in_think: res += f'\n\n</details>\n{think_end}\n\n'; self._in_think = False
|
|
750
756
|
if isinstance(o, dict):
|
|
751
757
|
if thk:=o.get('thinking'):
|
|
752
|
-
if self.showthink:
|
|
753
|
-
|
|
758
|
+
if self.showthink:
|
|
759
|
+
if not self._in_think:
|
|
760
|
+
res += f'\n{think_start}\n<details><summary>Thinking</summary>\n\n'
|
|
761
|
+
self._in_think = True
|
|
762
|
+
res += thk
|
|
763
|
+
else: res+= '🧠' if not self.outp or self.outp[-1]=='🧠' else '\n\n🧠'
|
|
754
764
|
elif self.outp and self.outp[-1] == '🧠': res+= '\n\n'
|
|
755
765
|
if txt:=o.get('text'): res+=f"\n\n{txt}" if res and res[-1] == '🧠' else txt
|
|
756
|
-
if isinstance(o, Part)
|
|
757
|
-
res += f"\n- ⏳ {_tc_summary(o)} ⏳\n"
|
|
758
|
-
|
|
759
|
-
res += mk_tr_details(o,mx=self.mx)
|
|
766
|
+
if isinstance(o, Part):
|
|
767
|
+
if o.type==PartType.tool_use: res += f"\n- ⏳ {_tc_summary(o)} ⏳\n"
|
|
768
|
+
elif o.type==PartType.tool_result: res += mk_tr_details(o,mx=self.mx)
|
|
760
769
|
self.outp+=res
|
|
761
770
|
return res
|
|
762
771
|
|
|
763
772
|
def format_stream(self, rs):
|
|
764
773
|
"Format the response stream for markdown display."
|
|
765
774
|
for o in rs: yield self.format_item(o)
|
|
775
|
+
if self._in_think: yield f'\n\n</details>\n{think_end}\n\n'
|
|
766
776
|
|
|
767
777
|
# %% ../nbs/07_chat.ipynb #0cdd4d7c
|
|
768
778
|
class AsyncStreamFormatter(StreamFormatter):
|
|
769
779
|
async def format_stream(self, rs):
|
|
770
780
|
"Format the response stream for markdown display."
|
|
771
781
|
async for o in rs: yield self.format_item(o)
|
|
782
|
+
if self._in_think: yield f'\n\n</details>\n{think_end}\n\n'
|
|
772
783
|
|
|
773
784
|
# %% ../nbs/07_chat.ipynb #944bcd25
|
|
774
785
|
@delegates(AsyncStreamFormatter)
|
|
@@ -397,6 +397,10 @@ register_model_info(codex53spark, 'codex', **codex_pricing,
|
|
|
397
397
|
supports_vision=False, supports_image_input=False, supports_web_search=True, supports_reasoning=True, supports_function_calling=True,
|
|
398
398
|
max_tokens=128000, max_input_tokens=128000, max_output_tokens=128000)
|
|
399
399
|
|
|
400
|
+
# %% ../nbs/00_types.ipynb #5d3e4720
|
|
401
|
+
for model in (haik45, sonn45, sonn46, opus46, opus):
|
|
402
|
+
register_model_info(model, 'claude_code', base=model, base_vendor_name='anthropic', **codex_pricing)
|
|
403
|
+
|
|
400
404
|
# %% ../nbs/00_types.ipynb #24cc47ec
|
|
401
405
|
def get_model_pricing(mn, vendor_name, million=True):
|
|
402
406
|
return {k:round(v * (1e6 if million else 1), 6)
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.0.22"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_fastllm-0.0.22 → python_fastllm-0.0.24}/python_fastllm.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|