model-library 0.1.0__py3-none-any.whl → 0.1.2__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.
Files changed (42) hide show
  1. model_library/__init__.py +7 -3
  2. model_library/base/__init__.py +7 -0
  3. model_library/{base.py → base/base.py} +47 -423
  4. model_library/base/batch.py +121 -0
  5. model_library/base/delegate_only.py +94 -0
  6. model_library/base/input.py +100 -0
  7. model_library/base/output.py +175 -0
  8. model_library/base/utils.py +42 -0
  9. model_library/config/all_models.json +164 -2
  10. model_library/config/anthropic_models.yaml +4 -0
  11. model_library/config/deepseek_models.yaml +3 -1
  12. model_library/config/openai_models.yaml +48 -0
  13. model_library/exceptions.py +2 -0
  14. model_library/logging.py +30 -0
  15. model_library/providers/__init__.py +0 -0
  16. model_library/providers/ai21labs.py +2 -0
  17. model_library/providers/alibaba.py +16 -78
  18. model_library/providers/amazon.py +3 -0
  19. model_library/providers/anthropic.py +213 -2
  20. model_library/providers/azure.py +2 -0
  21. model_library/providers/cohere.py +14 -80
  22. model_library/providers/deepseek.py +14 -90
  23. model_library/providers/fireworks.py +17 -81
  24. model_library/providers/google/google.py +22 -20
  25. model_library/providers/inception.py +15 -83
  26. model_library/providers/kimi.py +15 -83
  27. model_library/providers/mistral.py +2 -0
  28. model_library/providers/openai.py +2 -0
  29. model_library/providers/perplexity.py +12 -79
  30. model_library/providers/together.py +2 -0
  31. model_library/providers/vals.py +2 -0
  32. model_library/providers/xai.py +2 -0
  33. model_library/providers/zai.py +15 -83
  34. model_library/register_models.py +75 -55
  35. model_library/registry_utils.py +5 -5
  36. model_library/utils.py +3 -28
  37. {model_library-0.1.0.dist-info → model_library-0.1.2.dist-info}/METADATA +36 -7
  38. model_library-0.1.2.dist-info/RECORD +61 -0
  39. model_library-0.1.0.dist-info/RECORD +0 -53
  40. {model_library-0.1.0.dist-info → model_library-0.1.2.dist-info}/WHEEL +0 -0
  41. {model_library-0.1.0.dist-info → model_library-0.1.2.dist-info}/licenses/LICENSE +0 -0
  42. {model_library-0.1.0.dist-info → model_library-0.1.2.dist-info}/top_level.txt +0 -0
@@ -3,31 +3,20 @@ See deepseek data retention policy
3
3
  https://cdn.deepseek.com/policies/en-US/deepseek-privacy-policy.html
4
4
  """
5
5
 
6
- import io
7
- from typing import Any, Literal, Sequence
8
-
9
- from typing_extensions import override
6
+ from typing import Literal
10
7
 
11
8
  from model_library import model_library_settings
12
9
  from model_library.base import (
13
- LLM,
14
- FileInput,
15
- FileWithId,
16
- InputItem,
10
+ DelegateOnly,
17
11
  LLMConfig,
18
- QueryResult,
19
- ToolDefinition,
20
12
  )
21
- from model_library.exceptions import ToolCallingNotSupportedError
22
13
  from model_library.providers.openai import OpenAIModel
14
+ from model_library.register_models import register_provider
23
15
  from model_library.utils import create_openai_client_with_defaults
24
16
 
25
17
 
26
- class DeepSeekModel(LLM):
27
- @override
28
- def get_client(self) -> None:
29
- raise NotImplementedError("Not implemented")
30
-
18
+ @register_provider("deepseek")
19
+ class DeepSeekModel(DelegateOnly):
31
20
  def __init__(
32
21
  self,
33
22
  model_name: str,
@@ -36,80 +25,15 @@ class DeepSeekModel(LLM):
36
25
  config: LLMConfig | None = None,
37
26
  ):
38
27
  super().__init__(model_name, provider, config=config)
39
- self.model_name: str = model_name
40
- self.native: bool = False
41
28
 
42
29
  # https://api-docs.deepseek.com/
43
- self.delegate: OpenAIModel | None = (
44
- None
45
- if self.native
46
- else OpenAIModel(
47
- model_name=self.model_name,
48
- provider=provider,
49
- config=config,
50
- custom_client=create_openai_client_with_defaults(
51
- api_key=model_library_settings.DEEPSEEK_API_KEY,
52
- base_url="https://api.deepseek.com",
53
- ),
54
- use_completions=True,
55
- )
30
+ self.delegate = OpenAIModel(
31
+ model_name=self.model_name,
32
+ provider=self.provider,
33
+ config=config,
34
+ custom_client=create_openai_client_with_defaults(
35
+ api_key=model_library_settings.DEEPSEEK_API_KEY,
36
+ base_url="https://api.deepseek.com",
37
+ ),
38
+ use_completions=True,
56
39
  )
57
-
58
- @override
59
- async def parse_input(
60
- self,
61
- input: Sequence[InputItem],
62
- **kwargs: Any,
63
- ) -> Any:
64
- raise NotImplementedError()
65
-
66
- @override
67
- async def parse_image(
68
- self,
69
- image: FileInput,
70
- ) -> Any:
71
- raise NotImplementedError()
72
-
73
- @override
74
- async def parse_file(
75
- self,
76
- file: FileInput,
77
- ) -> Any:
78
- raise NotImplementedError()
79
-
80
- @override
81
- async def parse_tools(
82
- self,
83
- tools: list[ToolDefinition],
84
- ) -> Any:
85
- raise NotImplementedError()
86
-
87
- @override
88
- async def upload_file(
89
- self,
90
- name: str,
91
- mime: str,
92
- bytes: io.BytesIO,
93
- type: Literal["image", "file"] = "file",
94
- ) -> FileWithId:
95
- raise NotImplementedError()
96
-
97
- @override
98
- async def _query_impl(
99
- self,
100
- input: Sequence[InputItem],
101
- *,
102
- tools: list[ToolDefinition],
103
- **kwargs: object,
104
- ) -> QueryResult:
105
- # DeepSeek reasoning models don't support tools - they auto-route to chat model
106
- # which loses reasoning capability
107
- if tools and not self.supports_tools:
108
- raise ToolCallingNotSupportedError(
109
- f"DeepSeek model ({self.model_name}) does not support tools. "
110
- f"Use deepseek/deepseek-chat for tool calls."
111
- )
112
-
113
- if self.delegate:
114
- return await self.delegate_query(input, tools=tools, **kwargs)
115
- raise NotImplementedError()
@@ -1,22 +1,17 @@
1
- import io
2
- from typing import Any, Literal, Sequence
1
+ from typing import Literal
3
2
 
4
3
  from typing_extensions import override
5
4
 
6
5
  from model_library import model_library_settings
7
6
  from model_library.base import (
8
- LLM,
9
- FileInput,
10
- FileWithId,
11
- InputItem,
12
7
  LLMConfig,
13
8
  ProviderConfig,
14
- QueryResult,
15
9
  QueryResultCost,
16
10
  QueryResultMetadata,
17
- ToolDefinition,
18
11
  )
12
+ from model_library.base.delegate_only import DelegateOnly
19
13
  from model_library.providers.openai import OpenAIModel
14
+ from model_library.register_models import register_provider
20
15
  from model_library.utils import create_openai_client_with_defaults
21
16
 
22
17
 
@@ -24,13 +19,10 @@ class FireworksConfig(ProviderConfig):
24
19
  serverless: bool = True
25
20
 
26
21
 
27
- class FireworksModel(LLM):
22
+ @register_provider("fireworks")
23
+ class FireworksModel(DelegateOnly):
28
24
  provider_config = FireworksConfig()
29
25
 
30
- @override
31
- def get_client(self) -> None:
32
- raise NotImplementedError("Not implemented")
33
-
34
26
  def __init__(
35
27
  self,
36
28
  model_name: str,
@@ -45,76 +37,18 @@ class FireworksModel(LLM):
45
37
  else:
46
38
  self.model_name = "accounts/rayan-936e28/deployedModels/" + self.model_name
47
39
 
48
- # not using Fireworks SDK
49
- self.native: bool = False
50
-
51
40
  # https://docs.fireworks.ai/tools-sdks/openai-compatibility
52
- self.delegate: OpenAIModel | None = (
53
- None
54
- if self.native
55
- else OpenAIModel(
56
- model_name=self.model_name,
57
- provider=provider,
58
- config=config,
59
- custom_client=create_openai_client_with_defaults(
60
- api_key=model_library_settings.FIREWORKS_API_KEY,
61
- base_url="https://api.fireworks.ai/inference/v1",
62
- ),
63
- use_completions=True,
64
- )
41
+ self.delegate = OpenAIModel(
42
+ model_name=self.model_name,
43
+ provider=self.provider,
44
+ config=config,
45
+ custom_client=create_openai_client_with_defaults(
46
+ api_key=model_library_settings.FIREWORKS_API_KEY,
47
+ base_url="https://api.fireworks.ai/inference/v1",
48
+ ),
49
+ use_completions=True,
65
50
  )
66
51
 
67
- @override
68
- async def parse_input(
69
- self,
70
- input: Sequence[InputItem],
71
- **kwargs: Any,
72
- ) -> Any:
73
- raise NotImplementedError()
74
-
75
- @override
76
- async def parse_image(
77
- self,
78
- image: FileInput,
79
- ) -> Any:
80
- raise NotImplementedError()
81
-
82
- @override
83
- async def parse_file(
84
- self,
85
- file: FileInput,
86
- ) -> Any:
87
- raise NotImplementedError()
88
-
89
- @override
90
- async def parse_tools(
91
- self,
92
- tools: list[ToolDefinition],
93
- ) -> Any:
94
- raise NotImplementedError()
95
-
96
- @override
97
- async def upload_file(
98
- self,
99
- name: str,
100
- mime: str,
101
- bytes: io.BytesIO,
102
- type: Literal["image", "file"] = "file",
103
- ) -> FileWithId:
104
- raise NotImplementedError()
105
-
106
- @override
107
- async def _query_impl(
108
- self,
109
- input: Sequence[InputItem],
110
- *,
111
- tools: list[ToolDefinition],
112
- **kwargs: object,
113
- ) -> QueryResult:
114
- if self.delegate:
115
- return await self.delegate_query(input, tools=tools, **kwargs)
116
- raise NotImplementedError()
117
-
118
52
  @override
119
53
  async def _calculate_cost(
120
54
  self,
@@ -130,4 +64,6 @@ class FireworksModel(LLM):
130
64
  # https://docs.fireworks.ai/faq-new/billing-pricing/is-prompt-caching-billed-differently
131
65
  # prompt caching does not affect billing for serverless models
132
66
 
133
- return await super()._calculate_cost(metadata, batch, bill_reasoning=True)
67
+ return await super()._calculate_cost(
68
+ metadata, batch, bill_reasoning=bill_reasoning
69
+ )
@@ -2,6 +2,26 @@ import base64
2
2
  import io
3
3
  from typing import Any, Literal, Sequence, cast
4
4
 
5
+ from typing_extensions import override
6
+
7
+ from google.genai import Client
8
+ from google.genai import errors as genai_errors
9
+ from google.genai.types import (
10
+ Content,
11
+ File,
12
+ FunctionDeclaration,
13
+ GenerateContentConfig,
14
+ GenerateContentResponse,
15
+ GenerateContentResponseUsageMetadata,
16
+ HarmBlockThreshold,
17
+ HarmCategory,
18
+ Part,
19
+ SafetySetting,
20
+ ThinkingConfig,
21
+ Tool,
22
+ ToolListUnion,
23
+ UploadFileConfig,
24
+ )
5
25
  from model_library import model_library_settings
6
26
  from model_library.base import (
7
27
  LLM,
@@ -30,27 +50,8 @@ from model_library.exceptions import (
30
50
  ModelNoOutputError,
31
51
  )
32
52
  from model_library.providers.google.batch import GoogleBatchMixin
53
+ from model_library.register_models import register_provider
33
54
  from model_library.utils import normalize_tool_result
34
- from typing_extensions import override
35
-
36
- from google.genai import Client
37
- from google.genai import errors as genai_errors
38
- from google.genai.types import (
39
- Content,
40
- File,
41
- FunctionDeclaration,
42
- GenerateContentConfig,
43
- GenerateContentResponse,
44
- GenerateContentResponseUsageMetadata,
45
- HarmBlockThreshold,
46
- HarmCategory,
47
- Part,
48
- SafetySetting,
49
- ThinkingConfig,
50
- Tool,
51
- ToolListUnion,
52
- UploadFileConfig,
53
- )
54
55
 
55
56
 
56
57
  class GoogleConfig(ProviderConfig):
@@ -58,6 +59,7 @@ class GoogleConfig(ProviderConfig):
58
59
  use_interactions: bool = False
59
60
 
60
61
 
62
+ @register_provider("google")
61
63
  class GoogleModel(LLM):
62
64
  provider_config = GoogleConfig()
63
65
 
@@ -1,27 +1,17 @@
1
- import io
2
- from typing import Any, Literal, Sequence
3
-
4
- from typing_extensions import override
1
+ from typing import Literal
5
2
 
6
3
  from model_library import model_library_settings
7
4
  from model_library.base import (
8
- LLM,
9
- FileInput,
10
- FileWithId,
11
- InputItem,
5
+ DelegateOnly,
12
6
  LLMConfig,
13
- QueryResult,
14
- ToolDefinition,
15
7
  )
16
8
  from model_library.providers.openai import OpenAIModel
9
+ from model_library.register_models import register_provider
17
10
  from model_library.utils import create_openai_client_with_defaults
18
11
 
19
12
 
20
- class MercuryModel(LLM):
21
- @override
22
- def get_client(self) -> None:
23
- raise NotImplementedError("Not implemented")
24
-
13
+ @register_provider("inception")
14
+ class MercuryModel(DelegateOnly):
25
15
  def __init__(
26
16
  self,
27
17
  model_name: str,
@@ -30,73 +20,15 @@ class MercuryModel(LLM):
30
20
  config: LLMConfig | None = None,
31
21
  ):
32
22
  super().__init__(model_name, provider, config=config)
33
- self.model_name: str = model_name
34
- self.native: bool = False
35
23
 
36
- # https://docs.inceptionlabs.ai/get-started/models
37
- self.delegate: OpenAIModel | None = (
38
- None
39
- if self.native
40
- else OpenAIModel(
41
- model_name=self.model_name,
42
- provider=provider,
43
- config=config,
44
- custom_client=create_openai_client_with_defaults(
45
- api_key=model_library_settings.MERCURY_API_KEY,
46
- base_url="https://api.inceptionlabs.ai/v1/",
47
- ),
48
- use_completions=True,
49
- )
24
+ # https://docs.inceptionlabs.ai/get-started/get-started#external-libraries-compatibility
25
+ self.delegate = OpenAIModel(
26
+ model_name=self.model_name,
27
+ provider=self.provider,
28
+ config=config,
29
+ custom_client=create_openai_client_with_defaults(
30
+ api_key=model_library_settings.MERCURY_API_KEY,
31
+ base_url="https://api.inceptionlabs.ai/v1/",
32
+ ),
33
+ use_completions=True,
50
34
  )
51
-
52
- @override
53
- async def parse_input(
54
- self,
55
- input: Sequence[InputItem],
56
- **kwargs: Any,
57
- ) -> Any:
58
- raise NotImplementedError()
59
-
60
- @override
61
- async def parse_image(
62
- self,
63
- image: FileInput,
64
- ) -> Any:
65
- raise NotImplementedError()
66
-
67
- @override
68
- async def parse_file(
69
- self,
70
- file: FileInput,
71
- ) -> Any:
72
- raise NotImplementedError()
73
-
74
- @override
75
- async def parse_tools(
76
- self,
77
- tools: list[ToolDefinition],
78
- ) -> Any:
79
- raise NotImplementedError()
80
-
81
- @override
82
- async def upload_file(
83
- self,
84
- name: str,
85
- mime: str,
86
- bytes: io.BytesIO,
87
- type: Literal["image", "file"] = "file",
88
- ) -> FileWithId:
89
- raise NotImplementedError()
90
-
91
- @override
92
- async def _query_impl(
93
- self,
94
- input: Sequence[InputItem],
95
- *,
96
- tools: list[ToolDefinition],
97
- **kwargs: object,
98
- ) -> QueryResult:
99
- # relies on OpenAI delegate
100
- if self.delegate:
101
- return await self.delegate_query(input, tools=tools, **kwargs)
102
- raise NotImplementedError()
@@ -1,27 +1,17 @@
1
- import io
2
- from typing import Any, Literal, Sequence
3
-
4
- from typing_extensions import override
1
+ from typing import Literal
5
2
 
6
3
  from model_library import model_library_settings
7
4
  from model_library.base import (
8
- LLM,
9
- FileInput,
10
- FileWithId,
11
- InputItem,
5
+ DelegateOnly,
12
6
  LLMConfig,
13
- QueryResult,
14
- ToolDefinition,
15
7
  )
16
8
  from model_library.providers.openai import OpenAIModel
9
+ from model_library.register_models import register_provider
17
10
  from model_library.utils import create_openai_client_with_defaults
18
11
 
19
12
 
20
- class KimiModel(LLM):
21
- @override
22
- def get_client(self) -> None:
23
- raise NotImplementedError("Not implemented")
24
-
13
+ @register_provider("kimi")
14
+ class KimiModel(DelegateOnly):
25
15
  def __init__(
26
16
  self,
27
17
  model_name: str,
@@ -30,73 +20,15 @@ class KimiModel(LLM):
30
20
  config: LLMConfig | None = None,
31
21
  ):
32
22
  super().__init__(model_name, provider, config=config)
33
- self.model_name: str = model_name
34
- self.native: bool = False
35
23
 
36
- # https://platform.moonshot.ai/docs
37
- self.delegate: OpenAIModel | None = (
38
- None
39
- if self.native
40
- else OpenAIModel(
41
- model_name=self.model_name,
42
- provider=provider,
43
- config=config,
44
- custom_client=create_openai_client_with_defaults(
45
- api_key=model_library_settings.KIMI_API_KEY,
46
- base_url="https://api.moonshot.ai/v1/",
47
- ),
48
- use_completions=True,
49
- )
24
+ # https://platform.moonshot.ai/docs/guide/migrating-from-openai-to-kimi#about-api-compatibility
25
+ self.delegate = OpenAIModel(
26
+ model_name=self.model_name,
27
+ provider=self.provider,
28
+ config=config,
29
+ custom_client=create_openai_client_with_defaults(
30
+ api_key=model_library_settings.KIMI_API_KEY,
31
+ base_url="https://api.moonshot.ai/v1/",
32
+ ),
33
+ use_completions=True,
50
34
  )
51
-
52
- @override
53
- async def parse_input(
54
- self,
55
- input: Sequence[InputItem],
56
- **kwargs: Any,
57
- ) -> Any:
58
- raise NotImplementedError()
59
-
60
- @override
61
- async def parse_image(
62
- self,
63
- image: FileInput,
64
- ) -> Any:
65
- raise NotImplementedError()
66
-
67
- @override
68
- async def parse_file(
69
- self,
70
- file: FileInput,
71
- ) -> Any:
72
- raise NotImplementedError()
73
-
74
- @override
75
- async def parse_tools(
76
- self,
77
- tools: list[ToolDefinition],
78
- ) -> Any:
79
- raise NotImplementedError()
80
-
81
- @override
82
- async def upload_file(
83
- self,
84
- name: str,
85
- mime: str,
86
- bytes: io.BytesIO,
87
- type: Literal["image", "file"] = "file",
88
- ) -> FileWithId:
89
- raise NotImplementedError()
90
-
91
- @override
92
- async def _query_impl(
93
- self,
94
- input: Sequence[InputItem],
95
- *,
96
- tools: list[ToolDefinition],
97
- **kwargs: object,
98
- ) -> QueryResult:
99
- # relies on oAI delegate
100
- if self.delegate:
101
- return await self.delegate_query(input, tools=tools, **kwargs)
102
- raise NotImplementedError()
@@ -31,9 +31,11 @@ from model_library.exceptions import (
31
31
  MaxOutputTokensExceededError,
32
32
  )
33
33
  from model_library.file_utils import trim_images
34
+ from model_library.register_models import register_provider
34
35
  from model_library.utils import default_httpx_client
35
36
 
36
37
 
38
+ @register_provider("mistralai")
37
39
  class MistralModel(LLM):
38
40
  _client: Mistral | None = None
39
41
 
@@ -50,6 +50,7 @@ from model_library.exceptions import (
50
50
  ModelNoOutputError,
51
51
  )
52
52
  from model_library.model_utils import get_reasoning_in_tag
53
+ from model_library.register_models import register_provider
53
54
  from model_library.utils import create_openai_client_with_defaults
54
55
 
55
56
 
@@ -226,6 +227,7 @@ class OpenAIConfig(ProviderConfig):
226
227
  deep_research: bool = False
227
228
 
228
229
 
230
+ @register_provider("openai")
229
231
  class OpenAIModel(LLM):
230
232
  provider_config = OpenAIConfig()
231
233
 
@@ -1,30 +1,17 @@
1
- import io
2
- from typing import Any, Literal, Sequence
3
-
4
- from openai import AsyncOpenAI
5
- from typing_extensions import override
1
+ from typing import Literal
6
2
 
7
3
  from model_library import model_library_settings
8
4
  from model_library.base import (
9
- LLM,
10
- FileInput,
11
- FileWithId,
12
- InputItem,
5
+ DelegateOnly,
13
6
  LLMConfig,
14
- QueryResult,
15
- ToolDefinition,
16
7
  )
17
8
  from model_library.providers.openai import OpenAIModel
9
+ from model_library.register_models import register_provider
18
10
  from model_library.utils import create_openai_client_with_defaults
19
11
 
20
12
 
21
- class PerplexityModel(LLM):
22
- """Perplexity Sonar models via OpenAI-compatible API."""
23
-
24
- @override
25
- def get_client(self) -> None: # pragma: no cover - delegate is used instead
26
- raise NotImplementedError("Perplexity models are accessed via delegate client")
27
-
13
+ @register_provider("perplexity")
14
+ class PerplexityModel(DelegateOnly):
28
15
  def __init__(
29
16
  self,
30
17
  model_name: str,
@@ -33,69 +20,15 @@ class PerplexityModel(LLM):
33
20
  config: LLMConfig | None = None,
34
21
  ):
35
22
  super().__init__(model_name, provider, config=config)
36
- self.native = False
37
- client: AsyncOpenAI = create_openai_client_with_defaults(
38
- api_key=model_library_settings.PERPLEXITY_API_KEY,
39
- base_url="https://api.perplexity.ai",
40
- )
41
23
 
24
+ # https://docs.perplexity.ai/guides/chat-completions-guide
42
25
  self.delegate = OpenAIModel(
43
- model_name=model_name,
44
- provider=provider,
26
+ model_name=self.model_name,
27
+ provider=self.provider,
45
28
  config=config,
46
- custom_client=client,
29
+ custom_client=create_openai_client_with_defaults(
30
+ api_key=model_library_settings.PERPLEXITY_API_KEY,
31
+ base_url="https://api.perplexity.ai",
32
+ ),
47
33
  use_completions=True,
48
34
  )
49
-
50
- @override
51
- async def parse_input(
52
- self,
53
- input: Sequence[InputItem],
54
- **kwargs: object,
55
- ) -> Any:
56
- raise NotImplementedError()
57
-
58
- @override
59
- async def parse_image(
60
- self,
61
- image: FileInput,
62
- ) -> Any:
63
- raise NotImplementedError()
64
-
65
- @override
66
- async def parse_file(
67
- self,
68
- file: FileInput,
69
- ) -> Any:
70
- raise NotImplementedError()
71
-
72
- @override
73
- async def parse_tools(
74
- self,
75
- tools: list[ToolDefinition],
76
- ) -> Any:
77
- raise NotImplementedError()
78
-
79
- @override
80
- async def upload_file(
81
- self,
82
- name: str,
83
- mime: str,
84
- bytes: io.BytesIO,
85
- type: Literal["image", "file"] = "file",
86
- ) -> FileWithId:
87
- raise NotImplementedError()
88
-
89
- @override
90
- async def _query_impl(
91
- self,
92
- input: Sequence[InputItem],
93
- *,
94
- tools: list[ToolDefinition],
95
- **kwargs: object,
96
- ) -> QueryResult:
97
- return await self.delegate_query(
98
- input,
99
- tools=tools,
100
- **kwargs,
101
- )