chatlas 0.8.1__py3-none-any.whl → 0.9.1__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.

Potentially problematic release.


This version of chatlas might be problematic. Click here for more details.

chatlas/__init__.py CHANGED
@@ -2,7 +2,7 @@ from . import types
2
2
  from ._anthropic import ChatAnthropic, ChatBedrockAnthropic
3
3
  from ._auto import ChatAuto
4
4
  from ._chat import Chat
5
- from ._content import ContentToolRequest, ContentToolResult
5
+ from ._content import ContentToolRequest, ContentToolResult, ContentToolResultImage
6
6
  from ._content_image import content_image_file, content_image_plot, content_image_url
7
7
  from ._content_pdf import content_pdf_file, content_pdf_url
8
8
  from ._databricks import ChatDatabricks
@@ -46,6 +46,7 @@ __all__ = (
46
46
  "content_pdf_url",
47
47
  "ContentToolRequest",
48
48
  "ContentToolResult",
49
+ "ContentToolResultImage",
49
50
  "interpolate",
50
51
  "interpolate_file",
51
52
  "Provider",
chatlas/_anthropic.py CHANGED
@@ -17,12 +17,15 @@ from ._content import (
17
17
  ContentText,
18
18
  ContentToolRequest,
19
19
  ContentToolResult,
20
+ ContentToolResultImage,
21
+ ContentToolResultResource,
20
22
  )
21
23
  from ._logging import log_model_default
22
- from ._provider import Provider
24
+ from ._provider import Provider, StandardModelParamNames, StandardModelParams
23
25
  from ._tokens import tokens_log
24
26
  from ._tools import Tool, basemodel_to_param_schema
25
- from ._turn import Turn, normalize_turns, user_turn
27
+ from ._turn import Turn, user_turn
28
+ from ._utils import split_http_client_kwargs
26
29
 
27
30
  if TYPE_CHECKING:
28
31
  from anthropic.types import (
@@ -58,7 +61,6 @@ else:
58
61
  def ChatAnthropic(
59
62
  *,
60
63
  system_prompt: Optional[str] = None,
61
- turns: Optional[list[Turn]] = None,
62
64
  model: "Optional[ModelParam]" = None,
63
65
  api_key: Optional[str] = None,
64
66
  max_tokens: int = 4096,
@@ -104,13 +106,6 @@ def ChatAnthropic(
104
106
  ----------
105
107
  system_prompt
106
108
  A system prompt to set the behavior of the assistant.
107
- turns
108
- A list of turns to start the chat with (i.e., continuing a previous
109
- conversation). If not provided, the conversation begins from scratch. Do
110
- not provide non-None values for both `turns` and `system_prompt`. Each
111
- message in the list should be a dictionary with at least `role` (usually
112
- `system`, `user`, or `assistant`, but `tool` is also possible). Normally
113
- there is also a `content` field, which is a string.
114
109
  model
115
110
  The model to use for the chat. The default, None, will pick a reasonable
116
111
  default, and warn you about it. We strongly recommend explicitly
@@ -177,22 +172,23 @@ def ChatAnthropic(
177
172
  max_tokens=max_tokens,
178
173
  kwargs=kwargs,
179
174
  ),
180
- turns=normalize_turns(
181
- turns or [],
182
- system_prompt,
183
- ),
175
+ system_prompt=system_prompt,
184
176
  )
185
177
 
186
178
 
187
- class AnthropicProvider(Provider[Message, RawMessageStreamEvent, Message]):
179
+ class AnthropicProvider(
180
+ Provider[Message, RawMessageStreamEvent, Message, "SubmitInputArgs"]
181
+ ):
188
182
  def __init__(
189
183
  self,
190
184
  *,
191
- max_tokens: int,
185
+ max_tokens: int = 4096,
192
186
  model: str,
193
- api_key: str | None,
187
+ api_key: Optional[str] = None,
188
+ name: str = "Anthropic",
194
189
  kwargs: Optional["ChatClientArgs"] = None,
195
190
  ):
191
+ super().__init__(name=name, model=model)
196
192
  try:
197
193
  from anthropic import Anthropic, AsyncAnthropic
198
194
  except ImportError:
@@ -200,8 +196,6 @@ class AnthropicProvider(Provider[Message, RawMessageStreamEvent, Message]):
200
196
  "`ChatAnthropic()` requires the `anthropic` package. "
201
197
  "You can install it with 'pip install anthropic'."
202
198
  )
203
-
204
- self._model = model
205
199
  self._max_tokens = max_tokens
206
200
 
207
201
  kwargs_full: "ChatClientArgs" = {
@@ -209,9 +203,11 @@ class AnthropicProvider(Provider[Message, RawMessageStreamEvent, Message]):
209
203
  **(kwargs or {}),
210
204
  }
211
205
 
206
+ sync_kwargs, async_kwargs = split_http_client_kwargs(kwargs_full)
207
+
212
208
  # TODO: worth bringing in sync types?
213
- self._client = Anthropic(**kwargs_full) # type: ignore
214
- self._async_client = AsyncAnthropic(**kwargs_full)
209
+ self._client = Anthropic(**sync_kwargs) # type: ignore
210
+ self._async_client = AsyncAnthropic(**async_kwargs)
215
211
 
216
212
  @overload
217
213
  def chat_perform(
@@ -301,7 +297,7 @@ class AnthropicProvider(Provider[Message, RawMessageStreamEvent, Message]):
301
297
  """Extract structured data"""
302
298
  pass
303
299
 
304
- data_model_tool = Tool(_structured_tool_call)
300
+ data_model_tool = Tool.from_func(_structured_tool_call)
305
301
 
306
302
  data_model_tool.schema["function"]["parameters"] = {
307
303
  "type": "object",
@@ -322,7 +318,7 @@ class AnthropicProvider(Provider[Message, RawMessageStreamEvent, Message]):
322
318
  kwargs_full: "SubmitInputArgs" = {
323
319
  "stream": stream,
324
320
  "messages": self._as_message_params(turns),
325
- "model": self._model,
321
+ "model": self.model,
326
322
  "max_tokens": self._max_tokens,
327
323
  "tools": tool_schemas,
328
324
  **(kwargs or {}),
@@ -435,6 +431,34 @@ class AnthropicProvider(Provider[Message, RawMessageStreamEvent, Message]):
435
431
 
436
432
  return {arg: kwargs[arg] for arg in args_to_keep if arg in kwargs}
437
433
 
434
+ def translate_model_params(self, params: StandardModelParams) -> "SubmitInputArgs":
435
+ res: "SubmitInputArgs" = {}
436
+ if "temperature" in params:
437
+ res["temperature"] = params["temperature"]
438
+
439
+ if "top_p" in params:
440
+ res["top_p"] = params["top_p"]
441
+
442
+ if "top_k" in params:
443
+ res["top_k"] = params["top_k"]
444
+
445
+ if "max_tokens" in params:
446
+ res["max_tokens"] = params["max_tokens"]
447
+
448
+ if "stop_sequences" in params:
449
+ res["stop_sequences"] = params["stop_sequences"]
450
+
451
+ return res
452
+
453
+ def supported_model_params(self) -> set[StandardModelParamNames]:
454
+ return {
455
+ "temperature",
456
+ "top_p",
457
+ "top_k",
458
+ "max_tokens",
459
+ "stop_sequences",
460
+ }
461
+
438
462
  def _as_message_params(self, turns: list[Turn]) -> list["MessageParam"]:
439
463
  messages: list["MessageParam"] = []
440
464
  for turn in turns:
@@ -473,10 +497,13 @@ class AnthropicProvider(Provider[Message, RawMessageStreamEvent, Message]):
473
497
  },
474
498
  }
475
499
  elif isinstance(content, ContentImageRemote):
476
- raise NotImplementedError(
477
- "Remote images aren't supported by Anthropic (Claude). "
478
- "Consider downloading the image and using content_image_file() instead."
479
- )
500
+ return {
501
+ "type": "image",
502
+ "source": {
503
+ "type": "url",
504
+ "url": content.url,
505
+ },
506
+ }
480
507
  elif isinstance(content, ContentToolRequest):
481
508
  return {
482
509
  "type": "tool_use",
@@ -490,8 +517,26 @@ class AnthropicProvider(Provider[Message, RawMessageStreamEvent, Message]):
490
517
  "tool_use_id": content.id,
491
518
  "is_error": content.error is not None,
492
519
  }
493
- # Anthropic supports non-text contents like ImageBlockParam
494
- res["content"] = content.get_model_value() # type: ignore
520
+
521
+ if isinstance(content, ContentToolResultImage):
522
+ res["content"] = [
523
+ {
524
+ "type": "image",
525
+ "source": {
526
+ "type": "base64",
527
+ "media_type": content.mime_type,
528
+ "data": content.value,
529
+ },
530
+ }
531
+ ]
532
+ elif isinstance(content, ContentToolResultResource):
533
+ raise NotImplementedError(
534
+ "ContentToolResultResource is not currently supported by Anthropic."
535
+ )
536
+ else:
537
+ # Anthropic supports non-text contents like ImageBlockParam
538
+ res["content"] = content.get_model_value() # type: ignore
539
+
495
540
  return res
496
541
 
497
542
  raise ValueError(f"Unknown content type: {type(content)}")
@@ -565,7 +610,6 @@ def ChatBedrockAnthropic(
565
610
  aws_session_token: Optional[str] = None,
566
611
  base_url: Optional[str] = None,
567
612
  system_prompt: Optional[str] = None,
568
- turns: Optional[list[Turn]] = None,
569
613
  kwargs: Optional["ChatBedrockClientArgs"] = None,
570
614
  ) -> Chat["SubmitInputArgs", Message]:
571
615
  """
@@ -631,13 +675,6 @@ def ChatBedrockAnthropic(
631
675
  `f"https://bedrock-runtime.{aws_region}.amazonaws.com"`.
632
676
  system_prompt
633
677
  A system prompt to set the behavior of the assistant.
634
- turns
635
- A list of turns to start the chat with (i.e., continuing a previous
636
- conversation). If not provided, the conversation begins from scratch. Do
637
- not provide non-None values for both `turns` and `system_prompt`. Each
638
- message in the list should be a dictionary with at least `role` (usually
639
- `system`, `user`, or `assistant`, but `tool` is also possible). Normally
640
- there is also a `content` field, which is a string.
641
678
  kwargs
642
679
  Additional arguments to pass to the `anthropic.AnthropicBedrock()`
643
680
  client constructor.
@@ -711,10 +748,7 @@ def ChatBedrockAnthropic(
711
748
  base_url=base_url,
712
749
  kwargs=kwargs,
713
750
  ),
714
- turns=normalize_turns(
715
- turns or [],
716
- system_prompt,
717
- ),
751
+ system_prompt=system_prompt,
718
752
  )
719
753
 
720
754
 
@@ -728,10 +762,13 @@ class AnthropicBedrockProvider(AnthropicProvider):
728
762
  aws_region: str | None,
729
763
  aws_profile: str | None,
730
764
  aws_session_token: str | None,
731
- max_tokens: int,
765
+ max_tokens: int = 4096,
732
766
  base_url: str | None,
767
+ name: str = "AnthropicBedrock",
733
768
  kwargs: Optional["ChatBedrockClientArgs"] = None,
734
769
  ):
770
+ super().__init__(name=name, model=model, max_tokens=max_tokens)
771
+
735
772
  try:
736
773
  from anthropic import AnthropicBedrock, AsyncAnthropicBedrock
737
774
  except ImportError:
@@ -740,9 +777,6 @@ class AnthropicBedrockProvider(AnthropicProvider):
740
777
  "Install it with `pip install anthropic[bedrock]`."
741
778
  )
742
779
 
743
- self._model = model
744
- self._max_tokens = max_tokens
745
-
746
780
  kwargs_full: "ChatBedrockClientArgs" = {
747
781
  "aws_secret_key": aws_secret_key,
748
782
  "aws_access_key": aws_access_key,
chatlas/_auto.py CHANGED
@@ -15,7 +15,6 @@ from ._ollama import ChatOllama
15
15
  from ._openai import ChatAzureOpenAI, ChatOpenAI
16
16
  from ._perplexity import ChatPerplexity
17
17
  from ._snowflake import ChatSnowflake
18
- from ._turn import Turn
19
18
 
20
19
  AutoProviders = Literal[
21
20
  "anthropic",
@@ -50,7 +49,6 @@ _provider_chat_model_map: dict[AutoProviders, Callable[..., Chat]] = {
50
49
 
51
50
  def ChatAuto(
52
51
  system_prompt: Optional[str] = None,
53
- turns: Optional[list[Turn]] = None,
54
52
  *,
55
53
  provider: Optional[AutoProviders] = None,
56
54
  model: Optional[str] = None,
@@ -111,6 +109,8 @@ def ChatAuto(
111
109
 
112
110
  Parameters
113
111
  ----------
112
+ system_prompt
113
+ A system prompt to set the behavior of the assistant.
114
114
  provider
115
115
  The name of the default chat provider to use. Providers are strings
116
116
  formatted in kebab-case, e.g. to use `ChatBedrockAnthropic` set
@@ -123,15 +123,6 @@ def ChatAuto(
123
123
  The name of the default model to use. This value can also be provided
124
124
  via the `CHATLAS_CHAT_MODEL` environment variable, which takes
125
125
  precedence over `model` when set.
126
- system_prompt
127
- A system prompt to set the behavior of the assistant.
128
- turns
129
- A list of turns to start the chat with (i.e., continuing a previous
130
- conversation). If not provided, the conversation begins from scratch. Do
131
- not provide non-`None` values for both `turns` and `system_prompt`. Each
132
- message in the list should be a dictionary with at least `role` (usually
133
- `system`, `user`, or `assistant`, but `tool` is also possible). Normally
134
- there is also a `content` field, which is a string.
135
126
  **kwargs
136
127
  Additional keyword arguments to pass to the Chat constructor. See the
137
128
  documentation for each provider for more details on the available
@@ -169,7 +160,7 @@ def ChatAuto(
169
160
  )
170
161
 
171
162
  # `system_prompt` and `turns` always come from `ChatAuto()`
172
- base_args = {"system_prompt": system_prompt, "turns": turns}
163
+ base_args = {"system_prompt": system_prompt}
173
164
 
174
165
  if env_model := os.environ.get("CHATLAS_CHAT_MODEL"):
175
166
  model = env_model