versionhq 1.1.10.2__py3-none-any.whl → 1.1.10.3__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.
versionhq/__init__.py CHANGED
@@ -18,7 +18,7 @@ from versionhq.tool.model import Tool
18
18
  from versionhq.tool.composio_tool import ComposioHandler
19
19
 
20
20
 
21
- __version__ = "1.1.10.2"
21
+ __version__ = "1.1.10.3"
22
22
  __all__ = [
23
23
  "Agent",
24
24
  "Customer",
versionhq/agent/model.py CHANGED
@@ -390,7 +390,7 @@ class Agent(BaseModel):
390
390
  return raw_response
391
391
 
392
392
 
393
- def execute_task(self, task, context: Optional[str] = None, task_tools: Optional[List[Tool | ToolSet]] = None) -> str:
393
+ def execute_task(self, task, context: Optional[str] = None, task_tools: Optional[List[Tool | ToolSet]] = list()) -> str:
394
394
  """
395
395
  Execute the task and return the response in string.
396
396
  The agent utilizes the tools in task or their own tools if the task.can_use_agent_tools is True.
@@ -405,24 +405,6 @@ class Agent(BaseModel):
405
405
  if context is not task.prompt_context:
406
406
  task_prompt += context
407
407
 
408
- # if agent_tools_to_run_without_llm:
409
- # tool_results = []
410
- # for item in agent_tools_to_run_without_llm:
411
- # if isinstance(item, ToolSet):
412
- # tool_result = item.tool.run(**item.kwargs)
413
- # tool_results.append(tool_result)
414
- # elif isinstance(item, Tool):
415
- # tool_result = item.run()
416
- # tool_results.append(tool_result)
417
- # else:
418
- # try:
419
- # item.run()
420
- # except:
421
- # pass
422
-
423
- # if task.tool_res_as_final is True:
424
- # return tool_results
425
-
426
408
  # if self.team and self.team._train:
427
409
  # task_prompt = self._training_handler(task_prompt=task_prompt)
428
410
  # else:
versionhq/llm/llm_vars.py CHANGED
@@ -16,7 +16,7 @@ litellm.pick_cheapest_chat_models_from_llm_provider(custom_llm_provider: str, n=
16
16
 
17
17
  MODELS = {
18
18
  "openai": [
19
- "gpt-3.5-turbo",
19
+ # "gpt-3.5-turbo",
20
20
  "gpt-4",
21
21
  "gpt-4o",
22
22
  "gpt-4o-mini",
versionhq/llm/model.py CHANGED
@@ -196,6 +196,7 @@ class LLM(BaseModel):
196
196
  """
197
197
  Execute LLM based on the agent's params and model params.
198
198
  """
199
+ litellm.drop_params = True
199
200
 
200
201
  with suppress_warnings():
201
202
  if len(self.callbacks) > 0:
@@ -206,7 +207,7 @@ class LLM(BaseModel):
206
207
  self.tools = [item.tool.properties if isinstance(item, ToolSet) else item.properties for item in tools]
207
208
 
208
209
  if response_format:
209
- self.response_format = { "type": "json_object" } if self.model == "gpt-3.5-turbo" or tool_res_as_final else response_format
210
+ self.response_format = { "type": "json_object" } if tool_res_as_final else response_format
210
211
 
211
212
  provider = self.provider if self.provider else "openai"
212
213
 
@@ -227,6 +228,7 @@ class LLM(BaseModel):
227
228
  res = litellm.completion(messages=messages, stream=False, **params)
228
229
 
229
230
  if self.tools:
231
+ messages.append(res["choices"][0]["message"])
230
232
  tool_calls = res["choices"][0]["message"]["tool_calls"]
231
233
  tool_res = ""
232
234
 
@@ -242,18 +244,24 @@ class LLM(BaseModel):
242
244
  tool_instance = tool.tool
243
245
  args = tool.kwargs
244
246
  res = tool_instance.run(params=args)
245
- tool_res += str(res)
247
+
248
+ if tool_res_as_final:
249
+ tool_res += str(res)
250
+ else:
251
+ messages.append({ "role": "tool", "tool_call_id": item.id, "content": str(res) })
246
252
 
247
253
  elif (isinstance(tool, Tool) or type(tool) == Tool) and (tool.name.replace(" ", "_") == func_name or tool.func.__name__ == func_name):
248
254
  res = tool.run(params=func_args)
249
- tool_res += str(res)
255
+ if tool_res_as_final:
256
+ tool_res += str(res)
257
+ else:
258
+ messages.append({ "role": "tool", "tool_call_id": item.id, "content": str(res) })
250
259
 
251
- if tool_res_as_final == True:
260
+ if tool_res_as_final:
252
261
  return tool_res
253
- pass
254
262
 
255
263
  else:
256
- messages.append({ "role": "tool", "tool_call_id": tool_calls.id, "content": tool_res })
264
+ print(messages)
257
265
  res = litellm.completion(messages=messages, stream=False, **params)
258
266
 
259
267
  return res["choices"][0]["message"]["content"]
versionhq/task/model.py CHANGED
@@ -4,10 +4,10 @@ import datetime
4
4
  import uuid
5
5
  from concurrent.futures import Future
6
6
  from hashlib import md5
7
- from typing import Any, Dict, List, Set, Optional, Tuple, Callable, Type
7
+ from typing import Any, Dict, List, Set, Optional, Tuple, Callable, Type, TypeVar
8
8
  from typing_extensions import Annotated, Self
9
9
 
10
- from pydantic import UUID4, BaseModel, Field, PrivateAttr, field_validator, model_validator, create_model, InstanceOf
10
+ from pydantic import UUID4, BaseModel, Field, PrivateAttr, field_validator, model_validator, create_model, InstanceOf, field_validator
11
11
  from pydantic_core import PydanticCustomError
12
12
 
13
13
  from versionhq._utils.process_config import process_config
@@ -96,8 +96,8 @@ class ResponseField(BaseModel):
96
96
  for item in self.properties:
97
97
  p.update(**item._format_props())
98
98
 
99
- if item.required:
100
- r.append(item.title)
99
+ # if item.required:
100
+ r.append(item.title)
101
101
 
102
102
  props = {
103
103
  "type": schema_type,
@@ -161,14 +161,13 @@ class ResponseField(BaseModel):
161
161
 
162
162
  class TaskOutput(BaseModel):
163
163
  """
164
- Store the final output of the task in TaskOutput class.
165
- Depending on the task output format, use `raw`, `pydantic`, `json_dict` accordingly.
164
+ A class to store the final output of the given task in raw (string), json_dict, and pydantic class formats.
166
165
  """
167
166
 
168
167
  task_id: UUID4 = Field(default_factory=uuid.uuid4, frozen=True, description="store Task ID")
169
168
  raw: str = Field(default="", description="Raw output of the task")
170
169
  json_dict: Dict[str, Any] = Field(default=None, description="`raw` converted to dictionary")
171
- pydantic: Optional[Any] = Field(default=None, description="`raw` converted to the abs. pydantic model")
170
+ pydantic: Optional[Any] = Field(default=None)
172
171
  tool_output: Optional[Any] = Field(default=None, description="store tool result when the task takes tool output as its final output")
173
172
 
174
173
  def __str__(self) -> str:
@@ -256,7 +255,7 @@ class Task(BaseModel):
256
255
 
257
256
  @model_validator(mode="before")
258
257
  @classmethod
259
- def process_model_config(cls, values: Dict[str, Any]) -> None:
258
+ def process_config(cls, values: Dict[str, Any]) -> None:
260
259
  return process_config(values_to_update=values, model_class=cls)
261
260
 
262
261
 
@@ -276,16 +275,16 @@ class Task(BaseModel):
276
275
  return self
277
276
 
278
277
 
279
- @model_validator(mode="after")
280
- def set_attributes_based_on_config(self) -> Self:
281
- """
282
- Set attributes based on the task configuration.
283
- """
278
+ # @model_validator(mode="after")
279
+ # def set_attributes_based_on_config(self) -> Self:
280
+ # """
281
+ # Set attributes based on the task configuration.
282
+ # """
284
283
 
285
- if self.config:
286
- for key, value in self.config.items():
287
- setattr(self, key, value)
288
- return self
284
+ # if self.config:
285
+ # for key, value in self.config.items():
286
+ # setattr(self, key, value)
287
+ # return self
289
288
 
290
289
 
291
290
  @model_validator(mode="after")
@@ -322,7 +321,7 @@ class Task(BaseModel):
322
321
  if self.pydantic_custom_output:
323
322
  output_prompt = f"""
324
323
  Your response MUST STRICTLY follow the given repsonse format:
325
- JSON schema: {str({k: v for k, v in self.pydantic_custom_output.__fields__.items()})}
324
+ JSON schema: {str(self.pydantic_custom_output)}
326
325
  """
327
326
 
328
327
  elif self.response_fields:
@@ -380,16 +379,13 @@ Ref. Output image: {output_formats_to_follow}
380
379
 
381
380
  def _structure_response_format(self, data_type: str = "object", model_provider: str = "gemini") -> Dict[str, Any] | None:
382
381
  """
383
- Create and return a valid response format using
384
- - mannual response schema from `self.response_fields`, or
385
- - SDK objects from `pydantic_custom_output`.
386
- OpenAI:
387
- https://platform.openai.com/docs/guides/structured-outputs?context=ex1#function-calling-vs-response-format
388
- https://platform.openai.com/docs/guides/structured-outputs?context=with_parse#some-type-specific-keywords-are-not-yet-supported
389
- Gemini:
382
+ Structure a response format either from`response_fields` or `pydantic_custom_output`.
383
+ 1 nested item is accepted.
390
384
  """
391
385
 
392
- response_schema = None
386
+ from versionhq.task.structured_response import StructuredOutput
387
+
388
+ response_format: Dict[str, Any] = None
393
389
 
394
390
  if self.response_fields:
395
391
  properties, required_fields = {}, []
@@ -406,37 +402,19 @@ Ref. Output image: {output_formats_to_follow}
406
402
  "type": "object",
407
403
  "properties": properties,
408
404
  "required": required_fields,
409
- "additionalProperties": False, # for openai
405
+ "additionalProperties": False,
410
406
  }
411
407
 
412
-
413
- elif self.pydantic_custom_output:
414
- response_schema = {
415
- **self.pydantic_custom_output.model_json_schema(),
416
- "additionalProperties": False,
417
- "required": [k for k, v in self.pydantic_custom_output.__fields__.items()],
418
- "strict": True,
408
+ response_format = {
409
+ "type": "json_schema",
410
+ "json_schema": { "name": "outcome", "schema": response_schema }
419
411
  }
420
412
 
421
413
 
422
- if response_schema:
423
- if model_provider == "gemini":
424
- return {
425
- "type": data_type,
426
- "response_schema": response_schema,
427
- "enforce_validation": True
428
- }
414
+ elif self.pydantic_custom_output:
415
+ response_format = StructuredOutput(response_format=self.pydantic_custom_output)._format()
429
416
 
430
- if model_provider == "openai":
431
- if self.pydantic_custom_output:
432
- return self.pydantic_custom_output
433
- else:
434
- return {
435
- "type": "json_schema",
436
- "json_schema": { "name": "outcome", "strict": True, "schema": response_schema },
437
- }
438
- else:
439
- return None
417
+ return response_format
440
418
 
441
419
 
442
420
  def _create_json_output(self, raw: str) -> Dict[str, Any]:
@@ -477,17 +455,16 @@ Ref. Output image: {output_formats_to_follow}
477
455
 
478
456
  def _create_pydantic_output(self, raw: str = None, json_dict: Dict[str, Any] = None) -> InstanceOf[BaseModel]:
479
457
  """
480
- Create pydantic output from the `raw` result.
458
+ Create pydantic output from raw or json_dict output.
481
459
  """
482
460
 
483
- output_pydantic = None
484
- json_dict = json_dict
461
+ output_pydantic = self.pydantic_custom_output
485
462
 
486
463
  try:
487
- if not json_dict:
488
- json_dict = self._create_json_output(raw=raw)
464
+ json_dict = json_dict if json_dict else self._create_json_output(raw=raw)
489
465
 
490
- output_pydantic = self.pydantic_custom_output(**json_dict)
466
+ for k, v in json_dict.items():
467
+ setattr(output_pydantic, k, v)
491
468
 
492
469
  except:
493
470
  pass
@@ -600,13 +577,14 @@ Ref. Output image: {output_formats_to_follow}
600
577
  if self.callback:
601
578
  self.callback({ **self.callback_kwargs, **self.output.__dict__ })
602
579
 
603
- # if self.output_file:
580
+ # if self.output_file: ## disabled for now
604
581
  # content = (
605
582
  # json_output
606
583
  # if json_output
607
584
  # else pydantic_output.model_dump_json() if pydantic_output else result
608
585
  # )
609
586
  # self._save_file(content)
587
+
610
588
  ended_at = datetime.datetime.now()
611
589
  self.execution_span_in_sec = (ended_at - started_at).total_seconds()
612
590
 
@@ -0,0 +1,142 @@
1
+ #! FIXME
2
+ from typing import Dict, Optional, Type, List, Any, TypeVar
3
+
4
+ from pydantic import BaseModel, Field, InstanceOf
5
+
6
+ from versionhq.llm.llm_vars import SchemaType
7
+ from versionhq.llm.model import LLM
8
+
9
+
10
+ """
11
+ Structure a response schema (json schema) from the given Pydantic model.
12
+ """
13
+
14
+
15
+ class StructuredObject:
16
+ """
17
+ A class to store the structured dictionary.
18
+ """
19
+ provider: str = "openai"
20
+ field: Type[Field]
21
+
22
+ title: str
23
+ dtype: str = "object"
24
+ properties: Dict[str, Dict[str, str]] = dict()
25
+ required: List[str] = list()
26
+ additionalProperties: bool = False
27
+
28
+ def __init__(self, name, field: Type[Field], provider: str | InstanceOf[LLM] = "openai"):
29
+ self.title = name
30
+ self.field = field
31
+ self.dtype = "object"
32
+ self.additionalProperties = False
33
+ self.provider = provider if isinstance(provider, str) else provider.provider
34
+
35
+ def _format(self):
36
+ if not self.field:
37
+ pass
38
+ else:
39
+ description = self.field.description if hasattr(self.field, "description") and self.field.description is not None else ""
40
+ self.properties.update({"item": { "type": SchemaType(self.field.annotation.__args__).convert() }})
41
+ self.required.append("item")
42
+
43
+ return {
44
+ self.title: {
45
+ "type": self.dtype,
46
+ "description": description,
47
+ "properties": self.properties,
48
+ "additionalProperties": self.additionalProperties,
49
+ "required": self.required
50
+ }
51
+ }
52
+
53
+
54
+
55
+ class StructuredList:
56
+ """
57
+ A class to store a structured list with 1 nested object.
58
+ """
59
+ provider: str = "openai"
60
+ field: Type[Field]
61
+ title: str = ""
62
+ dtype: str = "array"
63
+ items: Dict[str, Dict[str, str]] = dict()
64
+
65
+ def __init__(self, name, field: Type[Field], provider: str | LLM = "openai"):
66
+ self.provider = provider if isinstance(provider, str) else provider.provider
67
+ self.field = field
68
+ self.title = name
69
+ self.dtype = "array"
70
+ self.items = dict()
71
+
72
+
73
+ def _format(self):
74
+ field = self.field
75
+ if not field:
76
+ pass
77
+ else:
78
+ description = "" if field.description is None else field.description
79
+ props = {}
80
+
81
+ for item in field.annotation.__args__:
82
+ nested_object_type = item.__origin__ if hasattr(item, "__origin__") else item
83
+
84
+ if nested_object_type == dict:
85
+ props.update({
86
+ "nest": {
87
+ "type": "object",
88
+ "properties": { "item": { "type": "string"} }, #! REFINEME - field title <>`item`
89
+ "required": ["item",],
90
+ "additionalProperties": False
91
+ }})
92
+
93
+ elif nested_object_type == list:
94
+ props.update({
95
+ "nest": {
96
+ "type": "array",
97
+ "items": { "item": { "type": "string" } }, #! REFINEME - field title <>`item`
98
+ }})
99
+ else:
100
+ props.update({ "nest": { "type": SchemaType(nested_object_type).convert() }})
101
+
102
+ self.items = { **props }
103
+ return {
104
+ self.title: {
105
+ "type": self.dtype,
106
+ "description": description,
107
+ "items": self.items,
108
+ }
109
+ }
110
+
111
+
112
+
113
+
114
+ class StructuredOutput(BaseModel):
115
+ response_format: Any = None
116
+ provider: str = "openai"
117
+ applicable_models: List[InstanceOf[LLM] | str] = list()
118
+ name: str = ""
119
+ schema: Dict[str, Any] = dict(type="object", additionalProperties=False, properties=dict(), required=list())
120
+
121
+
122
+ def _format(self, **kwargs):
123
+ if self.response_format is None:
124
+ pass
125
+
126
+ self.name = self.response_format.__name__
127
+
128
+ for name, field in self.response_format.model_fields.items():
129
+ self.schema["required"].append(name)
130
+
131
+ if hasattr(field.annotation, "__origin__") and field.annotation.__origin__ == dict:
132
+ self.schema["properties"].update(StructuredObject(name=name, field=field)._format())
133
+
134
+ elif hasattr(field.annotation, "__origin__") and field.annotation.__origin__ == list:
135
+ self.schema["properties"].update(StructuredList(name=name, field=field)._format())
136
+ else:
137
+ self.schema["properties"].update({ name: { "type": SchemaType(field.annotation).convert(), **kwargs }})
138
+
139
+ return {
140
+ "type": "json_schema",
141
+ "json_schema": { "name": self.name, "schema": self.schema }
142
+ }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: versionhq
3
- Version: 1.1.10.2
3
+ Version: 1.1.10.3
4
4
  Summary: LLM orchestration frameworks for model-agnostic AI agents that handle complex outbound workflows
5
5
  Author-email: Kuriko Iwai <kuriko@versi0n.io>
6
6
  License: MIT License
@@ -1,4 +1,4 @@
1
- versionhq/__init__.py,sha256=GkGY1ob5I6BdJjds_hdxOYWJ8n3EIWjTAQ48v1UheoQ,951
1
+ versionhq/__init__.py,sha256=lctzH-NkGs_wSYgbGkPFDcsPpGvFwE8UegxnHsiRp0E,951
2
2
  versionhq/_utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
3
  versionhq/_utils/i18n.py,sha256=TwA_PnYfDLA6VqlUDPuybdV9lgi3Frh_ASsb_X8jJo8,1483
4
4
  versionhq/_utils/logger.py,sha256=U-MpeGueA6YS8Ptfy0VnU_ePsZP-8Pvkvi0tZ4s_UMg,1438
@@ -6,7 +6,7 @@ versionhq/_utils/process_config.py,sha256=jbPGXK2Kb4iyCugJ3FwRJuU0wL5Trq2x4xFQz2
6
6
  versionhq/_utils/rpm_controller.py,sha256=dUgFd6JtdjiLLTRmrjsBHdTaLn73XFuKpLbJh7thf2A,2289
7
7
  versionhq/_utils/usage_metrics.py,sha256=hhq1OCW8Z4V93vwW2O2j528EyjOlF8wlTsX5IL-7asA,1106
8
8
  versionhq/agent/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
- versionhq/agent/model.py,sha256=g8S8d0uHORrpq2mAUzo1Tx1hZmtYKk8HT55iOICSte8,20344
9
+ versionhq/agent/model.py,sha256=tdqrnSA212I-oG1GLDw_9AjymjYxbKLBmsXJrghIxhM,19592
10
10
  versionhq/agent/parser.py,sha256=Z_swUPO3piJQuYU8oVYwXWeR2zjmNb4PxbXZeR-GlIg,4694
11
11
  versionhq/agent/TEMPLATES/Backstory.py,sha256=Gub3SUbdrNAwV0ITLYdZFJ4VFZRDfDRPdBZrtlknrds,554
12
12
  versionhq/agent/TEMPLATES/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -19,14 +19,15 @@ versionhq/clients/product/model.py,sha256=hLTvvQsatNuq0DtyTqpP_gRKgnv6N4uRjavnGf
19
19
  versionhq/clients/workflow/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
20
20
  versionhq/clients/workflow/model.py,sha256=FNftenLLoha0bkivrjId32awLHAkBwIT8iNljdic_bw,6003
21
21
  versionhq/llm/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
22
- versionhq/llm/llm_vars.py,sha256=SSrkrph1Nf6nvwsqf48vMovs2byxbL33CI8kcoakHK0,8759
23
- versionhq/llm/model.py,sha256=2waDxP_pISqqF2MTTdvzARi0hS9xna_d7YoGMwf8RGM,13020
22
+ versionhq/llm/llm_vars.py,sha256=PO__b-h5e-6oQ-uoIgXx3lPSAUPUwXYfdVRW73fvX14,8761
23
+ versionhq/llm/model.py,sha256=0vjFM_BC4B6URG2PRZLydmL8bE_hqsCYFyQHNt4GfGg,13408
24
24
  versionhq/storage/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
25
25
  versionhq/storage/task_output_storage.py,sha256=xoBJHeqUyQt6iJoR1WQTghP-fyxXL66qslpX1QC2-4o,4827
26
26
  versionhq/task/__init__.py,sha256=l2r_g01i91JAGlOoHZP_Gh2WCk6mo9D19lcqt7sKMpQ,186
27
27
  versionhq/task/formatter.py,sha256=N8Kmk9vtrMtBdgJ8J7RmlKNMdZWSmV8O1bDexmCWgU0,643
28
28
  versionhq/task/log_handler.py,sha256=KJRrcNZgFSKhlNzvtYFnvtp6xukaF1s7ifX9u4zWrN8,1683
29
- versionhq/task/model.py,sha256=Kj_a67TitiQsy9uZST7yDdi3mXcQqRhbdOF3DZ_fwjA,26207
29
+ versionhq/task/model.py,sha256=uBB98fIWoqHmnWzYYRgYeG1sw9yLrrwTjWsweMoRlf0,25231
30
+ versionhq/task/structured_response.py,sha256=FbDDnTixghowYNr95FigzpxNIc_A6pPzVVCu8kDgruM,4790
30
31
  versionhq/team/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
31
32
  versionhq/team/model.py,sha256=NzcRXWwP0adWL9vsnsmI-A5dOcE3199FGmGgemUB2VA,20043
32
33
  versionhq/team/team_planner.py,sha256=XkM93ItI59cuEzMN1s1jJ-B4LyalSZnAlYBY5SUCbVs,3603
@@ -37,8 +38,8 @@ versionhq/tool/composio_tool_vars.py,sha256=FvBuEXsOQUYnN7RTFxT20kAkiEYkxWKkiVtg
37
38
  versionhq/tool/decorator.py,sha256=C4ZM7Xi2gwtEMaSeRo-geo_g_MAkY77WkSLkAuY0AyI,1205
38
39
  versionhq/tool/model.py,sha256=5qG-OH7zohvepPDOjdjDulhEqmNUM4osiyk5LaxmSiU,12333
39
40
  versionhq/tool/tool_handler.py,sha256=2m41K8qo5bGCCbwMFferEjT-XZ-mE9F0mDUOBkgivOI,1416
40
- versionhq-1.1.10.2.dist-info/LICENSE,sha256=7CCXuMrAjPVsUvZrsBq9DsxI2rLDUSYXR_qj4yO_ZII,1077
41
- versionhq-1.1.10.2.dist-info/METADATA,sha256=UJJNvaPJqRsEQepGITgpHi6rcGmpXPO-zS_tuNVJpiY,16356
42
- versionhq-1.1.10.2.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
43
- versionhq-1.1.10.2.dist-info/top_level.txt,sha256=DClQwxDWqIUGeRJkA8vBlgeNsYZs4_nJWMonzFt5Wj0,10
44
- versionhq-1.1.10.2.dist-info/RECORD,,
41
+ versionhq-1.1.10.3.dist-info/LICENSE,sha256=7CCXuMrAjPVsUvZrsBq9DsxI2rLDUSYXR_qj4yO_ZII,1077
42
+ versionhq-1.1.10.3.dist-info/METADATA,sha256=HF7BiaGsEsAIlgHVlFq3IzIs5cpsOBzNqe56pv6teY4,16356
43
+ versionhq-1.1.10.3.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
44
+ versionhq-1.1.10.3.dist-info/top_level.txt,sha256=DClQwxDWqIUGeRJkA8vBlgeNsYZs4_nJWMonzFt5Wj0,10
45
+ versionhq-1.1.10.3.dist-info/RECORD,,