model-library 0.1.6__py3-none-any.whl → 0.1.7__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.
@@ -1,32 +1,30 @@
1
- import asyncio
2
1
  import io
3
2
  import logging
4
- from typing import Any, Literal, Sequence, cast
3
+ from typing import Any, Literal, Sequence
5
4
 
6
5
  import grpc
7
6
  from typing_extensions import override
8
- from xai_sdk import AsyncClient, Client
9
- from xai_sdk.aio.chat import Chat as AsyncChat
7
+ from xai_sdk import AsyncClient
8
+ from xai_sdk.aio.chat import Chat
10
9
  from xai_sdk.chat import Content, Response, system, tool_result, user
11
10
  from xai_sdk.chat import image as xai_image
12
11
  from xai_sdk.chat import tool as xai_tool
13
12
  from xai_sdk.proto.v6.chat_pb2 import Message, Tool
14
- from xai_sdk.sync.chat import Chat as SyncChat
15
13
 
16
14
  from model_library import model_library_settings
17
15
  from model_library.base import (
18
16
  LLM,
17
+ FileBase,
19
18
  FileInput,
20
19
  FileWithBase64,
21
20
  FileWithId,
22
- FileWithUrl,
23
21
  InputItem,
24
22
  LLMConfig,
25
- ProviderConfig,
26
23
  QueryResult,
27
24
  QueryResultCost,
28
25
  QueryResultMetadata,
29
- RawInputItem,
26
+ RawInput,
27
+ RawResponse,
30
28
  TextInput,
31
29
  ToolBody,
32
30
  ToolCall,
@@ -37,36 +35,25 @@ from model_library.exceptions import (
37
35
  BadInputError,
38
36
  MaxOutputTokensExceededError,
39
37
  ModelNoOutputError,
38
+ NoMatchingToolCallError,
40
39
  RateLimitException,
41
40
  )
42
41
  from model_library.providers.openai import OpenAIModel
43
42
  from model_library.register_models import register_provider
44
43
  from model_library.utils import create_openai_client_with_defaults
45
44
 
46
- Chat = AsyncChat | SyncChat
47
-
48
-
49
- class XAIConfig(ProviderConfig):
50
- sync_client: bool = False
51
-
52
45
 
53
46
  @register_provider("grok")
54
47
  class XAIModel(LLM):
55
- provider_config = XAIConfig()
56
-
57
- _client: AsyncClient | Client | None = None
48
+ _client: AsyncClient | None = None
58
49
 
59
50
  @override
60
- def get_client(self) -> AsyncClient | Client:
61
- if self._client:
62
- return self._client
63
-
64
- ClientClass = Client if self.provider_config.sync_client else AsyncClient
65
- self._client = ClientClass(
66
- api_key=model_library_settings.XAI_API_KEY,
67
- )
68
-
69
- return self._client
51
+ def get_client(self) -> AsyncClient:
52
+ if not XAIModel._client:
53
+ XAIModel._client = AsyncClient(
54
+ api_key=model_library_settings.XAI_API_KEY,
55
+ )
56
+ return XAIModel._client
70
57
 
71
58
  @override
72
59
  def __init__(
@@ -98,54 +85,68 @@ class XAIModel(LLM):
98
85
  )
99
86
  )
100
87
 
88
+ async def get_tool_call_ids(self, input: Sequence[InputItem]) -> list[str]:
89
+ raw_responses = [x for x in input if isinstance(x, RawResponse)]
90
+ tool_call_ids: list[str] = []
91
+
92
+ calls = [
93
+ y
94
+ for x in raw_responses
95
+ if isinstance(x.response, Response) and x.response.tool_calls
96
+ for y in x.response.tool_calls
97
+ ]
98
+ tool_call_ids.extend([x.id for x in calls if x.id])
99
+ return tool_call_ids
100
+
101
101
  @override
102
102
  async def parse_input(
103
103
  self,
104
104
  input: Sequence[InputItem],
105
105
  **kwargs: Any,
106
- ) -> None:
107
- chat: Chat = kwargs["chat"]
106
+ ) -> list[Message]:
107
+ new_input: list[Message] = []
108
+
108
109
  content_user: list[Any] = []
110
+
111
+ def flush_content_user():
112
+ if content_user:
113
+ new_input.append(user(*content_user))
114
+ content_user.clear()
115
+
116
+ tool_call_ids = await self.get_tool_call_ids(input)
117
+
109
118
  for item in input:
119
+ if isinstance(item, TextInput):
120
+ content_user.append(item.text)
121
+ continue
122
+
123
+ if isinstance(item, FileBase):
124
+ match item.type:
125
+ case "image":
126
+ parsed = await self.parse_image(item)
127
+ case "file":
128
+ parsed = await self.parse_file(item)
129
+ content_user.append(parsed)
130
+ continue
131
+
132
+ # non content user item
133
+ flush_content_user()
134
+
110
135
  match item:
111
- case TextInput():
112
- content_user.append(item.text)
113
- case FileWithBase64() | FileWithUrl() | FileWithId():
114
- match item.type:
115
- case "image":
116
- content_user.append(await self.parse_image(item))
117
- case "file":
118
- content_user.append(await self.parse_file(item))
119
- case _:
120
- if content_user:
121
- chat.append(user(*content_user))
122
- content_user = []
123
- match item:
124
- case ToolResult():
125
- if not (
126
- isinstance(x, Response)
127
- and x.finish_reason == "REASON_TOOL_CALLS"
128
- and x.tool_calls
129
- and any(
130
- tool
131
- for tool in x.tool_calls
132
- if tool.id == item.tool_call.id
133
- )
134
- for x in chat.messages
135
- ):
136
- raise Exception(
137
- "Tool call result provided with no matching tool call"
138
- )
139
- chat.append(tool_result(item.result))
140
- case dict(): # RawInputItem
141
- item = cast(RawInputItem, item)
142
- chat.append(item) # pyright: ignore[reportArgumentType]
143
- case _: # RawResponse
144
- item = cast(Response, item)
145
- chat.append(item)
146
-
147
- if content_user:
148
- chat.append(user(*content_user))
136
+ case ToolResult():
137
+ if item.tool_call.id not in tool_call_ids:
138
+ raise NoMatchingToolCallError()
139
+
140
+ new_input.append(tool_result(item.result))
141
+ case RawResponse():
142
+ new_input.append(item.response)
143
+ case RawInput():
144
+ new_input.append(item.input)
145
+
146
+ # in case content user item is the last item
147
+ flush_content_user()
148
+
149
+ return new_input
149
150
 
150
151
  @override
151
152
  async def parse_image(
@@ -200,43 +201,10 @@ class XAIModel(LLM):
200
201
  ) -> FileWithId:
201
202
  raise NotImplementedError()
202
203
 
203
- def fetch_response_sync(
204
- self,
205
- chat: SyncChat,
206
- ) -> Response | None:
207
- latest_response = None
208
- for response, _ in chat.stream():
209
- latest_response = response
210
-
211
- return latest_response
212
-
213
- async def fetch_response_async(
214
- self,
215
- chat: AsyncChat,
216
- ) -> Response | None:
217
- latest_response = None
218
- async for response, _ in chat.stream():
219
- latest_response = response
220
-
221
- return latest_response
222
-
223
204
  @override
224
- async def _query_impl(
225
- self,
226
- input: Sequence[InputItem],
227
- *,
228
- tools: list[ToolDefinition],
229
- query_logger: logging.Logger,
230
- **kwargs: object,
231
- ) -> QueryResult:
232
- if self.reasoning_effort:
233
- kwargs["reasoning_effort"] = self.reasoning_effort
234
-
235
- if self.delegate:
236
- return await self.delegate_query(
237
- input, tools=tools, query_logger=query_logger, **kwargs
238
- )
239
-
205
+ async def build_body(
206
+ self, input: Sequence[InputItem], *, tools: list[ToolDefinition], **kwargs: Any
207
+ ) -> dict[str, Any]:
240
208
  messages: Sequence[Message] = []
241
209
  if "system_prompt" in kwargs:
242
210
  messages.append(system(str(kwargs.pop("system_prompt"))))
@@ -254,20 +222,43 @@ class XAIModel(LLM):
254
222
  if self.top_p is not None:
255
223
  body["top_p"] = self.top_p
256
224
 
225
+ if self.reasoning_effort:
226
+ body["reasoning_effort"] = self.reasoning_effort
227
+
257
228
  body.update(kwargs)
258
229
 
230
+ # use Chat object to parse raw Response and other objects into the correct formats
231
+ # see xai's chat.py `class BaseChat` -> `def append`
232
+ chat: Chat = self.get_client().chat.create("dummy")
233
+ parsed_input = await self.parse_input(input)
234
+ for message in parsed_input:
235
+ chat.append(message)
236
+ body["messages"].extend(chat.messages)
237
+
238
+ return body
239
+
240
+ @override
241
+ async def _query_impl(
242
+ self,
243
+ input: Sequence[InputItem],
244
+ *,
245
+ tools: list[ToolDefinition],
246
+ query_logger: logging.Logger,
247
+ **kwargs: object,
248
+ ) -> QueryResult:
249
+ if self.delegate:
250
+ return await self.delegate_query(
251
+ input, tools=tools, query_logger=query_logger, **kwargs
252
+ )
253
+
254
+ body = await self.build_body(input, tools=tools, **kwargs)
255
+
259
256
  try:
260
- chat: Chat = self.get_client().chat.create(**body) # pyright: ignore[reportAny]
261
- await self.parse_input(input, chat=chat)
262
-
263
- # Allows users to dynamically swap to a sync client if getting grpc errors
264
- # Run in a separate thread so we are playing fair with other async processes
265
- if self.provider_config.sync_client:
266
- latest_response = await asyncio.to_thread(
267
- self.fetch_response_sync, cast(SyncChat, chat)
268
- )
269
- else:
270
- latest_response = await self.fetch_response_async(cast(AsyncChat, chat))
257
+ chat: Chat = self.get_client().chat.create(**body)
258
+
259
+ latest_response: Response | None = None
260
+ async for response, _ in chat.stream():
261
+ latest_response = response
271
262
 
272
263
  if not latest_response:
273
264
  raise ModelNoOutputError("Model failed to produce a response")
@@ -307,8 +298,25 @@ class XAIModel(LLM):
307
298
  cache_read_tokens=latest_response.usage.cached_prompt_text_tokens,
308
299
  ),
309
300
  tool_calls=tool_calls,
310
- history=[*input, latest_response],
301
+ history=[*input, RawResponse(response=latest_response)],
302
+ )
303
+
304
+ @override
305
+ async def count_tokens(
306
+ self,
307
+ input: Sequence[InputItem],
308
+ *,
309
+ history: Sequence[InputItem] = [],
310
+ tools: list[ToolDefinition] = [],
311
+ **kwargs: object,
312
+ ) -> int:
313
+ string_input = await self.stringify_input(input, history=history, tools=tools)
314
+ self.logger.debug(string_input)
315
+
316
+ tokens = await self.get_client().tokenize.tokenize_text(
317
+ string_input, self.model_name
311
318
  )
319
+ return len(tokens)
312
320
 
313
321
  @override
314
322
  async def _calculate_cost(
@@ -7,7 +7,7 @@ from pathlib import Path
7
7
  from typing import Any, Callable, Type, TypeVar, cast, get_type_hints
8
8
 
9
9
  import yaml
10
- from pydantic import create_model, model_validator
10
+ from pydantic import ConfigDict, create_model, model_validator
11
11
  from pydantic.fields import Field
12
12
  from pydantic.main import BaseModel
13
13
 
@@ -173,6 +173,8 @@ class DefaultParameters(BaseModel):
173
173
 
174
174
 
175
175
  class RawModelConfig(BaseModel):
176
+ model_config = ConfigDict(extra="forbid", strict=True)
177
+
176
178
  company: str
177
179
  label: str
178
180
  description: str | None = None
@@ -275,7 +277,7 @@ def _register_models() -> ModelRegistry:
275
277
 
276
278
  # create model config object
277
279
  raw_model_obj: RawModelConfig = RawModelConfig.model_validate(
278
- current_model_config, strict=True, extra="forbid"
280
+ current_model_config
279
281
  )
280
282
 
281
283
  provider_endpoint = (
model_library/utils.py CHANGED
@@ -1,6 +1,5 @@
1
1
  import logging
2
2
  from collections.abc import Mapping, Sequence
3
- from typing import Any
4
3
 
5
4
  import httpx
6
5
  from openai import AsyncOpenAI
@@ -90,37 +89,3 @@ def get_context_window_for_model(model_name: str, default: int = 128_000) -> int
90
89
  f"using default context length of {default}"
91
90
  )
92
91
  return default
93
-
94
-
95
- def normalize_tool_result(result: Any) -> str:
96
- """Normalize tool result to non-empty string for API compatibility.
97
-
98
- Empty results (None, empty dict/list, whitespace-only strings) are
99
- converted to a single space to satisfy API requirements.
100
-
101
- Args:
102
- result: Tool result value (any type)
103
-
104
- Returns:
105
- Non-empty string representation of the result
106
- """
107
- if result is None or (isinstance(result, (dict, list)) and not result):
108
- return " "
109
- result_str = str(result) # pyright: ignore[reportUnknownArgumentType]
110
- return result_str.strip() or " "
111
-
112
-
113
- def filter_empty_text_blocks(content: list[dict[str, Any]]) -> list[dict[str, Any]]:
114
- """Filter out empty text blocks from content list.
115
-
116
- Args:
117
- content: List of content blocks (dicts with 'type' and potentially 'text' keys)
118
-
119
- Returns:
120
- Filtered list with empty text blocks removed
121
- """
122
- return [
123
- block
124
- for block in content
125
- if block.get("type") != "text" or block.get("text", "").strip()
126
- ]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: model-library
3
- Version: 0.1.6
3
+ Version: 0.1.7
4
4
  Summary: Model Library for vals.ai
5
5
  Author-email: "Vals AI, Inc." <contact@vals.ai>
6
6
  License: MIT
@@ -13,13 +13,13 @@ Requires-Dist: pyyaml>=6.0.2
13
13
  Requires-Dist: rich
14
14
  Requires-Dist: backoff<3.0,>=2.2.1
15
15
  Requires-Dist: redis<7.0,>=6.2.0
16
- Requires-Dist: tiktoken==0.11.0
16
+ Requires-Dist: tiktoken>=0.12.0
17
17
  Requires-Dist: pillow
18
18
  Requires-Dist: openai<3.0,>=2.0
19
19
  Requires-Dist: anthropic<1.0,>=0.57.1
20
20
  Requires-Dist: mistralai<2.0,>=1.9.10
21
21
  Requires-Dist: xai-sdk<2.0,>=1.0.0
22
- Requires-Dist: ai21<5.0,>=4.0.3
22
+ Requires-Dist: ai21<5.0,>=4.3.0
23
23
  Requires-Dist: boto3<2.0,>=1.38.27
24
24
  Requires-Dist: google-genai[aiohttp]>=1.51.0
25
25
  Requires-Dist: google-cloud-storage>=1.26.0
@@ -1,20 +1,20 @@
1
1
  model_library/__init__.py,sha256=AKc_15aklOf-LbcS9z1Xer_moRWNpG6Dh3kqvSQ0nOI,714
2
- model_library/exceptions.py,sha256=ZHMr6lloXZz4V4Wy1UP8zc1CdUHx6-IS9_rOi6oN45s,8680
2
+ model_library/exceptions.py,sha256=4TJ1aDkpPV-gv3gLIO7pi5ORRBG2hPXSBAvOXS6I_Wg,9027
3
3
  model_library/file_utils.py,sha256=FAZRRtDT8c4Rjfoj64Te3knEHggXAAfRRuS8WLCsSe8,3682
4
- model_library/logging.py,sha256=McyaPHUk7RkB38-LrfnudrrU1B62ta8wAbbIBwLRmj0,853
4
+ model_library/logging.py,sha256=rZrrVQlEmyZzvKx6nIOR8bKHl49wQIIW5c36Zqcigm4,888
5
5
  model_library/model_utils.py,sha256=l8oCltGeimMGtnne_3Q1EguVtzCj61UMsLsma-1czwg,753
6
6
  model_library/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
- model_library/register_models.py,sha256=3FeFrcS2qRpAhj9ahXNuZ6jcH5UEks3I_PaT6rPvKgs,13653
7
+ model_library/register_models.py,sha256=-CtFggD296wqO2nd6yC5GIWBoi0YD0kDyG8bwxBa1ec,13696
8
8
  model_library/registry_utils.py,sha256=BVauHcP02Et2maLxowNBbdpGd32cnLz1_zSjDLVJjp0,8843
9
9
  model_library/settings.py,sha256=QyeUqzWBpexFi014L_mZkoXP49no3SAQNJRObATXrL8,873
10
- model_library/utils.py,sha256=T91ACGTc-KtksVyMFspt-vJtR5I-xcO3nVfH6SltmMU,3988
10
+ model_library/utils.py,sha256=dcww26Ph0PSihEzSN4gZ48XXxN3Bt5oWveVYX6UACyI,2922
11
11
  model_library/base/__init__.py,sha256=TtxCXGUtkEqWZNMMofLPuC4orN7Ja2hemtbtHitt_UA,266
12
- model_library/base/base.py,sha256=mvubt5VC1eM8cuLw_RHP04hTgNEcULzIBiJcHqKF--c,14289
12
+ model_library/base/base.py,sha256=nrdPS92-vFkDVJJvNVOQ8e6U1zCyZxOtFg18ZgM4o0s,17467
13
13
  model_library/base/batch.py,sha256=-jd6L0ECc5pkj73zoX2ZYcv_9iQdqxEi1kEilwaXWSA,2895
14
- model_library/base/delegate_only.py,sha256=YJUvP9k8x2kBsI-0ACNmx1Jx77zdZSBWCMSpx0LAyXE,2213
15
- model_library/base/input.py,sha256=Nhg8Ril1kFau1DnE8u102JC1l-vxNd-v9e3SjovR-Do,1876
16
- model_library/base/output.py,sha256=Ak6CJRYqtjYILsSWkfE70fSK3yvP7v_n5NYfysMaIL4,7464
17
- model_library/base/utils.py,sha256=YGQLPyQgCbfHNBxyTxCvpZNZ-ctEji258IdfMiXUJXs,1962
14
+ model_library/base/delegate_only.py,sha256=5v2twEuQl1jF34M8iFcaZQlk0_uBLew4B46TkHUEssw,2441
15
+ model_library/base/input.py,sha256=JrnvBZ_xLcEmaMjnOfUS6GFV0QWtCGpJq0RQQL2YBG8,1934
16
+ model_library/base/output.py,sha256=jwd3rfRFUcqm8q-O5H684ToNZPvcD_obtf6ugmhzUus,7613
17
+ model_library/base/utils.py,sha256=eiMTiFFXHTb44Nnz3fjxf9YQzJpdfNI7tprSi9COPu0,2268
18
18
  model_library/config/README.md,sha256=i8_wHnlI6uHIqWN9fYBkDCglZM2p5ZMVD3SLlxiwUVk,4274
19
19
  model_library/config/ai21labs_models.yaml,sha256=ZWHhk1cep2GQIYHqkTS_0152mF3oZg2tSzMPmvfMRSI,2478
20
20
  model_library/config/alibaba_models.yaml,sha256=-RLWOwh3ZaCQqjaZ-4Zw0BJNVE6JVHJ8Ggm9gQJZ6QI,2082
@@ -36,29 +36,29 @@ model_library/config/together_models.yaml,sha256=BeqRJonYzPvWwoLfkyH0RMRKBYUrCSE
36
36
  model_library/config/xai_models.yaml,sha256=2KRNNQy3kV-4xxSfhj7Uhp9TZF-S5qPlM8Ef-04zv8Y,7985
37
37
  model_library/config/zai_models.yaml,sha256=lcYMh2FCrLWkKqdCnarRlwDoL3SbutRBNAiMPBUYQiw,1894
38
38
  model_library/providers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
39
- model_library/providers/ai21labs.py,sha256=sqmu9R7owZZQLxOkNV9dhSeZVAlTMDCNFVdxJyJo6UA,5885
39
+ model_library/providers/ai21labs.py,sha256=NXoEu0NFwxLVJIN751tEuKLFYk4ECSDnWMik35pL5Y4,6277
40
40
  model_library/providers/alibaba.py,sha256=k6LZErV_l9oTFTdKTwyw1SXD509Rl3AqFbN8umCryEE,2941
41
- model_library/providers/amazon.py,sha256=U0tH5mw8dAMDg06BtnVoR-RxYlcAL1-7ZR737sR8xgU,14068
42
- model_library/providers/anthropic.py,sha256=G94hFkRFTWutq9XYd3321KkPrxVHnR6fs_h2AdkVqx4,23197
41
+ model_library/providers/amazon.py,sha256=F8anL4pmeadA0P9luUZSSnEcke90WH7mCa3afJ2akgM,14156
42
+ model_library/providers/anthropic.py,sha256=xbSZx6R54UhNQij-vwFKPCIQJoTzxLblJMIxdqGcsqs,23094
43
43
  model_library/providers/azure.py,sha256=brQNCED-zHvYjL5K5hdjFBNso6hJZg0HTHNnAgJPPG0,1408
44
44
  model_library/providers/cohere.py,sha256=lCBm1PP1l_UOa1pKFMIZM3C0wCv3QWB6UP0-jvjkFa4,1066
45
45
  model_library/providers/deepseek.py,sha256=7T4lxDiV5wmWUK7TAKwr332_T6uyXNCOiirZOCCETL0,1159
46
46
  model_library/providers/fireworks.py,sha256=w-5mOF5oNzqx_0ijCoTm1lSn2ZHwhp6fURKhV3LEqIc,2309
47
47
  model_library/providers/inception.py,sha256=Nrky53iujIM9spAWoNRtoJg2inFiL0li6E75vT3b6V8,1107
48
48
  model_library/providers/kimi.py,sha256=zzvcKpZLsM1xPebpLeMxNKTt_FRiLN1rFWrIly7wfXA,1092
49
- model_library/providers/minimax.py,sha256=YRtJW2wgiu6KXEBScYETeVMNTfhPvpjL2J-oo0wE_BI,1057
50
- model_library/providers/mistral.py,sha256=r0PY30kHY-guaSzIEahdp2I45meJzo71Ql97NfkPv-8,9798
51
- model_library/providers/openai.py,sha256=MMm6K4iewhSpPzEeRhrPRYf_txrpklCrefNHiUly8S8,33665
49
+ model_library/providers/minimax.py,sha256=ckVyoXdtVxGT3aU-AknBQCa7_mOckNMfOXSgwbrJNIY,1610
50
+ model_library/providers/mistral.py,sha256=kmp74jEETMnB8fQ5VNfNVkksIrPMGJwJeXJDnTVwKa8,10117
51
+ model_library/providers/openai.py,sha256=gMykcN5eHFHqCrK9y5twc18h7XSMI68mB9YGYnpt93A,34522
52
52
  model_library/providers/perplexity.py,sha256=eIzzkaZ4ZMlRKFVI9bnwyo91iJkh7aEmJ-0_4OKeAWc,1083
53
53
  model_library/providers/together.py,sha256=7Y4QLnX8c_fyXUud-W_C1gidmROQainTgODBwbvFyXQ,2033
54
- model_library/providers/vals.py,sha256=mKaItg_g9RJeaIDhoBu7ksTe42P0MRYFI4X1cla8YC0,9883
55
- model_library/providers/xai.py,sha256=toSqWBHUaHE000aMdOayAW3-_ZmDUotWEpZ4-X33LuY,10918
54
+ model_library/providers/vals.py,sha256=dbaL8toYTssm8qVlrgqzqwCeeTV9h-xfA37uBuoWtfg,9894
55
+ model_library/providers/xai.py,sha256=eA3CsiOWIF_vKxNZC95INUKOazz54R6vpVrGM8VR1tY,10719
56
56
  model_library/providers/zai.py,sha256=O_GM6KlJ0fM2wYoxO9xrCWfnpYH7IpoKEzjiD4jB8Kc,1050
57
57
  model_library/providers/google/__init__.py,sha256=ypuLVL_QJEQ7C3S47FhC9y4wyawYOdGikAViJmACI0U,115
58
- model_library/providers/google/batch.py,sha256=4TE90Uo1adi54dVtGcGyUAxw11YExJq-Y4KmkQ-cyHA,9978
59
- model_library/providers/google/google.py,sha256=xmiktN-Z9W1fC1jHUT_m6x5fTpI6-mWpKvbMGg9kgXE,16787
60
- model_library-0.1.6.dist-info/licenses/LICENSE,sha256=x6mf4o7U_wHaaqcfxoU-0R6uYJLbqL_TNuoULP3asaA,1070
61
- model_library-0.1.6.dist-info/METADATA,sha256=sNWBOgDqydFI184UERputqhulBz0olrbye-fO7owrCE,6989
62
- model_library-0.1.6.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
63
- model_library-0.1.6.dist-info/top_level.txt,sha256=HtQYxA_7RP8UT35I6VcUw20L6edI0Zf2t5Ys1uDGVjs,14
64
- model_library-0.1.6.dist-info/RECORD,,
58
+ model_library/providers/google/batch.py,sha256=ycK2arf00lhZQNgyM5Yd01LAScul6rvVv--dUcRWWSA,9977
59
+ model_library/providers/google/google.py,sha256=txQaet1HobyjYd3dp9Mgonx3x5ln3LMuW10Qsyum3B4,17809
60
+ model_library-0.1.7.dist-info/licenses/LICENSE,sha256=x6mf4o7U_wHaaqcfxoU-0R6uYJLbqL_TNuoULP3asaA,1070
61
+ model_library-0.1.7.dist-info/METADATA,sha256=436seE0dN2884VkHzGHyp36aARqBxqKMKRccmKYG3_E,6989
62
+ model_library-0.1.7.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
63
+ model_library-0.1.7.dist-info/top_level.txt,sha256=HtQYxA_7RP8UT35I6VcUw20L6edI0Zf2t5Ys1uDGVjs,14
64
+ model_library-0.1.7.dist-info/RECORD,,