python-fastllm 0.0.60__py3-none-any.whl → 0.0.62__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 CHANGED
@@ -2,4 +2,4 @@
2
2
 
3
3
  - `fastllm.responses`: Provider-independent Responses resources and streaming over FastLLM"""
4
4
 
5
- __version__ = "0.0.60"
5
+ __version__ = "0.0.62"
fastllm/acomplete.py CHANGED
@@ -33,6 +33,7 @@ vendor_mapping = {
33
33
  "codex": ('openai', 'https://chatgpt.com/backend-api/codex', 'CODEX_AUTH_TOKEN', _codex_json),
34
34
  "moonshot": ('openai_chat', "https://api.moonshot.ai/v1", "MOONSHOT_API_KEY"),
35
35
  "deepseek": ('openai_chat', "https://api.deepseek.com/v1", "DEEPSEEK_API_KEY"),
36
+ "inception": ('openai_chat', "https://api.inceptionlabs.ai/v1", "INCEPTION_API_KEY"),
36
37
  "mimo": ('anthropic', "https://api.xiaomimimo.com/anthropic", "MIMO_API_KEY"),
37
38
  "openrouter": ('openai_chat', "https://openrouter.ai/api/v1", "OPENROUTER_API_KEY"),
38
39
  "together": ('openai_chat', "https://api.together.xyz/v1", "TOGETHER_API_KEY"),
@@ -167,20 +168,23 @@ async def acomplete(msgs, model, api_name=None, vendor_name=None, api_key=None,
167
168
  if own:
168
169
  vendor_name = ifnone(vendor_name, api_name) # an own-transport api: no HTTP client to build
169
170
  if oauth_token: kwargs['oauth_token'] = oauth_token # its `mk_payload` applies the user's token itself
170
- else: cli, api_name, vendor_name = mk_client(model=model, vendor_name=vendor_name, api_name=api_name, api_key=api_key, oauth_token=oauth_token, base_url=base_url, xtra_hdrs=xtra_hdrs)
171
+ else: cli, api_name, vendor_name = mk_client(model=model, vendor_name=vendor_name, api_name=api_name, api_key=api_key, oauth_token=oauth_token, base_url=base_url)
171
172
  api = api_registry[api_name]
172
173
  if previous_response_id is not None:
173
174
  if not getattr(api, 'supports_previous_response_id', False):
174
175
  raise ValueError('previous_response_id is not supported by this transport')
175
176
  kwargs['previous_response_id'] = previous_response_id
176
177
  payload = api.mk_payload(msgs, model, stream=stream, **kwargs)
177
- xtra_body = ifnone(xtra_body, {})
178
178
  if fix := getattr(api, 'fix_payload', None): fix(payload, model, vendor_name)
179
+ body = payload | ifnone(xtra_body, {})
179
180
  if not own:
181
+ headers = xtra_hdrs or {}
182
+ if vendor_name == 'codex' and (key := body.get('prompt_cache_key')):
183
+ if not any(k.lower() == 'session-id' for k in headers): headers = {**headers, 'session-id':key}
180
184
  ep = endpoint or api.endpoint
181
185
  path,params = ep(model, stream) if callable(ep) else (ep, None)
182
- if defaults.debug_mode: _debug_print(model, api_name, vendor_name, payload | xtra_body, None if own else cli._url(path))
183
- async def _call(): return await provider_req(cli, path, payload | xtra_body, params=params, stream=stream)
186
+ if defaults.debug_mode: _debug_print(model, api_name, vendor_name, body, None if own else cli._url(path))
187
+ async def _call(): return await provider_req(cli, path, body, params=params, stream=stream, headers=headers)
184
188
  async def _mk_gen():
185
189
  resp = payload if own else await _call() # an own-transport api's `acollect_stream` makes the request itself, from the payload
186
190
  async for o in api.acollect_stream(resp, model=model, vendor_name=vendor_name, stop_callables=stop_callables): yield o
fastllm/chat.py CHANGED
@@ -9,6 +9,7 @@ __all__ = ['effort', 'contents', 'stop_reason', 'cite_footnote', 'postproc', 'Re
9
9
  'StopSequencesCallback', 'StreamAccum', 'adisplay_stream']
10
10
 
11
11
  # %% ../nbs/07_chat.ipynb #d5a3bc1f
12
+ import secrets
12
13
  from typing import Optional,Callable
13
14
  from fastcore.funccall import mk_ns, call_func, call_func_async, get_schema
14
15
  from fastcore.utils import *
@@ -168,6 +169,7 @@ class AsyncChat:
168
169
  cache=False, # Anthropic prompt caching
169
170
  cache_idxs:list=[-1], # Anthropic cache breakpoint idxs, use `0` for sys prompt if provided
170
171
  ttl=None, # Anthropic prompt caching ttl
172
+ prompt_cache_key=None, # Stable conversation key for OpenAI Responses; generated once if omitted
171
173
  api_name=None, # API to use, one of ApiName: openai (responses), openai_chat, anthropic, gemini
172
174
  vendor_name=None, # Vendor name, one of vendor_mapping which resolves api_base/api_key automatically
173
175
  api_key=None, # API key when model can't be resolved or vendor_name is not known or codex
@@ -195,6 +197,7 @@ class AsyncChat:
195
197
  self.response_id,self._response_hist_idx = None,0
196
198
  self._turn_start = 0 # index into `hist` where the current turn began, for `full`
197
199
  self.last_req_use = None # usage of the latest request only; `use` accumulates across a turn's tool-call steps
200
+ if prompt_cache_key is None: prompt_cache_key = secrets.token_hex(16)
198
201
  store_attr(but='cbs')
199
202
  self.cbs = L()
200
203
  if default_cbs: self.add_cbs(defaults.chat_callbacks)
@@ -256,6 +259,7 @@ def _prep_call(self:AsyncChat, search, max_tokens, kwargs, stream=False, think=N
256
259
  if self.base_url: kwargs['base_url'] = self.base_url
257
260
  if self.endpoint: kwargs['endpoint'] = self.endpoint
258
261
  if self.extra_headers: kwargs['xtra_hdrs'] = self.extra_headers
262
+ kwargs.setdefault('prompt_cache_key', self.prompt_cache_key)
259
263
  kwargs.update(_think_kw(self.model, think, self.vendor_name))
260
264
  return max_tokens
261
265