python-fastllm 0.0.60__tar.gz → 0.0.61__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.
Files changed (23) hide show
  1. {python_fastllm-0.0.60 → python_fastllm-0.0.61}/PKG-INFO +16 -29
  2. {python_fastllm-0.0.60 → python_fastllm-0.0.61}/README.md +15 -28
  3. {python_fastllm-0.0.60 → python_fastllm-0.0.61}/fastllm/__init__.py +1 -1
  4. {python_fastllm-0.0.60 → python_fastllm-0.0.61}/fastllm/acomplete.py +1 -0
  5. {python_fastllm-0.0.60 → python_fastllm-0.0.61}/fastllm/model_prices.json +6517 -470
  6. {python_fastllm-0.0.60 → python_fastllm-0.0.61}/fastllm/openai_chat.py +1 -1
  7. {python_fastllm-0.0.60 → python_fastllm-0.0.61}/fastllm/types.py +20 -21
  8. {python_fastllm-0.0.60 → python_fastllm-0.0.61}/python_fastllm.egg-info/PKG-INFO +16 -29
  9. {python_fastllm-0.0.60 → python_fastllm-0.0.61}/fastllm/_modidx.py +0 -0
  10. {python_fastllm-0.0.60 → python_fastllm-0.0.61}/fastllm/anthropic.py +0 -0
  11. {python_fastllm-0.0.60 → python_fastllm-0.0.61}/fastllm/chat.py +0 -0
  12. {python_fastllm-0.0.60 → python_fastllm-0.0.61}/fastllm/codex.py +0 -0
  13. {python_fastllm-0.0.60 → python_fastllm-0.0.61}/fastllm/gemini.py +0 -0
  14. {python_fastllm-0.0.60 → python_fastllm-0.0.61}/fastllm/openai_responses.py +0 -0
  15. {python_fastllm-0.0.60 → python_fastllm-0.0.61}/fastllm/responses.py +0 -0
  16. {python_fastllm-0.0.60 → python_fastllm-0.0.61}/fastllm/streaming.py +0 -0
  17. {python_fastllm-0.0.60 → python_fastllm-0.0.61}/pyproject.toml +0 -0
  18. {python_fastllm-0.0.60 → python_fastllm-0.0.61}/python_fastllm.egg-info/SOURCES.txt +0 -0
  19. {python_fastllm-0.0.60 → python_fastllm-0.0.61}/python_fastllm.egg-info/dependency_links.txt +0 -0
  20. {python_fastllm-0.0.60 → python_fastllm-0.0.61}/python_fastllm.egg-info/entry_points.txt +0 -0
  21. {python_fastllm-0.0.60 → python_fastllm-0.0.61}/python_fastllm.egg-info/requires.txt +0 -0
  22. {python_fastllm-0.0.60 → python_fastllm-0.0.61}/python_fastllm.egg-info/top_level.txt +0 -0
  23. {python_fastllm-0.0.60 → python_fastllm-0.0.61}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-fastllm
3
- Version: 0.0.60
3
+ Version: 0.0.61
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
@@ -61,15 +61,11 @@ mtok = 1024
61
61
  Use the same `acomplete` interface with Claude, GPT, Gemini, or Kimi. Set `model` and any provider-specific routing arguments:
62
62
 
63
63
  ``` python
64
- models = [
65
- ('claude-sonnet-5', {}),
66
- ('gpt-4o-mini', {}),
67
- ('models/gemini-3-flash-preview', {}),
68
- ('accounts/fireworks/models/kimi-k3', dict(vendor_name='fireworks_ai'))
69
- ]
64
+ models = [('claude-sonnet-5', {}), ('gpt-4o-mini', {}), ('models/gemini-3-flash-preview', {}),
65
+ ('accounts/fireworks/models/kimi-k3', dict(vendor_name='fireworks_ai'))]
70
66
  for name, kw in models:
71
67
  r = await acomplete([user("Translate 'hello' into French. Return only the translation.")],
72
- model=name, max_tokens=mtok, **kw)
68
+ model=name, max_tokens=mtok, **kw)
73
69
  text = ''.join(p.text for p in r.message.content if isinstance(p, Text))
74
70
  print(f"{name}: {text.strip()}")
75
71
  ```
@@ -101,11 +97,8 @@ r = await stream([user("What should I do today?")], model='models/gemini-3-flash
101
97
  Define tools in the shared schema. `fastllm` translates it to the provider’s tool format. This example handles a tool request, adds the result to the history, and continues the conversation:
102
98
 
103
99
  ``` python
104
- tools = [{"type": "function", "function": {
105
- "name": "get_weather",
106
- "description": "Get current weather for a city",
107
- "parameters": {"type": "object", "properties": {"city": {"type": "string"}}, "required": ["city"]}
108
- }}]
100
+ tools = [{"type": "function", "function": dict(name="get_weather", description="Get current weather for a city",
101
+ parameters=dict(type="object", properties={"city": {"type": "string"}}, required=["city"]))}]
109
102
 
110
103
  msgs = [user("What's the weather in Paris?")]
111
104
  r1 = await stream(msgs, model='claude-sonnet-5', tools=tools, max_tokens=mtok)
@@ -118,7 +111,7 @@ print("Tool calls:", r1.tool_calls)
118
111
 
119
112
  ``` python
120
113
  msgs += [r1.message, mk_tool_res_msg(r1.tool_calls, ['22°C, sunny with light clouds']),
121
- user("Should I bring a jacket? Answer in one short sentence.")]
114
+ user("Should I bring a jacket? Answer in one short sentence.")]
122
115
  r2 = await stream(msgs, model='claude-sonnet-5', tools=tools, max_tokens=mtok)
123
116
  ```
124
117
 
@@ -129,12 +122,10 @@ r2 = await stream(msgs, model='claude-sonnet-5', tools=tools, max_tokens=mtok)
129
122
  Control whether the model must use tools, can’t use tools, or decides on its own:
130
123
 
131
124
  ``` python
132
- r = await acomplete([user("Hello there!")], model='claude-sonnet-5',
133
- tools=tools, tool_choice='required', max_tokens=mtok)
125
+ r = await acomplete([user('Hello there!')], model='claude-sonnet-5', tools=tools, tool_choice='required', max_tokens=mtok)
134
126
  print("Required:", [tc.name for tc in r.tool_calls])
135
127
 
136
- r = await acomplete([user("What's the weather?")], model='claude-sonnet-5',
137
- tools=tools, tool_choice='none', max_tokens=mtok)
128
+ r = await acomplete([user("What's the weather?")], model='claude-sonnet-5', tools=tools, tool_choice='none', max_tokens=mtok)
138
129
  print("None:", r.tool_calls)
139
130
  ```
140
131
 
@@ -148,14 +139,13 @@ Set `reasoning_effort` to `low`, `medium`, or `high` for supported models. The a
148
139
  ``` python
149
140
  print("Claude: ", end='')
150
141
  r = await stream([user("What is 127 × 849? Return just the number.")], model='claude-sonnet-4-6',
151
- reasoning_effort='low', max_tokens=8192)
142
+ reasoning_effort='low', max_tokens=8192)
152
143
  for p in r.message.content:
153
144
  if isinstance(p, Thinking): print(f"Thinking excerpt: {p.text[:150]}...")
154
145
 
155
146
  print("Kimi: ", end='')
156
- r = await stream([user("What is 127 × 849? Return just the number.")],
157
- model='accounts/fireworks/models/kimi-k3', vendor_name='fireworks_ai',
158
- reasoning_effort='low', max_tokens=8192)
147
+ r = await stream([user('What is 127 × 849? Return just the number.')], model='accounts/fireworks/models/kimi-k3',
148
+ vendor_name='fireworks_ai', reasoning_effort='low', max_tokens=8192)
159
149
  for p in r.message.content:
160
150
  if isinstance(p, Thinking): print(f"Thinking excerpt: {p.text[:150]}...")
161
151
  ```
@@ -172,7 +162,7 @@ OpenAI’s Responses API supports server-side web search. Server tool calls are
172
162
  ``` python
173
163
  ws_tools = [{"type": "web_search_preview"}]
174
164
  r = await acomplete([user("What is the latest Python release? Reply with the version number only.")],
175
- model='gpt-4o-mini', tools=ws_tools, max_tokens=512)
165
+ model='gpt-4o-mini', tools=ws_tools, max_tokens=512)
176
166
  print("Server tools used:", [tc.name for tc in r.tool_calls if tc.server])
177
167
  ```
178
168
 
@@ -187,11 +177,11 @@ long_ctx = "You are an expert on the solar system. " * 200
187
177
  system = Text(long_ctx, cache_control={'type': 'ephemeral'})
188
178
 
189
179
  r1 = await acomplete([user("What is Jupiter's mass? Answer in one sentence.")],
190
- model='claude-sonnet-5', system=system, max_tokens=mtok)
180
+ model='claude-sonnet-5', system=system, max_tokens=mtok)
191
181
  print("First call: cache creation tokens", r1.usage.cache_creation_tokens)
192
182
 
193
183
  r2 = await acomplete([user("What is Saturn's mass? Answer in one sentence.")],
194
- model='claude-sonnet-5', system=system, max_tokens=mtok)
184
+ model='claude-sonnet-5', system=system, max_tokens=mtok)
195
185
  print("Second call: cache read tokens", r2.usage.cached_tokens)
196
186
  ```
197
187
 
@@ -203,10 +193,7 @@ print("Second call: cache read tokens", r2.usage.cached_tokens)
203
193
  Use `InputImage` with a model that supports images. The example sends the same image message to three providers:
204
194
 
205
195
  ``` python
206
- img_msg = Msg(role='user', content=[
207
- InputImage(sample_img_url),
208
- Text("List three visible objects, using nouns only.")
209
- ])
196
+ img_msg = Msg(role='user', content=[InputImage(sample_img_url), Text('List three visible objects, using nouns only.')])
210
197
 
211
198
  for name, kw in [('claude-sonnet-5', {}), ('gpt-4o-mini', {}), ('models/gemini-3-flash-preview', {})]:
212
199
  print(f"{name}: ", end='')
@@ -45,15 +45,11 @@ mtok = 1024
45
45
  Use the same `acomplete` interface with Claude, GPT, Gemini, or Kimi. Set `model` and any provider-specific routing arguments:
46
46
 
47
47
  ``` python
48
- models = [
49
- ('claude-sonnet-5', {}),
50
- ('gpt-4o-mini', {}),
51
- ('models/gemini-3-flash-preview', {}),
52
- ('accounts/fireworks/models/kimi-k3', dict(vendor_name='fireworks_ai'))
53
- ]
48
+ models = [('claude-sonnet-5', {}), ('gpt-4o-mini', {}), ('models/gemini-3-flash-preview', {}),
49
+ ('accounts/fireworks/models/kimi-k3', dict(vendor_name='fireworks_ai'))]
54
50
  for name, kw in models:
55
51
  r = await acomplete([user("Translate 'hello' into French. Return only the translation.")],
56
- model=name, max_tokens=mtok, **kw)
52
+ model=name, max_tokens=mtok, **kw)
57
53
  text = ''.join(p.text for p in r.message.content if isinstance(p, Text))
58
54
  print(f"{name}: {text.strip()}")
59
55
  ```
@@ -85,11 +81,8 @@ r = await stream([user("What should I do today?")], model='models/gemini-3-flash
85
81
  Define tools in the shared schema. `fastllm` translates it to the provider’s tool format. This example handles a tool request, adds the result to the history, and continues the conversation:
86
82
 
87
83
  ``` python
88
- tools = [{"type": "function", "function": {
89
- "name": "get_weather",
90
- "description": "Get current weather for a city",
91
- "parameters": {"type": "object", "properties": {"city": {"type": "string"}}, "required": ["city"]}
92
- }}]
84
+ tools = [{"type": "function", "function": dict(name="get_weather", description="Get current weather for a city",
85
+ parameters=dict(type="object", properties={"city": {"type": "string"}}, required=["city"]))}]
93
86
 
94
87
  msgs = [user("What's the weather in Paris?")]
95
88
  r1 = await stream(msgs, model='claude-sonnet-5', tools=tools, max_tokens=mtok)
@@ -102,7 +95,7 @@ print("Tool calls:", r1.tool_calls)
102
95
 
103
96
  ``` python
104
97
  msgs += [r1.message, mk_tool_res_msg(r1.tool_calls, ['22°C, sunny with light clouds']),
105
- user("Should I bring a jacket? Answer in one short sentence.")]
98
+ user("Should I bring a jacket? Answer in one short sentence.")]
106
99
  r2 = await stream(msgs, model='claude-sonnet-5', tools=tools, max_tokens=mtok)
107
100
  ```
108
101
 
@@ -113,12 +106,10 @@ r2 = await stream(msgs, model='claude-sonnet-5', tools=tools, max_tokens=mtok)
113
106
  Control whether the model must use tools, can’t use tools, or decides on its own:
114
107
 
115
108
  ``` python
116
- r = await acomplete([user("Hello there!")], model='claude-sonnet-5',
117
- tools=tools, tool_choice='required', max_tokens=mtok)
109
+ r = await acomplete([user('Hello there!')], model='claude-sonnet-5', tools=tools, tool_choice='required', max_tokens=mtok)
118
110
  print("Required:", [tc.name for tc in r.tool_calls])
119
111
 
120
- r = await acomplete([user("What's the weather?")], model='claude-sonnet-5',
121
- tools=tools, tool_choice='none', max_tokens=mtok)
112
+ r = await acomplete([user("What's the weather?")], model='claude-sonnet-5', tools=tools, tool_choice='none', max_tokens=mtok)
122
113
  print("None:", r.tool_calls)
123
114
  ```
124
115
 
@@ -132,14 +123,13 @@ Set `reasoning_effort` to `low`, `medium`, or `high` for supported models. The a
132
123
  ``` python
133
124
  print("Claude: ", end='')
134
125
  r = await stream([user("What is 127 × 849? Return just the number.")], model='claude-sonnet-4-6',
135
- reasoning_effort='low', max_tokens=8192)
126
+ reasoning_effort='low', max_tokens=8192)
136
127
  for p in r.message.content:
137
128
  if isinstance(p, Thinking): print(f"Thinking excerpt: {p.text[:150]}...")
138
129
 
139
130
  print("Kimi: ", end='')
140
- r = await stream([user("What is 127 × 849? Return just the number.")],
141
- model='accounts/fireworks/models/kimi-k3', vendor_name='fireworks_ai',
142
- reasoning_effort='low', max_tokens=8192)
131
+ r = await stream([user('What is 127 × 849? Return just the number.')], model='accounts/fireworks/models/kimi-k3',
132
+ vendor_name='fireworks_ai', reasoning_effort='low', max_tokens=8192)
143
133
  for p in r.message.content:
144
134
  if isinstance(p, Thinking): print(f"Thinking excerpt: {p.text[:150]}...")
145
135
  ```
@@ -156,7 +146,7 @@ OpenAI’s Responses API supports server-side web search. Server tool calls are
156
146
  ``` python
157
147
  ws_tools = [{"type": "web_search_preview"}]
158
148
  r = await acomplete([user("What is the latest Python release? Reply with the version number only.")],
159
- model='gpt-4o-mini', tools=ws_tools, max_tokens=512)
149
+ model='gpt-4o-mini', tools=ws_tools, max_tokens=512)
160
150
  print("Server tools used:", [tc.name for tc in r.tool_calls if tc.server])
161
151
  ```
162
152
 
@@ -171,11 +161,11 @@ long_ctx = "You are an expert on the solar system. " * 200
171
161
  system = Text(long_ctx, cache_control={'type': 'ephemeral'})
172
162
 
173
163
  r1 = await acomplete([user("What is Jupiter's mass? Answer in one sentence.")],
174
- model='claude-sonnet-5', system=system, max_tokens=mtok)
164
+ model='claude-sonnet-5', system=system, max_tokens=mtok)
175
165
  print("First call: cache creation tokens", r1.usage.cache_creation_tokens)
176
166
 
177
167
  r2 = await acomplete([user("What is Saturn's mass? Answer in one sentence.")],
178
- model='claude-sonnet-5', system=system, max_tokens=mtok)
168
+ model='claude-sonnet-5', system=system, max_tokens=mtok)
179
169
  print("Second call: cache read tokens", r2.usage.cached_tokens)
180
170
  ```
181
171
 
@@ -187,10 +177,7 @@ print("Second call: cache read tokens", r2.usage.cached_tokens)
187
177
  Use `InputImage` with a model that supports images. The example sends the same image message to three providers:
188
178
 
189
179
  ``` python
190
- img_msg = Msg(role='user', content=[
191
- InputImage(sample_img_url),
192
- Text("List three visible objects, using nouns only.")
193
- ])
180
+ img_msg = Msg(role='user', content=[InputImage(sample_img_url), Text('List three visible objects, using nouns only.')])
194
181
 
195
182
  for name, kw in [('claude-sonnet-5', {}), ('gpt-4o-mini', {}), ('models/gemini-3-flash-preview', {})]:
196
183
  print(f"{name}: ", end='')
@@ -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.61"
@@ -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"),