python-fastllm 0.0.34__tar.gz → 0.0.36__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.34 → python_fastllm-0.0.36}/PKG-INFO +1 -1
- python_fastllm-0.0.36/fastllm/__init__.py +1 -0
- {python_fastllm-0.0.34 → python_fastllm-0.0.36}/fastllm/_modidx.py +4 -2
- {python_fastllm-0.0.34 → python_fastllm-0.0.36}/fastllm/chat.py +5 -10
- {python_fastllm-0.0.34 → python_fastllm-0.0.36}/fastllm/gemini.py +6 -9
- {python_fastllm-0.0.34 → python_fastllm-0.0.36}/fastllm/openai_responses.py +4 -3
- {python_fastllm-0.0.34 → python_fastllm-0.0.36}/fastllm/types.py +31 -7
- {python_fastllm-0.0.34 → python_fastllm-0.0.36}/python_fastllm.egg-info/PKG-INFO +1 -1
- python_fastllm-0.0.34/fastllm/__init__.py +0 -1
- {python_fastllm-0.0.34 → python_fastllm-0.0.36}/README.md +0 -0
- {python_fastllm-0.0.34 → python_fastllm-0.0.36}/fastllm/acomplete.py +0 -0
- {python_fastllm-0.0.34 → python_fastllm-0.0.36}/fastllm/anthropic.py +0 -0
- {python_fastllm-0.0.34 → python_fastllm-0.0.36}/fastllm/codex.py +0 -0
- {python_fastllm-0.0.34 → python_fastllm-0.0.36}/fastllm/openai_chat.py +0 -0
- {python_fastllm-0.0.34 → python_fastllm-0.0.36}/fastllm/specs/anthropic.json +0 -0
- {python_fastllm-0.0.34 → python_fastllm-0.0.36}/fastllm/specs/anthropic.yml +0 -0
- {python_fastllm-0.0.34 → python_fastllm-0.0.36}/fastllm/specs/gemini.json +0 -0
- {python_fastllm-0.0.34 → python_fastllm-0.0.36}/fastllm/specs/openai.with-code-samples.json +0 -0
- {python_fastllm-0.0.34 → python_fastllm-0.0.36}/fastllm/specs/openai.with-code-samples.yml +0 -0
- {python_fastllm-0.0.34 → python_fastllm-0.0.36}/fastllm/specs/spec_manifest.json +0 -0
- {python_fastllm-0.0.34 → python_fastllm-0.0.36}/fastllm/streaming.py +0 -0
- {python_fastllm-0.0.34 → python_fastllm-0.0.36}/pyproject.toml +0 -0
- {python_fastllm-0.0.34 → python_fastllm-0.0.36}/python_fastllm.egg-info/SOURCES.txt +0 -0
- {python_fastllm-0.0.34 → python_fastllm-0.0.36}/python_fastllm.egg-info/dependency_links.txt +0 -0
- {python_fastllm-0.0.34 → python_fastllm-0.0.36}/python_fastllm.egg-info/entry_points.txt +0 -0
- {python_fastllm-0.0.34 → python_fastllm-0.0.36}/python_fastllm.egg-info/requires.txt +0 -0
- {python_fastllm-0.0.34 → python_fastllm-0.0.36}/python_fastllm.egg-info/top_level.txt +0 -0
- {python_fastllm-0.0.34 → python_fastllm-0.0.36}/setup.cfg +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.0.36"
|
|
@@ -95,7 +95,6 @@ d = { 'settings': { 'branch': 'main',
|
|
|
95
95
|
'fastllm.chat.ToolReminderCallback.__init__': ('chat.html#toolremindercallback.__init__', 'fastllm/chat.py'),
|
|
96
96
|
'fastllm.chat.ToolReminderCallback.after_msgs': ( 'chat.html#toolremindercallback.after_msgs',
|
|
97
97
|
'fastllm/chat.py'),
|
|
98
|
-
'fastllm.chat.ToolResponse': ('chat.html#toolresponse', 'fastllm/chat.py'),
|
|
99
98
|
'fastllm.chat.UsageStats': ('chat.html#usagestats', 'fastllm/chat.py'),
|
|
100
99
|
'fastllm.chat.UsageStats.__add__': ('chat.html#usagestats.__add__', 'fastllm/chat.py'),
|
|
101
100
|
'fastllm.chat.UsageStats.__init__': ('chat.html#usagestats.__init__', 'fastllm/chat.py'),
|
|
@@ -258,6 +257,7 @@ d = { 'settings': { 'branch': 'main',
|
|
|
258
257
|
'fastllm.types.Completion._repr_markdown_': ('types.html#completion._repr_markdown_', 'fastllm/types.py'),
|
|
259
258
|
'fastllm.types.Completion.cost': ('types.html#completion.cost', 'fastllm/types.py'),
|
|
260
259
|
'fastllm.types.Usage': ('types.html#usage', 'fastllm/types.py'),
|
|
260
|
+
'fastllm.types._rm_ctx_tiers': ('types.html#_rm_ctx_tiers', 'fastllm/types.py'),
|
|
261
261
|
'fastllm.types.approx_pricing': ('types.html#approx_pricing', 'fastllm/types.py'),
|
|
262
262
|
'fastllm.types.fn_schema': ('types.html#fn_schema', 'fastllm/types.py'),
|
|
263
263
|
'fastllm.types.get_api_key': ('types.html#get_api_key', 'fastllm/types.py'),
|
|
@@ -269,5 +269,7 @@ d = { 'settings': { 'branch': 'main',
|
|
|
269
269
|
'fastllm.types.mk_completion': ('types.html#mk_completion', 'fastllm/types.py'),
|
|
270
270
|
'fastllm.types.model_prices_meta': ('types.html#model_prices_meta', 'fastllm/types.py'),
|
|
271
271
|
'fastllm.types.payload_kwargs': ('types.html#payload_kwargs', 'fastllm/types.py'),
|
|
272
|
+
'fastllm.types.price_tier': ('types.html#price_tier', 'fastllm/types.py'),
|
|
272
273
|
'fastllm.types.register_model_info': ('types.html#register_model_info', 'fastllm/types.py'),
|
|
273
|
-
'fastllm.types.resize_b64': ('types.html#resize_b64', 'fastllm/types.py')
|
|
274
|
+
'fastllm.types.resize_b64': ('types.html#resize_b64', 'fastllm/types.py'),
|
|
275
|
+
'fastllm.types.tier_rate': ('types.html#tier_rate', 'fastllm/types.py')}}}
|
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
|
|
5
5
|
# %% auto #0
|
|
6
6
|
__all__ = ['effort', 'remove_cache_ckpts', 'contents', 'stop_reason', 'mk_msg', 'FenceToolStop', 'extract_fence_call', 'mk_msgs',
|
|
7
|
-
'cite_footnote', 'postproc', 'lite_mk_func', '
|
|
8
|
-
'
|
|
9
|
-
'
|
|
10
|
-
'
|
|
7
|
+
'cite_footnote', 'postproc', 'lite_mk_func', 'structured', 'search_count', 'UsageStats', 'AsyncChat',
|
|
8
|
+
'astream_with_complete', 'ChatCallback', 'DeepseekMsgsCallback', 'DeepseekPrefillCallback', 'add_warning',
|
|
9
|
+
'StopReasonCallback', 'run_fence_tool', 'FenceToolCallback', 'ToolReminderCallback', 'stop_sequences',
|
|
10
|
+
'StopSequencesCallback', 'StreamFormatter', 'AsyncStreamFormatter', 'adisplay_stream']
|
|
11
11
|
|
|
12
12
|
# %% ../nbs/07_chat.ipynb #d5a3bc1f
|
|
13
13
|
from typing import Optional,Callable
|
|
@@ -18,7 +18,7 @@ from dataclasses import dataclass
|
|
|
18
18
|
|
|
19
19
|
from .types import *
|
|
20
20
|
from aidialog.msg_parts import (Msg, Part, PartType, ToolCall, mk_tool_res_msg, mk_tr_details,
|
|
21
|
-
tool_info, usage_info, think_start, think_end, StopResponse, display_list, fmt2hist,
|
|
21
|
+
tool_info, usage_info, think_start, think_end, StopResponse, ToolResponse, display_list, fmt2hist,
|
|
22
22
|
_mk_content, _mk_result_fence, _split_fence_msgs, _fence_back, _trunc_str)
|
|
23
23
|
from .acomplete import *
|
|
24
24
|
|
|
@@ -141,11 +141,6 @@ def lite_mk_func(f):
|
|
|
141
141
|
if isinstance(f, dict): return f
|
|
142
142
|
return {'type':'function', 'function':get_schema(f, pname='parameters')}
|
|
143
143
|
|
|
144
|
-
# %% ../nbs/07_chat.ipynb #3e0afa31
|
|
145
|
-
@dataclass
|
|
146
|
-
class ToolResponse:
|
|
147
|
-
content: list[str,str]
|
|
148
|
-
|
|
149
144
|
# %% ../nbs/07_chat.ipynb #bba6fd58
|
|
150
145
|
def _mk_tool_result(res):
|
|
151
146
|
"Unwrap `ToolResponse`, and format tool result message"
|
|
@@ -273,21 +273,18 @@ def get_hdrs(api_key=None):
|
|
|
273
273
|
def cost(usage, m):
|
|
274
274
|
raw = usage.raw
|
|
275
275
|
prompt_tot = raw.get('promptTokenCount', 0)
|
|
276
|
-
tier =
|
|
277
|
-
in_rate = m
|
|
278
|
-
out_rate = m
|
|
279
|
-
cache_rate = m
|
|
280
|
-
|
|
281
|
-
|
|
276
|
+
tier = price_tier(m, prompt_tot)
|
|
277
|
+
in_rate = tier_rate(m, 'input_cost_per_token', tier)
|
|
278
|
+
out_rate = tier_rate(m, 'output_cost_per_token', tier)
|
|
279
|
+
cache_rate = tier_rate(m, 'cache_read_input_token_cost', tier)
|
|
280
|
+
# Models with no `input_cost_per_audio_token` (e.g. Gemini 3 Pro) bill audio at the standard input rate, so it stays in `in_txt`
|
|
281
|
+
audio_rate = m.get('input_cost_per_audio_token')
|
|
282
282
|
cached = raw.get('cachedContentTokenCount', 0)
|
|
283
|
-
# Gemini 3 Pro supports bills audio at the standard input rate (no separate input_cost_per_audio_token key in the metadata)
|
|
284
283
|
audio = sum(d['tokenCount'] for d in raw.get('promptTokensDetails', []) if d.get('modality')=='AUDIO') if audio_rate else 0
|
|
285
284
|
in_txt = prompt_tot - cached - audio
|
|
286
|
-
|
|
287
285
|
thoughts = raw.get('thoughtsTokenCount', 0) or 0
|
|
288
286
|
cands = raw.get('candidatesTokenCount', 0) or 0
|
|
289
287
|
reason_rate = m.get('output_cost_per_reasoning_token') or out_rate
|
|
290
|
-
|
|
291
288
|
cost = in_txt * in_rate + cands * out_rate
|
|
292
289
|
cost += cached * cache_rate
|
|
293
290
|
cost += audio * (audio_rate or 0)
|
|
@@ -251,9 +251,10 @@ def get_hdrs(api_key=None):
|
|
|
251
251
|
def cost(usage, m):
|
|
252
252
|
raw = usage.raw
|
|
253
253
|
cached = raw.get('input_tokens_details', {}).get('cached_tokens', 0)
|
|
254
|
-
|
|
255
|
-
cost =
|
|
256
|
-
cost +=
|
|
254
|
+
tier = price_tier(m, raw['input_tokens'])
|
|
255
|
+
cost = (raw['input_tokens'] - cached) * tier_rate(m, 'input_cost_per_token', tier)
|
|
256
|
+
cost += raw['output_tokens'] * tier_rate(m, 'output_cost_per_token', tier)
|
|
257
|
+
cost += cached * tier_rate(m, 'cache_read_input_token_cost', tier)
|
|
257
258
|
return cost
|
|
258
259
|
|
|
259
260
|
# %% ../nbs/02_oai_responses.ipynb #07114b55
|
|
@@ -9,7 +9,7 @@ __all__ = ['FinishReason', 'api_registry', 'model_prices_url', 'haik45', 'sonn45
|
|
|
9
9
|
'codex_pricing', 'sol', 'terra', 'luna', 'gpt56s', 'Usage', 'Completion', 'APIRegistry', 'mk_completion',
|
|
10
10
|
'fn_schema', 'payload_kwargs', 'get_api_key', 'resize_b64', 'model_prices_meta', 'infer_api_name',
|
|
11
11
|
'get_model_meta', 'register_model_info', 'get_model_info', 'get_model_pricing', 'approx_pricing',
|
|
12
|
-
'is_deepseek_peak_hour']
|
|
12
|
+
'is_deepseek_peak_hour', 'price_tier', 'tier_rate']
|
|
13
13
|
|
|
14
14
|
# %% ../nbs/00_types.ipynb #b4d047fd
|
|
15
15
|
import httpx, base64, io
|
|
@@ -225,10 +225,11 @@ register_model_info('gemini-3.5-flash', vendor_name='gemini', base='gemini-3-fla
|
|
|
225
225
|
input_cost_per_token=1.5e-6, output_cost_per_token=9e-6,
|
|
226
226
|
output_cost_per_reasoning_token=9e-6, cache_read_input_token_cost=1.5e-7)
|
|
227
227
|
|
|
228
|
-
|
|
229
|
-
|
|
228
|
+
register_model_info('gpt-5.4', vendor_name='openai', base='gpt-5.4', supports_web_search=True, mode=None)
|
|
229
|
+
# Upstream metadata says 1,050,000 input tokens for gpt-5.4-mini, but OpenAI documents a 272k limit
|
|
230
|
+
register_model_info('gpt-5.4-mini', vendor_name='openai', base='gpt-5.4-mini', supports_web_search=True, mode=None, max_input_tokens=272_000)
|
|
230
231
|
|
|
231
|
-
for model in ('kimi-k2.5', 'kimi-k2.6'):
|
|
232
|
+
for model in ('kimi-k2.5', 'kimi-k2.6' , 'kimi-k3'):
|
|
232
233
|
register_model_info(model, vendor_name='moonshot', base=f'moonshot/{model}', base_vendor_name=None,
|
|
233
234
|
supports_reasoning=True, supports_vision=True, supports_assistant_prefill=True)
|
|
234
235
|
|
|
@@ -241,9 +242,11 @@ register_model_info('accounts/fireworks/models/kimi-k2p5', vendor_name='firework
|
|
|
241
242
|
register_model_info('accounts/fireworks/models/kimi-k2p6', vendor_name='fireworks_ai', base='accounts/fireworks/models/kimi-k2p5',
|
|
242
243
|
supports_reasoning=True, supports_vision=True,
|
|
243
244
|
input_cost_per_token=0.95e-6, cache_read_input_token_cost=0.16e-6, output_cost_per_token=4.0e-6)
|
|
244
|
-
|
|
245
245
|
register_model_info('kimi-k2.7-code', vendor_name='moonshot', base='kimi-k2.6',
|
|
246
246
|
input_cost_per_token=0.95e-6, cache_read_input_token_cost=0.19e-6, output_cost_per_token=4.0e-6)
|
|
247
|
+
register_model_info('kimi-k3', vendor_name='moonshot', base='kimi-k2.6',
|
|
248
|
+
supports_reasoning=True, supports_vision=True, max_input_tokens=1_000_000,
|
|
249
|
+
input_cost_per_token=3e-6, cache_read_input_token_cost=0.30e-6, output_cost_per_token=15.0e-6)
|
|
247
250
|
|
|
248
251
|
# %% ../nbs/00_types.ipynb #948d55d0
|
|
249
252
|
deepseek_v4_common = dict(**modern_llm, supports_assistant_prefill=True,
|
|
@@ -281,8 +284,14 @@ codex_pricing = dict(
|
|
|
281
284
|
input_cost_per_token = 0.10/1_000_000, output_cost_per_token = 0.50/1_000_000,
|
|
282
285
|
cache_creation_input_token_cost = 0.10/1_000_000, cache_read_input_token_cost = 0.10/1_000_000)
|
|
283
286
|
|
|
287
|
+
def _rm_ctx_tiers(vendor_name, model):
|
|
288
|
+
"Drop upstream context-tier rates, which would otherwise override flat subscription pricing"
|
|
289
|
+
info = model_info_registry[vendor_name, model]
|
|
290
|
+
for k in [k for k in info if re.search(r'_above_\d+k_tokens', k)]: del info[k]
|
|
291
|
+
|
|
284
292
|
for model in (codex54, codex54m, codex55):
|
|
285
293
|
register_model_info(model, 'codex', base=model, base_vendor_name='chatgpt', supports_web_search=True, max_input_tokens=256000, **codex_pricing)
|
|
294
|
+
_rm_ctx_tiers('codex', model)
|
|
286
295
|
|
|
287
296
|
register_model_info(codex53spark, 'codex', **codex_pricing,
|
|
288
297
|
supports_vision=False, supports_image_input=False, supports_web_search=True, supports_reasoning=True, supports_function_calling=True,
|
|
@@ -295,8 +304,12 @@ for model in (haik45, sonn45, sonn46, sonn5, opus46, opus48, opus5, fable5):
|
|
|
295
304
|
# %% ../nbs/00_types.ipynb #bb0c4c2a
|
|
296
305
|
sol,terra,luna = gpt56s = 'gpt-5.6-sol gpt-5.6-terra gpt-5.6-luna'.split()
|
|
297
306
|
for model in ['gpt-5.6']+gpt56s:
|
|
298
|
-
register_model_info(model, 'openai', base=model, base_vendor_name='openai'
|
|
299
|
-
|
|
307
|
+
register_model_info(model, 'openai', base=model, base_vendor_name='openai')
|
|
308
|
+
# Codex serves only the suffixed names; bare `gpt-5.6` is rejected with a ChatGPT account.
|
|
309
|
+
# Its window is smaller than the API's: 371,331 input tokens is accepted and 371,981 is not, on all three.
|
|
310
|
+
for model in gpt56s:
|
|
311
|
+
register_model_info(model, 'codex', base=model, base_vendor_name='openai', max_input_tokens=371_000, **codex_pricing)
|
|
312
|
+
_rm_ctx_tiers('codex', model)
|
|
300
313
|
|
|
301
314
|
# %% ../nbs/00_types.ipynb #24cc47ec
|
|
302
315
|
def get_model_pricing(mn, vendor_name, million=True):
|
|
@@ -320,6 +333,17 @@ def is_deepseek_peak_hour(dt=None):
|
|
|
320
333
|
h = dt.hour + dt.minute/60
|
|
321
334
|
return 1 <= h < 4 or 6 <= h < 10
|
|
322
335
|
|
|
336
|
+
# %% ../nbs/00_types.ipynb #4c701619
|
|
337
|
+
def price_tier(meta, n):
|
|
338
|
+
"Suffix of the pricing tier applying to `n` prompt tokens, or '' for base rates."
|
|
339
|
+
o = first(o for k in meta if (o:=re.match(r'input_cost_per_token(_above_(\d+)k_tokens)$', k)))
|
|
340
|
+
return o[1] if o and n>int(o[2])*1000 else ''
|
|
341
|
+
|
|
342
|
+
# %% ../nbs/00_types.ipynb #956d2495
|
|
343
|
+
def tier_rate(meta, key, tier):
|
|
344
|
+
"Rate for `key` at `tier`, falling back to the base key."
|
|
345
|
+
return meta.get(f'{key}{tier}') or meta[key]
|
|
346
|
+
|
|
323
347
|
# %% ../nbs/00_types.ipynb #8bfca02d
|
|
324
348
|
@patch(as_prop=True)
|
|
325
349
|
def cost(self:Completion):
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.0.34"
|
|
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.34 → python_fastllm-0.0.36}/python_fastllm.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|