python-fastllm 0.0.38__tar.gz → 0.0.39__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.38 → python_fastllm-0.0.39}/PKG-INFO +2 -2
- python_fastllm-0.0.39/fastllm/__init__.py +1 -0
- {python_fastllm-0.0.38 → python_fastllm-0.0.39}/fastllm/_modidx.py +14 -13
- {python_fastllm-0.0.38 → python_fastllm-0.0.39}/fastllm/acomplete.py +2 -1
- {python_fastllm-0.0.38 → python_fastllm-0.0.39}/fastllm/anthropic.py +37 -2
- {python_fastllm-0.0.38 → python_fastllm-0.0.39}/fastllm/chat.py +23 -114
- {python_fastllm-0.0.38 → python_fastllm-0.0.39}/fastllm/streaming.py +18 -19
- {python_fastllm-0.0.38 → python_fastllm-0.0.39}/fastllm/types.py +19 -41
- {python_fastllm-0.0.38 → python_fastllm-0.0.39}/pyproject.toml +1 -1
- {python_fastllm-0.0.38 → python_fastllm-0.0.39}/python_fastllm.egg-info/PKG-INFO +2 -2
- {python_fastllm-0.0.38 → python_fastllm-0.0.39}/python_fastllm.egg-info/requires.txt +1 -1
- python_fastllm-0.0.38/fastllm/__init__.py +0 -1
- {python_fastllm-0.0.38 → python_fastllm-0.0.39}/README.md +0 -0
- {python_fastllm-0.0.38 → python_fastllm-0.0.39}/fastllm/codex.py +0 -0
- {python_fastllm-0.0.38 → python_fastllm-0.0.39}/fastllm/gemini.py +0 -0
- {python_fastllm-0.0.38 → python_fastllm-0.0.39}/fastllm/openai_chat.py +0 -0
- {python_fastllm-0.0.38 → python_fastllm-0.0.39}/fastllm/openai_responses.py +0 -0
- {python_fastllm-0.0.38 → python_fastllm-0.0.39}/fastllm/specs/anthropic.json +0 -0
- {python_fastllm-0.0.38 → python_fastllm-0.0.39}/fastllm/specs/anthropic.yml +0 -0
- {python_fastllm-0.0.38 → python_fastllm-0.0.39}/fastllm/specs/gemini.json +0 -0
- {python_fastllm-0.0.38 → python_fastllm-0.0.39}/fastllm/specs/openai.with-code-samples.json +0 -0
- {python_fastllm-0.0.38 → python_fastllm-0.0.39}/fastllm/specs/openai.with-code-samples.yml +0 -0
- {python_fastllm-0.0.38 → python_fastllm-0.0.39}/fastllm/specs/spec_manifest.json +0 -0
- {python_fastllm-0.0.38 → python_fastllm-0.0.39}/python_fastllm.egg-info/SOURCES.txt +0 -0
- {python_fastllm-0.0.38 → python_fastllm-0.0.39}/python_fastllm.egg-info/dependency_links.txt +0 -0
- {python_fastllm-0.0.38 → python_fastllm-0.0.39}/python_fastllm.egg-info/entry_points.txt +0 -0
- {python_fastllm-0.0.38 → python_fastllm-0.0.39}/python_fastllm.egg-info/top_level.txt +0 -0
- {python_fastllm-0.0.38 → python_fastllm-0.0.39}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-fastllm
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.39
|
|
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
|
|
@@ -10,7 +10,7 @@ Classifier: Programming Language :: Python :: 3 :: Only
|
|
|
10
10
|
Requires-Python: >=3.10
|
|
11
11
|
Description-Content-Type: text/markdown
|
|
12
12
|
Requires-Dist: fastcore>=2.1.18
|
|
13
|
-
Requires-Dist: aidialog>=0.0.
|
|
13
|
+
Requires-Dist: aidialog>=0.0.10
|
|
14
14
|
Requires-Dist: fastspec>=0.0.11
|
|
15
15
|
Requires-Dist: pillow
|
|
16
16
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.0.39"
|
|
@@ -19,10 +19,12 @@ d = { 'settings': { 'branch': 'main',
|
|
|
19
19
|
'fastllm.acomplete.acomplete': ('acomplete.html#acomplete', 'fastllm/acomplete.py'),
|
|
20
20
|
'fastllm.acomplete.mk_client': ('acomplete.html#mk_client', 'fastllm/acomplete.py'),
|
|
21
21
|
'fastllm.acomplete.split_vendor': ('acomplete.html#split_vendor', 'fastllm/acomplete.py')},
|
|
22
|
-
'fastllm.anthropic': { 'fastllm.anthropic.
|
|
22
|
+
'fastllm.anthropic': { 'fastllm.anthropic._add_cache_control': ('anthropic.html#_add_cache_control', 'fastllm/anthropic.py'),
|
|
23
|
+
'fastllm.anthropic._ant_cc': ('anthropic.html#_ant_cc', 'fastllm/anthropic.py'),
|
|
23
24
|
'fastllm.anthropic._ant_part_type': ('anthropic.html#_ant_part_type', 'fastllm/anthropic.py'),
|
|
24
25
|
'fastllm.anthropic._sanid': ('anthropic.html#_sanid', 'fastllm/anthropic.py'),
|
|
25
26
|
'fastllm.anthropic.acollect_stream': ('anthropic.html#acollect_stream', 'fastllm/anthropic.py'),
|
|
27
|
+
'fastllm.anthropic.apply_cache_idxs': ('anthropic.html#apply_cache_idxs', 'fastllm/anthropic.py'),
|
|
26
28
|
'fastllm.anthropic.cost': ('anthropic.html#cost', 'fastllm/anthropic.py'),
|
|
27
29
|
'fastllm.anthropic.delta_index_fn': ('anthropic.html#delta_index_fn', 'fastllm/anthropic.py'),
|
|
28
30
|
'fastllm.anthropic.denorm_assistant': ('anthropic.html#denorm_assistant', 'fastllm/anthropic.py'),
|
|
@@ -66,9 +68,6 @@ d = { 'settings': { 'branch': 'main',
|
|
|
66
68
|
'fastllm.chat.DeepseekMsgsCallback': ('chat.html#deepseekmsgscallback', 'fastllm/chat.py'),
|
|
67
69
|
'fastllm.chat.DeepseekMsgsCallback.after_msgs': ( 'chat.html#deepseekmsgscallback.after_msgs',
|
|
68
70
|
'fastllm/chat.py'),
|
|
69
|
-
'fastllm.chat.DeepseekPrefillCallback': ('chat.html#deepseekprefillcallback', 'fastllm/chat.py'),
|
|
70
|
-
'fastllm.chat.DeepseekPrefillCallback.before_acomplete': ( 'chat.html#deepseekprefillcallback.before_acomplete',
|
|
71
|
-
'fastllm/chat.py'),
|
|
72
71
|
'fastllm.chat.FenceToolCallback': ('chat.html#fencetoolcallback', 'fastllm/chat.py'),
|
|
73
72
|
'fastllm.chat.FenceToolCallback.after_msgs': ('chat.html#fencetoolcallback.after_msgs', 'fastllm/chat.py'),
|
|
74
73
|
'fastllm.chat.FenceToolCallback.before_acomplete': ( 'chat.html#fencetoolcallback.before_acomplete',
|
|
@@ -99,17 +98,13 @@ d = { 'settings': { 'branch': 'main',
|
|
|
99
98
|
'fastllm.chat.UsageStats.fmt': ('chat.html#usagestats.fmt', 'fastllm/chat.py'),
|
|
100
99
|
'fastllm.chat.UsageStats.from_response': ('chat.html#usagestats.from_response', 'fastllm/chat.py'),
|
|
101
100
|
'fastllm.chat._active_fence_langs': ('chat.html#_active_fence_langs', 'fastllm/chat.py'),
|
|
102
|
-
'fastllm.chat._add_cache_control': ('chat.html#_add_cache_control', 'fastllm/chat.py'),
|
|
103
101
|
'fastllm.chat._alite_call_func': ('chat.html#_alite_call_func', 'fastllm/chat.py'),
|
|
104
|
-
'fastllm.chat._apply_cache_idxs': ('chat.html#_apply_cache_idxs', 'fastllm/chat.py'),
|
|
105
102
|
'fastllm.chat._call_func': ('chat.html#_call_func', 'fastllm/chat.py'),
|
|
106
103
|
'fastllm.chat._handle_stop_reason': ('chat.html#_handle_stop_reason', 'fastllm/chat.py'),
|
|
107
|
-
'fastllm.chat._has_cache': ('chat.html#_has_cache', 'fastllm/chat.py'),
|
|
108
104
|
'fastllm.chat._has_search': ('chat.html#_has_search', 'fastllm/chat.py'),
|
|
109
105
|
'fastllm.chat._has_stop': ('chat.html#_has_stop', 'fastllm/chat.py'),
|
|
110
106
|
'fastllm.chat._inject_tool_reminder': ('chat.html#_inject_tool_reminder', 'fastllm/chat.py'),
|
|
111
107
|
'fastllm.chat._lite_call_func': ('chat.html#_lite_call_func', 'fastllm/chat.py'),
|
|
112
|
-
'fastllm.chat._mk_prefill': ('chat.html#_mk_prefill', 'fastllm/chat.py'),
|
|
113
108
|
'fastllm.chat._mk_tool_result': ('chat.html#_mk_tool_result', 'fastllm/chat.py'),
|
|
114
109
|
'fastllm.chat._think_kw': ('chat.html#_think_kw', 'fastllm/chat.py'),
|
|
115
110
|
'fastllm.chat._usrtools': ('chat.html#_usrtools', 'fastllm/chat.py'),
|
|
@@ -119,10 +114,7 @@ d = { 'settings': { 'branch': 'main',
|
|
|
119
114
|
'fastllm.chat.cite_footnote': ('chat.html#cite_footnote', 'fastllm/chat.py'),
|
|
120
115
|
'fastllm.chat.contents': ('chat.html#contents', 'fastllm/chat.py'),
|
|
121
116
|
'fastllm.chat.lite_mk_func': ('chat.html#lite_mk_func', 'fastllm/chat.py'),
|
|
122
|
-
'fastllm.chat.mk_msg': ('chat.html#mk_msg', 'fastllm/chat.py'),
|
|
123
|
-
'fastllm.chat.mk_msgs': ('chat.html#mk_msgs', 'fastllm/chat.py'),
|
|
124
117
|
'fastllm.chat.postproc': ('chat.html#postproc', 'fastllm/chat.py'),
|
|
125
|
-
'fastllm.chat.remove_cache_ckpts': ('chat.html#remove_cache_ckpts', 'fastllm/chat.py'),
|
|
126
118
|
'fastllm.chat.run_fence_tool': ('chat.html#run_fence_tool', 'fastllm/chat.py'),
|
|
127
119
|
'fastllm.chat.search_count': ('chat.html#search_count', 'fastllm/chat.py'),
|
|
128
120
|
'fastllm.chat.stop_reason': ('chat.html#stop_reason', 'fastllm/chat.py'),
|
|
@@ -232,12 +224,18 @@ d = { 'settings': { 'branch': 'main',
|
|
|
232
224
|
'fastllm.openai_responses.norm_usage': ( 'oai_responses.html#norm_usage',
|
|
233
225
|
'fastllm/openai_responses.py')},
|
|
234
226
|
'fastllm.streaming': { 'fastllm.streaming.Delta': ('streaming.html#delta', 'fastllm/streaming.py'),
|
|
227
|
+
'fastllm.streaming.Delta.__eq__': ('streaming.html#delta.__eq__', 'fastllm/streaming.py'),
|
|
228
|
+
'fastllm.streaming.Delta.__hash__': ('streaming.html#delta.__hash__', 'fastllm/streaming.py'),
|
|
229
|
+
'fastllm.streaming.Delta.__init__': ('streaming.html#delta.__init__', 'fastllm/streaming.py'),
|
|
235
230
|
'fastllm.streaming.FenceToolStop': ('streaming.html#fencetoolstop', 'fastllm/streaming.py'),
|
|
236
231
|
'fastllm.streaming.FenceToolStop.__call__': ( 'streaming.html#fencetoolstop.__call__',
|
|
237
232
|
'fastllm/streaming.py'),
|
|
238
233
|
'fastllm.streaming.FenceToolStop.__init__': ( 'streaming.html#fencetoolstop.__init__',
|
|
239
234
|
'fastllm/streaming.py'),
|
|
240
235
|
'fastllm.streaming.PartAccum': ('streaming.html#partaccum', 'fastllm/streaming.py'),
|
|
236
|
+
'fastllm.streaming.PartAccum.__eq__': ('streaming.html#partaccum.__eq__', 'fastllm/streaming.py'),
|
|
237
|
+
'fastllm.streaming.PartAccum.__hash__': ('streaming.html#partaccum.__hash__', 'fastllm/streaming.py'),
|
|
238
|
+
'fastllm.streaming.PartAccum.__init__': ('streaming.html#partaccum.__init__', 'fastllm/streaming.py'),
|
|
241
239
|
'fastllm.streaming.PartAccum.append': ('streaming.html#partaccum.append', 'fastllm/streaming.py'),
|
|
242
240
|
'fastllm.streaming.PartAccum.get_merged': ( 'streaming.html#partaccum.get_merged',
|
|
243
241
|
'fastllm/streaming.py'),
|
|
@@ -247,6 +245,9 @@ d = { 'settings': { 'branch': 'main',
|
|
|
247
245
|
'fastllm.streaming.PrintStream.__init__': ( 'streaming.html#printstream.__init__',
|
|
248
246
|
'fastllm/streaming.py'),
|
|
249
247
|
'fastllm.streaming.Status': ('streaming.html#status', 'fastllm/streaming.py'),
|
|
248
|
+
'fastllm.streaming.Status.__eq__': ('streaming.html#status.__eq__', 'fastllm/streaming.py'),
|
|
249
|
+
'fastllm.streaming.Status.__hash__': ('streaming.html#status.__hash__', 'fastllm/streaming.py'),
|
|
250
|
+
'fastllm.streaming.Status.__init__': ('streaming.html#status.__init__', 'fastllm/streaming.py'),
|
|
250
251
|
'fastllm.streaming.Status.formatted': ('streaming.html#status.formatted', 'fastllm/streaming.py'),
|
|
251
252
|
'fastllm.streaming._mk_delta_part': ('streaming.html#_mk_delta_part', 'fastllm/streaming.py'),
|
|
252
253
|
'fastllm.streaming._trim_delta': ('streaming.html#_trim_delta', 'fastllm/streaming.py'),
|
|
@@ -259,12 +260,12 @@ d = { 'settings': { 'branch': 'main',
|
|
|
259
260
|
'fastllm.types.APIRegistry.__missing__': ('types.html#apiregistry.__missing__', 'fastllm/types.py'),
|
|
260
261
|
'fastllm.types.APIRegistry._load': ('types.html#apiregistry._load', 'fastllm/types.py'),
|
|
261
262
|
'fastllm.types.APIRegistry.register': ('types.html#apiregistry.register', 'fastllm/types.py'),
|
|
262
|
-
'fastllm.types.Completion': ('types.html#completion', 'fastllm/types.py'),
|
|
263
263
|
'fastllm.types.Completion._repr_markdown_': ('types.html#completion._repr_markdown_', 'fastllm/types.py'),
|
|
264
264
|
'fastllm.types.Completion.cost': ('types.html#completion.cost', 'fastllm/types.py'),
|
|
265
265
|
'fastllm.types.Completion.formatted': ('types.html#completion.formatted', 'fastllm/types.py'),
|
|
266
|
-
'fastllm.types.Completion.tool_calls': ('types.html#completion.tool_calls', 'fastllm/types.py'),
|
|
267
266
|
'fastllm.types.Usage': ('types.html#usage', 'fastllm/types.py'),
|
|
267
|
+
'fastllm.types.Usage.__eq__': ('types.html#usage.__eq__', 'fastllm/types.py'),
|
|
268
|
+
'fastllm.types.Usage.__init__': ('types.html#usage.__init__', 'fastllm/types.py'),
|
|
268
269
|
'fastllm.types._rm_ctx_tiers': ('types.html#_rm_ctx_tiers', 'fastllm/types.py'),
|
|
269
270
|
'fastllm.types.approx_pricing': ('types.html#approx_pricing', 'fastllm/types.py'),
|
|
270
271
|
'fastllm.types.fn_schema': ('types.html#fn_schema', 'fastllm/types.py'),
|
|
@@ -16,7 +16,8 @@ from fastspec.oapi import *
|
|
|
16
16
|
from fastspec.errors import APIError
|
|
17
17
|
|
|
18
18
|
from .types import *
|
|
19
|
-
from aidialog.msg_parts import Part, PartType, Msg, Text, Thinking, ToolUse, ToolResult, InputImage, InputAudio, InputVideo,
|
|
19
|
+
from aidialog.msg_parts import (Part, PartType, Msg, Text, Thinking, ToolUse, ToolResult, InputImage, InputAudio, InputVideo,
|
|
20
|
+
InputFile, mk_tool_res_msg, Completion)
|
|
20
21
|
from .streaming import *
|
|
21
22
|
from .openai_responses import *
|
|
22
23
|
from .openai_chat import *
|
|
@@ -5,7 +5,7 @@ __all__ = ['ant_tc_types', 'norm_tool_call', 'norm_tool_calls', 'norm_usage', 'f
|
|
|
5
5
|
'norm_tr_parts', 'norm_sse_event', 'delta_index_fn', 'acollect_stream', 'denorm_tool_use',
|
|
6
6
|
'denorm_assistant', 'denorm_tool', 'denorm_msgs', 'denorm_tool_schs', 'denorm_tool_choice',
|
|
7
7
|
'denorm_reasoning', 'denorm_web_search', 'denorm_system', 'denorm_user', 'denorm_image', 'denorm_file',
|
|
8
|
-
'denorm_tool_result', 'mk_payload', 'get_hdrs', 'cost']
|
|
8
|
+
'denorm_tool_result', 'apply_cache_idxs', 'mk_payload', 'get_hdrs', 'cost']
|
|
9
9
|
|
|
10
10
|
# %% ../nbs/04_anthropic.ipynb #02afd3d7
|
|
11
11
|
import json
|
|
@@ -271,12 +271,47 @@ def denorm_tool_result(p:ToolResult):
|
|
|
271
271
|
return _ant_cc(dict(type='tool_result', tool_use_id=tid, content=blocks), p)
|
|
272
272
|
return _ant_cc(dict(type='tool_result', tool_use_id=tid, content=tool_text(p.text)), p)
|
|
273
273
|
|
|
274
|
+
# %% ../nbs/04_anthropic.ipynb #e4eb8d3b
|
|
275
|
+
def _add_cache_control(
|
|
276
|
+
msg, # Canonical Msg to mark
|
|
277
|
+
ttl=None # Cache TTL: '5m' (default) or '1h'
|
|
278
|
+
):
|
|
279
|
+
"Set a cache breakpoint on the last `Text` or `ToolUse` part of `msg`"
|
|
280
|
+
cc = {"type": "ephemeral"} | ({"ttl": ttl} if ttl else {})
|
|
281
|
+
idxs = [i for i,p in enumerate(msg.content) if isinstance(p, (Text, ToolUse))]
|
|
282
|
+
if idxs: msg.content[idxs[-1]].cache_control = cc
|
|
283
|
+
return msg
|
|
284
|
+
|
|
285
|
+
# %% ../nbs/04_anthropic.ipynb #6bc52ef5
|
|
286
|
+
def apply_cache_idxs(
|
|
287
|
+
msgs, # Canonical Msgs to mark
|
|
288
|
+
cache_idxs=[-1], # Breakpoint idxs into `msgs` (tool-role msgs excluded); 0 is `sp` when given
|
|
289
|
+
sp=None, # System prompt: str, Msg, or Part
|
|
290
|
+
ttl=None # Cache TTL: '5m' (default) or '1h'
|
|
291
|
+
):
|
|
292
|
+
"Strip all cache breakpoints from `msgs`, then mark `cache_idxs`; returns `sp`, marked if 0 is included"
|
|
293
|
+
for m in msgs:
|
|
294
|
+
for p in m.content: p.cache_control = None
|
|
295
|
+
if sp:
|
|
296
|
+
if 0 in cache_idxs:
|
|
297
|
+
if isinstance(sp, str): sp = Text(sp)
|
|
298
|
+
if isinstance(sp, Part): sp = Msg('', [sp])
|
|
299
|
+
_add_cache_control(sp, ttl)
|
|
300
|
+
cache_idxs = [o-1 if o>0 else o for o in cache_idxs if o]
|
|
301
|
+
ms = [j for j,m in enumerate(msgs) if m.role != 'tool']
|
|
302
|
+
for i in cache_idxs:
|
|
303
|
+
try: _add_cache_control(msgs[ms[i]], ttl)
|
|
304
|
+
except IndexError: continue
|
|
305
|
+
return sp
|
|
306
|
+
|
|
274
307
|
# %% ../nbs/04_anthropic.ipynb #587d4fe5
|
|
275
308
|
@delegates(payload_kwargs)
|
|
276
309
|
def mk_payload(msgs, model, **kwargs):
|
|
310
|
+
sp = kwargs.get('system')
|
|
311
|
+
if (ci:=kwargs.get('cache_idxs')) is not None: sp = apply_cache_idxs(msgs, ci, sp, kwargs.get('ttl'))
|
|
277
312
|
payload = dict(model=model, messages=denorm_msgs(msgs), max_tokens=kwargs.get('max_tokens') or 1024)
|
|
278
313
|
if kwargs.get('stream'): payload['stream'] = True
|
|
279
|
-
if sp
|
|
314
|
+
if sp: payload['system'] = denorm_system(sp)
|
|
280
315
|
if tools:=kwargs.get('tools'): payload['tools'] = denorm_tool_schs(tools)
|
|
281
316
|
if tchc:=kwargs.get('tool_choice'): payload['tool_choice'] = denorm_tool_choice(tchc)
|
|
282
317
|
if thk:=kwargs.get('reasoning_effort'): payload.update(denorm_reasoning(thk))
|
|
@@ -3,49 +3,24 @@
|
|
|
3
3
|
# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/07_chat.ipynb.
|
|
4
4
|
|
|
5
5
|
# %% auto #0
|
|
6
|
-
__all__ = ['effort', '
|
|
7
|
-
'
|
|
8
|
-
'
|
|
9
|
-
'
|
|
10
|
-
'StreamAccum', 'adisplay_stream']
|
|
6
|
+
__all__ = ['effort', 'contents', 'stop_reason', 'cite_footnote', 'postproc', 'Refresh', 'think_sep', 'lite_mk_func', 'structured',
|
|
7
|
+
'search_count', 'UsageStats', 'AsyncChat', 'astream_with_complete', 'ChatCallback', 'DeepseekMsgsCallback',
|
|
8
|
+
'add_warning', 'StopReasonCallback', 'run_fence_tool', 'FenceToolCallback', 'ToolReminderCallback',
|
|
9
|
+
'StopSequencesCallback', 'StreamAccum', 'adisplay_stream']
|
|
11
10
|
|
|
12
11
|
# %% ../nbs/07_chat.ipynb #d5a3bc1f
|
|
13
12
|
from typing import Optional,Callable
|
|
14
13
|
from fastcore.funccall import mk_ns, call_func, call_func_async, get_schema
|
|
15
14
|
from fastcore.utils import *
|
|
16
15
|
from fastcore.meta import delegates
|
|
17
|
-
from dataclasses import dataclass
|
|
18
16
|
|
|
19
17
|
from .types import *
|
|
20
|
-
from aidialog.msg_parts import (Msg, Part, PartType, Text, Thinking, ToolUse,
|
|
21
|
-
|
|
22
|
-
|
|
18
|
+
from aidialog.msg_parts import (Msg, Part, PartType, Text, Thinking, ToolUse, tool_text, mk_tool_res_msg, tool_info, usage_info,
|
|
19
|
+
StopResponse, ToolResponse, display_list, fmt2hist, hist2fmt, mk_result_fence, split_fence_msgs, extract_fence_call,
|
|
20
|
+
trunc_str, Completion, mk_msg, mk_msgs)
|
|
23
21
|
from .acomplete import *
|
|
24
22
|
from .streaming import FenceToolStop, stop_sequences
|
|
25
23
|
|
|
26
|
-
# %% ../nbs/07_chat.ipynb #43a55cda
|
|
27
|
-
def _add_cache_control(
|
|
28
|
-
msg, # LiteLLM formatted msg
|
|
29
|
-
ttl=None # Cache TTL: '5m' (default) or '1h'
|
|
30
|
-
):
|
|
31
|
-
"cache `msg` with default time-to-live (ttl) of 5minutes ('5m'), but can be set to '1h'."
|
|
32
|
-
cc = {"type": "ephemeral"} | ({"ttl": ttl} if ttl else {})
|
|
33
|
-
cache_idx = None
|
|
34
|
-
for idx, part in enumerate(msg.content):
|
|
35
|
-
if isinstance(part, (Text, ToolUse)): cache_idx = idx
|
|
36
|
-
msg.content[idx].cache_control = cc
|
|
37
|
-
return msg
|
|
38
|
-
|
|
39
|
-
def _has_cache(msg):
|
|
40
|
-
"Check if msg has cache_control set"
|
|
41
|
-
return any(part.cache_control for part in msg.content)
|
|
42
|
-
|
|
43
|
-
def remove_cache_ckpts(msg):
|
|
44
|
-
"remove cache checkpoints and return msg."
|
|
45
|
-
for part in msg.content: part.cache_control = None
|
|
46
|
-
return msg
|
|
47
|
-
|
|
48
|
-
|
|
49
24
|
# %% ../nbs/07_chat.ipynb #48c78e48
|
|
50
25
|
def contents(c):
|
|
51
26
|
"Get Msg object from Completion."
|
|
@@ -56,51 +31,6 @@ def stop_reason(c):
|
|
|
56
31
|
if not c.finish_reason: return 'unk'
|
|
57
32
|
return c.finish_reason
|
|
58
33
|
|
|
59
|
-
# %% ../nbs/07_chat.ipynb #4a1c44ea
|
|
60
|
-
def mk_msg(
|
|
61
|
-
content, # Content: str, bytes (image), list of mixed content, or dict w 'role' and 'content' fields
|
|
62
|
-
role="user", # Message role if content isn't already a dict/Message
|
|
63
|
-
cache=False, # Enable Anthropic caching
|
|
64
|
-
ttl=None # Cache TTL: '5m' (default) or '1h'
|
|
65
|
-
):
|
|
66
|
-
"Create a LiteLLM compatible message."
|
|
67
|
-
if content is None: return None
|
|
68
|
-
if isinstance(content, Msg): return content
|
|
69
|
-
if isinstance(content, Completion): return content.message
|
|
70
|
-
if isinstance(content, list) and len(content) == 1 and isinstance(content[0], str): parts = [Text(content[0])]
|
|
71
|
-
elif isinstance(content, list): parts = [mk_content(o) for o in content]
|
|
72
|
-
elif isinstance(content, dict): return Msg(role=content['role'], content=[Text(content['content'])])
|
|
73
|
-
else: parts = [Text(content)]
|
|
74
|
-
msg = Msg(role=role, content=parts)
|
|
75
|
-
return _add_cache_control(msg, ttl=ttl) if cache else msg
|
|
76
|
-
|
|
77
|
-
# %% ../nbs/07_chat.ipynb #01bd81de
|
|
78
|
-
def _apply_cache_idxs(msgs, cache_idxs=[-1], ttl=None):
|
|
79
|
-
"Add cache control to `cache_idxs` after filtering tool-role msgs"
|
|
80
|
-
ms = [j for j,m in enumerate(msgs) if m.role != 'tool']
|
|
81
|
-
for i in cache_idxs:
|
|
82
|
-
try: idx = ms[i]
|
|
83
|
-
except IndexError: continue
|
|
84
|
-
_add_cache_control(msgs[idx], ttl)
|
|
85
|
-
|
|
86
|
-
# %% ../nbs/07_chat.ipynb #fcbb9f5d
|
|
87
|
-
def mk_msgs(
|
|
88
|
-
msgs, # List of messages (each: str, bytes, list, Msg, or Completion)
|
|
89
|
-
cache=False, # Enable Anthropic caching
|
|
90
|
-
cache_idxs=[-1], # Cache breakpoint idxs
|
|
91
|
-
ttl=None, # Cache TTL: '5m' (default) or '1h'
|
|
92
|
-
):
|
|
93
|
-
"Create a list of fastllm canonical Msgs."
|
|
94
|
-
if not msgs: return []
|
|
95
|
-
if not isinstance(msgs, list): msgs = [msgs]
|
|
96
|
-
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()
|
|
97
|
-
res, role = [], 'user'
|
|
98
|
-
for m in msgs:
|
|
99
|
-
res.append(msg := remove_cache_ckpts(mk_msg(m, role=role)))
|
|
100
|
-
role = 'assistant' if msg.role in ('user','tool') else 'user'
|
|
101
|
-
if cache: _apply_cache_idxs(res, cache_idxs, ttl)
|
|
102
|
-
return res
|
|
103
|
-
|
|
104
34
|
# %% ../nbs/07_chat.ipynb #447aed6e
|
|
105
35
|
def cite_footnote(citations):
|
|
106
36
|
'Build citation footnotes for a single Delta'
|
|
@@ -172,9 +102,6 @@ def _has_search(info): return bool(info.get('search_context_cost_per_query') or
|
|
|
172
102
|
effort = AttrDict({o[0]:o for o in ('low','medium','high')})
|
|
173
103
|
effort['x'] = 'max'
|
|
174
104
|
|
|
175
|
-
# %% ../nbs/07_chat.ipynb #e1facb77
|
|
176
|
-
def _mk_prefill(pf): return Text(pf)
|
|
177
|
-
|
|
178
105
|
# %% ../nbs/07_chat.ipynb #dc17f844
|
|
179
106
|
def _has_stop(tres_parts): return any(isinstance(p.text, StopResponse) for p in tres_parts)
|
|
180
107
|
|
|
@@ -255,7 +182,7 @@ class AsyncChat:
|
|
|
255
182
|
if v in vendor_mapping: vendor_name = v
|
|
256
183
|
elif v: api_name = v # a registered transport api (e.g. claude_code)
|
|
257
184
|
self.model = model
|
|
258
|
-
hist,tools = mk_msgs(hist
|
|
185
|
+
hist,tools = mk_msgs(hist),listify(tools)
|
|
259
186
|
if ns is None and tools: ns = mk_ns(tools)
|
|
260
187
|
elif ns is None: ns = globals()
|
|
261
188
|
self.tool_schemas = [lite_mk_func(t) for t in tools] if tools else None
|
|
@@ -267,18 +194,11 @@ class AsyncChat:
|
|
|
267
194
|
if default_cbs: self.add_cbs(defaults.chat_callbacks)
|
|
268
195
|
self.add_cbs(cbs)
|
|
269
196
|
|
|
270
|
-
def _prep_msg(self, msg=None
|
|
197
|
+
def _prep_msg(self, msg=None):
|
|
271
198
|
"Prepare the system prompt and messages list for the API call"
|
|
272
|
-
sp = self.sp
|
|
273
|
-
if sp:
|
|
274
|
-
if 0 in self.cache_idxs: sp = _add_cache_control(Msg('',[Text(sp)]))
|
|
275
|
-
cache_idxs = L(self.cache_idxs).filter().map(lambda o: o-1 if o>0 else o)
|
|
276
|
-
else: cache_idxs = self.cache_idxs
|
|
277
199
|
if msg: self.hist = self.hist+[msg]
|
|
278
|
-
self.hist = mk_msgs(self.hist
|
|
279
|
-
|
|
280
|
-
if prefill: msgs = self.hist + [Msg(role='assistant', content=[Text(prefill)])]
|
|
281
|
-
return sp, msgs
|
|
200
|
+
self.hist = mk_msgs(self.hist)
|
|
201
|
+
return self.sp, self.hist
|
|
282
202
|
|
|
283
203
|
@property
|
|
284
204
|
def tcdict(self): return dict(tool_schemas=self.tool_schemas, ns=self.ns)
|
|
@@ -317,11 +237,10 @@ def _think_kw(model, think, vendor_name):
|
|
|
317
237
|
|
|
318
238
|
# %% ../nbs/07_chat.ipynb #06e898fd
|
|
319
239
|
@patch
|
|
320
|
-
def _prep_call(self:AsyncChat,
|
|
321
|
-
"Prepare model info,
|
|
240
|
+
def _prep_call(self:AsyncChat, search, max_tokens, kwargs, stream=False, think=None):
|
|
241
|
+
"Prepare model info, search, and provider kwargs for a completion call"
|
|
322
242
|
model_info = get_model_info(self.model, self.vendor_name)
|
|
323
243
|
if max_tokens is None: max_tokens = ifnone(model_info.get('max_output_tokens'), 32_000)
|
|
324
|
-
if not model_info.get("supports_assistant_prefill"): prefill = None
|
|
325
244
|
if _has_search(model_info) and (s:=ifnone(search,self.search)):
|
|
326
245
|
if 'web_search_options' not in kwargs: kwargs['web_search_options'] = {}
|
|
327
246
|
kwargs['web_search_options']['search_context_size'] = effort[s]
|
|
@@ -333,7 +252,7 @@ def _prep_call(self:AsyncChat, prefill, search, max_tokens, kwargs, stream=False
|
|
|
333
252
|
if self.base_url: kwargs['base_url'] = self.base_url
|
|
334
253
|
if self.extra_headers: kwargs['xtra_headers'] = self.extra_headers
|
|
335
254
|
kwargs.update(_think_kw(self.model, think, self.vendor_name))
|
|
336
|
-
return
|
|
255
|
+
return max_tokens
|
|
337
256
|
|
|
338
257
|
# %% ../nbs/07_chat.ipynb #07951b77
|
|
339
258
|
@patch
|
|
@@ -357,26 +276,25 @@ async def astream_with_complete(self, agen, postproc=noop):
|
|
|
357
276
|
# %% ../nbs/07_chat.ipynb #a049cf52
|
|
358
277
|
@patch
|
|
359
278
|
@delegates(acomplete)
|
|
360
|
-
async def _call(self:AsyncChat, msg=None,
|
|
279
|
+
async def _call(self:AsyncChat, msg=None, temp=None, think=None, search=None, stream=False, max_steps=2, step=1,
|
|
361
280
|
final_prompt=None, tool_choice=None, max_tokens=None, n_workers=8, pause=0.001, tc_timeout=7200, **kwargs):
|
|
362
281
|
if step>max_steps+1: return
|
|
363
|
-
|
|
364
|
-
self.turn_sysp, self.turn_msgs = self._prep_msg(msg
|
|
282
|
+
max_tokens = self._prep_call(search, max_tokens, kwargs, stream=stream, think=think)
|
|
283
|
+
self.turn_sysp, self.turn_msgs = self._prep_msg(msg)
|
|
365
284
|
async for o in self._call_cbs('after_msgs'): yield o
|
|
366
285
|
|
|
367
286
|
self.turn_kwargs, self.stream = kwargs, stream
|
|
368
287
|
async for o in self._call_cbs('before_acomplete'): yield o
|
|
369
288
|
res = await acomplete(self.turn_msgs, self.model, system=self.turn_sysp, stream=stream, tools=self.tool_schemas,
|
|
370
|
-
tool_choice=tool_choice, max_tokens=int(max_tokens), temperature=None if think else ifnone(temp,self.temp),
|
|
289
|
+
tool_choice=tool_choice, max_tokens=int(max_tokens), temperature=None if think else ifnone(temp,self.temp),
|
|
290
|
+
cache_idxs=self.cache_idxs if self.cache else [], ttl=self.ttl, **self.turn_kwargs)
|
|
371
291
|
if stream:
|
|
372
|
-
if self.prefill: yield _mk_prefill(self.prefill)
|
|
373
292
|
res = astream_with_complete(res, postproc=postproc)
|
|
374
293
|
async for chunk in res:
|
|
375
294
|
if isinstance(chunk, Thinking) and self.showthink: chunk.showthink = True
|
|
376
295
|
yield chunk
|
|
377
296
|
res = res.value
|
|
378
297
|
self.turn_res, self.turn_msg = res, contents(res)
|
|
379
|
-
if self.prefill: self.turn_msg.content[0].text = self.prefill + self.turn_msg.content[0].text
|
|
380
298
|
self.hist.append(self.turn_msg)
|
|
381
299
|
async for o in self._call_cbs('after_acomplete'): yield o
|
|
382
300
|
self._track(self.turn_res)
|
|
@@ -397,14 +315,14 @@ async def _call(self:AsyncChat, msg=None, prefill=None, temp=None, think=None, s
|
|
|
397
315
|
if self.toolloop and step <= max_steps:
|
|
398
316
|
try:
|
|
399
317
|
async for result in self._call(
|
|
400
|
-
self.prompt,
|
|
318
|
+
self.prompt, temp, think, search, stream, max_steps, step+1,
|
|
401
319
|
final_prompt, tool_choice=tool_choice, **kwargs): yield result
|
|
402
320
|
except ContextWindowExceededError:
|
|
403
321
|
if tmsg is not None:
|
|
404
322
|
for p in tmsg.content:
|
|
405
323
|
if len(p.text)>1000: p.text = _cwe_msg + trunc_str(p.text, mx=1000)
|
|
406
324
|
async for result in self._call(
|
|
407
|
-
self.prompt,
|
|
325
|
+
self.prompt, temp, think, search, stream, max_steps, step+1,
|
|
408
326
|
final_prompt, tool_choice='none', **kwargs): yield result
|
|
409
327
|
|
|
410
328
|
# %% ../nbs/07_chat.ipynb #1361515a
|
|
@@ -413,7 +331,6 @@ async def _call(self:AsyncChat, msg=None, prefill=None, temp=None, think=None, s
|
|
|
413
331
|
async def __call__(
|
|
414
332
|
self:AsyncChat,
|
|
415
333
|
msg=None, # Message str, or list of multiple message parts
|
|
416
|
-
prefill=None, # Prefill AI response if model supports it
|
|
417
334
|
temp=None, # Override temp set on chat initialization
|
|
418
335
|
think=None, # Thinking (l,m,h)
|
|
419
336
|
search=None, # Override search set on chat initialization (l,m,h)
|
|
@@ -425,7 +342,7 @@ async def __call__(
|
|
|
425
342
|
):
|
|
426
343
|
self.use = UsageStats()
|
|
427
344
|
self._turn_start = len(self.hist)
|
|
428
|
-
result_gen = self._call(msg,
|
|
345
|
+
result_gen = self._call(msg, temp, think, search, stream, max_steps, 1, final_prompt, **kwargs)
|
|
429
346
|
if stream or return_all: return result_gen
|
|
430
347
|
async for res in result_gen: pass
|
|
431
348
|
return res # normal chat behavior only return last msg
|
|
@@ -458,14 +375,6 @@ class DeepseekMsgsCallback(ChatCallback):
|
|
|
458
375
|
if m.role=='assistant' and not any(isinstance(p, Thinking) for p in m.content): m.content.append(Thinking(''))
|
|
459
376
|
if False: yield
|
|
460
377
|
|
|
461
|
-
# %% ../nbs/07_chat.ipynb #14baac3e
|
|
462
|
-
class DeepseekPrefillCallback(ChatCallback):
|
|
463
|
-
order = 10
|
|
464
|
-
async def before_acomplete(self):
|
|
465
|
-
if self.prefill and self.vendor_name == 'deepseek' and self.model.startswith("deepseek-"):
|
|
466
|
-
self.chat.turn_kwargs['base_url'] = 'https://api.deepseek.com/beta'
|
|
467
|
-
if False: yield
|
|
468
|
-
|
|
469
378
|
# %% ../nbs/07_chat.ipynb #ce47dc4a
|
|
470
379
|
def add_warning(r, msg):
|
|
471
380
|
wrn = Text(f"<warning>{msg}</warning>")
|
|
@@ -565,7 +474,7 @@ class StopSequencesCallback(ChatCallback):
|
|
|
565
474
|
if False: yield
|
|
566
475
|
|
|
567
476
|
# %% ../nbs/07_chat.ipynb #318ee856
|
|
568
|
-
defaults.chat_callbacks = [
|
|
477
|
+
defaults.chat_callbacks = [FenceToolCallback, ToolReminderCallback, StopReasonCallback]
|
|
569
478
|
|
|
570
479
|
# %% ../nbs/07_chat.ipynb #ead4b56d
|
|
571
480
|
class StreamAccum:
|
|
@@ -8,26 +8,21 @@ __all__ = ['Delta', 'norm_and_yield', 'PrintStream', 'PartAccum', 'FenceToolStop
|
|
|
8
8
|
|
|
9
9
|
# %% ../nbs/01_streaming.ipynb #0df5c926
|
|
10
10
|
import json,copy
|
|
11
|
-
from dataclasses import dataclass, field, fields
|
|
12
11
|
from fastcore.utils import *
|
|
13
12
|
from fastcore.meta import delegates
|
|
14
13
|
from fastspec.errors import *
|
|
15
14
|
from .types import *
|
|
16
|
-
from aidialog.msg_parts import Part, PartType, Msg, Text, Thinking, ToolUse, ToolResult, ServerToolResult, mk_part, fence_call_re
|
|
15
|
+
from aidialog.msg_parts import Part, PartType, Msg, Text, Thinking, ToolUse, ToolResult, ServerToolResult, mk_part, fence_call_re, Completion
|
|
17
16
|
|
|
18
17
|
# %% ../nbs/01_streaming.ipynb #400d628a
|
|
19
|
-
|
|
20
|
-
class Delta:
|
|
18
|
+
class Delta(BasicRepr):
|
|
21
19
|
"Normalized streaming delta event."
|
|
22
|
-
text
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
finish_reason: str = None
|
|
29
|
-
usage: Usage = None
|
|
30
|
-
raw: dict = field(default_factory=dict)
|
|
20
|
+
def __init__(self, text='', thinking='', refusal='', tool_calls=None, citations=None,
|
|
21
|
+
server_tool_result=None, finish_reason=None, usage=None, raw=None):
|
|
22
|
+
store_attr()
|
|
23
|
+
self.tool_calls,self.citations,self.raw = ifnone(tool_calls,[]),ifnone(citations,[]),ifnone(raw,{})
|
|
24
|
+
def __eq__(self, o): return type(o) is type(self) and self.__dict__ == o.__dict__
|
|
25
|
+
def __hash__(self): return hash((self.text, self.thinking, self.finish_reason))
|
|
31
26
|
|
|
32
27
|
# %% ../nbs/01_streaming.ipynb #f59f837b
|
|
33
28
|
async def norm_and_yield(resp, norm_func):
|
|
@@ -47,10 +42,13 @@ class PrintStream:
|
|
|
47
42
|
if f: print(f, end='', flush=True)
|
|
48
43
|
|
|
49
44
|
# %% ../nbs/01_streaming.ipynb #a7f1738a
|
|
50
|
-
|
|
51
|
-
class PartAccum:
|
|
45
|
+
class PartAccum(BasicRepr):
|
|
52
46
|
"Accumulate streamed part deltas by index"
|
|
53
|
-
|
|
47
|
+
def __init__(self, parts=None):
|
|
48
|
+
store_attr()
|
|
49
|
+
self.parts = ifnone(parts, {})
|
|
50
|
+
def __eq__(self, o): return type(o) is type(self) and self.__dict__ == o.__dict__
|
|
51
|
+
def __hash__(self): return hash(len(self.parts))
|
|
54
52
|
|
|
55
53
|
def append(self, typ, index, txt='', citations=None, **tc_kwargs):
|
|
56
54
|
'Create and accumulate same type sequential parts'
|
|
@@ -117,11 +115,12 @@ def stop_sequences(seqs):
|
|
|
117
115
|
return _stop
|
|
118
116
|
|
|
119
117
|
# %% ../nbs/01_streaming.ipynb #90f91955
|
|
120
|
-
|
|
121
|
-
class Status:
|
|
118
|
+
class Status(BasicRepr):
|
|
122
119
|
"Stream marker for activity that isn't model content (e.g. draining deltas after a stop sequence)"
|
|
123
|
-
status: str
|
|
124
120
|
type = 'status'
|
|
121
|
+
def __init__(self, status): store_attr()
|
|
122
|
+
def __eq__(self, o): return type(o) is type(self) and self.__dict__ == o.__dict__
|
|
123
|
+
def __hash__(self): return hash(self.status)
|
|
125
124
|
@property
|
|
126
125
|
def formatted(self): return '🧠'
|
|
127
126
|
|
|
@@ -6,51 +6,29 @@
|
|
|
6
6
|
__all__ = ['FinishReason', 'api_registry', 'model_prices_url', 'haik45', 'sonn45', 'sonn46', 'sonn', 'sonn5', 'opus46', 'opus48',
|
|
7
7
|
'opus', 'opus5', 'fable', 'fable5', 'gpt54', 'gpt54m', 'gpt55', 'codex54', 'codex54m', 'codex55',
|
|
8
8
|
'codex53spark', 'model_info_registry', 'modern_llm', 'deepseek_v4_common', 'mimo_v25_common',
|
|
9
|
-
'codex_pricing', 'sol', 'terra', 'luna', 'gpt56s', 'Usage', '
|
|
10
|
-
'
|
|
11
|
-
'
|
|
12
|
-
'
|
|
9
|
+
'codex_pricing', 'sol', 'terra', 'luna', 'gpt56s', 'Usage', 'APIRegistry', 'mk_completion', 'fn_schema',
|
|
10
|
+
'payload_kwargs', 'get_api_key', 'resize_b64', 'model_prices_meta', 'infer_api_name', 'get_model_meta',
|
|
11
|
+
'register_model_info', 'get_model_info', 'get_model_pricing', 'approx_pricing', 'is_deepseek_peak_hour',
|
|
12
|
+
'price_tier', 'tier_rate']
|
|
13
13
|
|
|
14
14
|
# %% ../nbs/00_types.ipynb #b4d047fd
|
|
15
15
|
import httpx, base64, io
|
|
16
16
|
from importlib.metadata import entry_points
|
|
17
|
-
from dataclasses import dataclass, field
|
|
18
17
|
from datetime import datetime, timezone
|
|
19
|
-
from fastcore.net import urljson
|
|
20
18
|
from fastcore.utils import *
|
|
21
19
|
from PIL import Image as PImg
|
|
22
|
-
from aidialog.msg_parts import
|
|
20
|
+
from aidialog.msg_parts import Msg, Thinking, ToolUse, Completion
|
|
23
21
|
|
|
24
22
|
|
|
25
23
|
# %% ../nbs/00_types.ipynb #802ad832
|
|
26
|
-
|
|
27
|
-
class Usage:
|
|
24
|
+
class Usage(BasicRepr):
|
|
28
25
|
"Normalized usage."
|
|
29
|
-
prompt_tokens
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
raw: dict = field(default_factory=dict)
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
# %% ../nbs/00_types.ipynb #297a1672
|
|
39
|
-
@dataclass(frozen=True)
|
|
40
|
-
class Completion:
|
|
41
|
-
"Normalized completion response."
|
|
42
|
-
model: str
|
|
43
|
-
message: Msg
|
|
44
|
-
finish_reason: str = None
|
|
45
|
-
usage: Usage = None
|
|
46
|
-
api_name: str = None
|
|
47
|
-
vendor_name: str = None
|
|
48
|
-
raw: dict = field(default_factory=dict)
|
|
49
|
-
|
|
50
|
-
@property
|
|
51
|
-
def tool_calls(self):
|
|
52
|
-
"The `ToolUse` parts of `message`: a call lives in the content, not beside it"
|
|
53
|
-
return [p for p in self.message.content if isinstance(p, ToolUse)]
|
|
26
|
+
def __init__(self, prompt_tokens=0, completion_tokens=0, total_tokens=0, cached_tokens=0,
|
|
27
|
+
cache_creation_tokens=0, reasoning_tokens=0, raw=None):
|
|
28
|
+
store_attr()
|
|
29
|
+
self.raw = ifnone(raw, {})
|
|
30
|
+
def __eq__(self, o): return type(o) is type(self) and self.__dict__ == o.__dict__
|
|
31
|
+
|
|
54
32
|
|
|
55
33
|
# %% ../nbs/00_types.ipynb #4901e693
|
|
56
34
|
@patch(as_prop=True)
|
|
@@ -62,18 +40,18 @@ def _repr_markdown_(self: Completion):
|
|
|
62
40
|
content = ''
|
|
63
41
|
for p in self.message.content:
|
|
64
42
|
if isinstance(p, Thinking):
|
|
65
|
-
if p.text: content += f"
|
|
43
|
+
if p.text: content += f"\n::: details\n## Thinking\n\n{p.text}\n\n:::\n\n"
|
|
66
44
|
elif isinstance(p, ToolUse): content += f"\n\n🔧 {p.name}({p.arguments})\n"
|
|
67
45
|
elif txt := p.text: content += txt
|
|
68
46
|
details = [f"model: `{self.model}`", f"finish_reason: `{self.finish_reason}`", f"usage: `{self.usage}`"]
|
|
69
47
|
det_str = '\n- '.join(details)
|
|
70
48
|
return f"""{content}
|
|
71
49
|
|
|
72
|
-
|
|
50
|
+
::: details
|
|
73
51
|
|
|
74
52
|
- {det_str}
|
|
75
53
|
|
|
76
|
-
|
|
54
|
+
:::"""
|
|
77
55
|
|
|
78
56
|
# %% ../nbs/00_types.ipynb #ce59e431
|
|
79
57
|
FinishReason = str_enum('finish_reason', 'stop', 'tool_calls', 'length', 'content_filter')
|
|
@@ -123,7 +101,8 @@ def fn_schema(t):
|
|
|
123
101
|
return None
|
|
124
102
|
|
|
125
103
|
# %% ../nbs/00_types.ipynb #28c698fe
|
|
126
|
-
def payload_kwargs(msgs, model, stream=False, system=None, max_tokens=None, temperature=None, tools=None, tool_choice=None,
|
|
104
|
+
def payload_kwargs(msgs, model, stream=False, system=None, max_tokens=None, temperature=None, tools=None, tool_choice=None,
|
|
105
|
+
reasoning_effort=None, web_search_options=None, cache_idxs=None, ttl=None, stop_callables=None): pass
|
|
127
106
|
|
|
128
107
|
# %% ../nbs/00_types.ipynb #c2a2cb49
|
|
129
108
|
def get_api_key(api_key, default):
|
|
@@ -234,7 +213,7 @@ register_model_info('gpt-5.4-mini', vendor_name='openai', base='gpt-5.4-mini', s
|
|
|
234
213
|
|
|
235
214
|
for model in ('kimi-k2.5', 'kimi-k2.6' , 'kimi-k3'):
|
|
236
215
|
register_model_info(model, vendor_name='moonshot', base=f'moonshot/{model}', base_vendor_name=None,
|
|
237
|
-
supports_reasoning=True, supports_vision=True
|
|
216
|
+
supports_reasoning=True, supports_vision=True)
|
|
238
217
|
|
|
239
218
|
register_model_info('gemini-3.1-flash-lite', vendor_name='gemini', base='gemini-3.1-flash-lite-preview')
|
|
240
219
|
register_model_info('models/gemini-3.1-flash-lite', vendor_name='gemini', base='gemini-3.1-flash-lite-preview')
|
|
@@ -252,8 +231,7 @@ register_model_info('kimi-k3', vendor_name='moonshot', base='kimi-k2.6',
|
|
|
252
231
|
input_cost_per_token=3e-6, cache_read_input_token_cost=0.30e-6, output_cost_per_token=15.0e-6)
|
|
253
232
|
|
|
254
233
|
# %% ../nbs/00_types.ipynb #948d55d0
|
|
255
|
-
deepseek_v4_common = dict(**modern_llm,
|
|
256
|
-
max_input_tokens=1048576, max_output_tokens=393216, max_tokens=393216)
|
|
234
|
+
deepseek_v4_common = dict(**modern_llm, max_input_tokens=1048576, max_output_tokens=393216, max_tokens=393216)
|
|
257
235
|
|
|
258
236
|
register_model_info('deepseek-v4-flash', vendor_name='deepseek', base='deepseek/deepseek-v3.2', **deepseek_v4_common,
|
|
259
237
|
input_cost_per_token=1.4e-07, input_cost_per_token_cache_hit=2.8e-09,
|
|
@@ -15,7 +15,7 @@ classifiers = [
|
|
|
15
15
|
"Programming Language :: Python :: 3",
|
|
16
16
|
"Programming Language :: Python :: 3 :: Only",
|
|
17
17
|
]
|
|
18
|
-
dependencies = ['fastcore>=2.1.18', 'aidialog>=0.0.
|
|
18
|
+
dependencies = ['fastcore>=2.1.18', 'aidialog>=0.0.10', 'fastspec>=0.0.11', 'pillow']
|
|
19
19
|
|
|
20
20
|
[project.urls]
|
|
21
21
|
Repository = "https://github.com/AnswerDotAI/fastllm"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-fastllm
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.39
|
|
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
|
|
@@ -10,7 +10,7 @@ Classifier: Programming Language :: Python :: 3 :: Only
|
|
|
10
10
|
Requires-Python: >=3.10
|
|
11
11
|
Description-Content-Type: text/markdown
|
|
12
12
|
Requires-Dist: fastcore>=2.1.18
|
|
13
|
-
Requires-Dist: aidialog>=0.0.
|
|
13
|
+
Requires-Dist: aidialog>=0.0.10
|
|
14
14
|
Requires-Dist: fastspec>=0.0.11
|
|
15
15
|
Requires-Dist: pillow
|
|
16
16
|
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.0.38"
|
|
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.38 → python_fastllm-0.0.39}/python_fastllm.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|