sunholo 0.71.29__py3-none-any.whl → 0.73.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.
@@ -0,0 +1,219 @@
1
+ import os
2
+ import json
3
+ import yaml
4
+ from datetime import datetime, timedelta
5
+ from collections import defaultdict
6
+ from .timedelta import format_timedelta
7
+
8
+ class ConfigManager:
9
+ def __init__(self, vector_name: str):
10
+ """
11
+ Initialize the ConfigManager with a vector name.
12
+ Requires a local config/ folder holding your configuration files or the env var VAC_CONFIG_FOLDER to be set.
13
+
14
+ Read more at: https://dev.sunholo.com/docs/config
15
+
16
+ Args:
17
+ vector_name (str): The name of the vector in the configuration files.
18
+
19
+ Example:
20
+ ```python
21
+ # Usage example:
22
+ config = ConfigManager("my_vac")
23
+ agent = config.vacConfig("agent")
24
+ ```
25
+ """
26
+ local_config_folder = os.path.join(os.getcwd(), "config")
27
+ if os.path.isdir(local_config_folder):
28
+ print(f"Found local config folder {local_config_folder} - will overwrite any global configurations")
29
+ else:
30
+ local_config_folder = None
31
+ if os.getenv("VAC_CONFIG_FOLDER") is None and local_config_folder is None:
32
+ raise ValueError(f"Must have either a local config/ folder in this dir ({os.getcwd()}/config/) or a folder specified via the VAC_CONFIG_FOLDER environment variable, or both.")
33
+
34
+ self.vector_name = vector_name
35
+ self.config_cache = {}
36
+ self.config_folder = os.getenv("VAC_CONFIG_FOLDER", os.getcwd())
37
+ self.local_config_folder = local_config_folder
38
+ self.configs_by_kind = self.load_all_configs()
39
+
40
+ def load_all_configs(self):
41
+ """
42
+ Load all configuration files from the specified directories into a dictionary.
43
+ Caching is used to avoid reloading files within a 5-minute window.
44
+
45
+ Returns:
46
+ dict: A dictionary of configurations grouped by their 'kind' key.
47
+ """
48
+ from ..logging import log
49
+
50
+ log.debug(f"Loading all configs from folder: {self.config_folder} and local folder: {self.local_config_folder}")
51
+ global_configs_by_kind = self._load_configs_from_folder(self.config_folder)
52
+
53
+ if self.local_config_folder:
54
+ local_configs_by_kind = self._load_configs_from_folder(self.local_config_folder)
55
+ # Merge local configs into global configs
56
+ for kind, local_config in local_configs_by_kind.items():
57
+ if kind in global_configs_by_kind:
58
+ global_configs_by_kind[kind] = self._merge_dicts(global_configs_by_kind[kind], local_config)
59
+ else:
60
+ global_configs_by_kind[kind] = local_config
61
+
62
+ return global_configs_by_kind
63
+
64
+ def _load_configs_from_folder(self, folder):
65
+ """
66
+ Load all configuration files from a specific folder into a dictionary.
67
+
68
+ Args:
69
+ folder (str): The path of the folder to load configurations from.
70
+
71
+ Returns:
72
+ dict: A dictionary of configurations grouped by their 'kind' key.
73
+ """
74
+ from ..logging import log
75
+
76
+ configs_by_kind = defaultdict(dict)
77
+ current_time = datetime.now()
78
+
79
+ for filename in os.listdir(folder):
80
+ if filename in ["cloudbuild.yaml", "cloud_run_urls.json"]:
81
+ continue
82
+ if filename.endswith(('.yaml', '.yml', '.json')):
83
+ config_file = os.path.join(folder, filename)
84
+ if filename in self.config_cache:
85
+ cached_config, cache_time = self.config_cache[filename]
86
+ time_to_recache = (current_time - cache_time)
87
+ if time_to_recache < timedelta(minutes=5):
88
+ config = cached_config
89
+ else:
90
+ config = self._reload_config_file(config_file, filename, folder == self.local_config_folder)
91
+ else:
92
+ config = self._reload_config_file(config_file, filename, folder == self.local_config_folder)
93
+ kind = config.get('kind')
94
+ if kind:
95
+ configs_by_kind[kind] = config
96
+ else:
97
+ log.warning(f"No 'kind' found in {filename}")
98
+ return configs_by_kind
99
+
100
+ def _reload_config_file(self, config_file, filename, is_local=False):
101
+ """
102
+ Helper function to load a config file and update the cache.
103
+
104
+ Args:
105
+ config_file (str): The path to the configuration file.
106
+ filename (str): The name of the configuration file.
107
+ is_local (bool): Indicates if the config file is from the local folder.
108
+
109
+ Returns:
110
+ dict: The loaded configuration.
111
+ """
112
+ from ..logging import log
113
+ with open(config_file, 'r') as file:
114
+ if filename.endswith('.json'):
115
+ config = json.load(file)
116
+ else:
117
+ config = yaml.safe_load(file)
118
+ self.config_cache[filename] = (config, datetime.now())
119
+ log.debug(f"Loaded and cached {config_file}")
120
+ if is_local:
121
+ log.warning(f"Local configuration override for {filename}")
122
+ return config
123
+
124
+ def _check_and_reload_configs(self):
125
+ """
126
+ Check if configurations are older than 5 minutes and reload if necessary.
127
+ """
128
+ current_time = datetime.now()
129
+ for filename, (config, cache_time) in list(self.config_cache.items()):
130
+ if (current_time - cache_time) >= timedelta(minutes=5):
131
+ config_file_main = os.path.join(self.config_folder, filename)
132
+ config_file_local = os.path.join(self.local_config_folder, filename)
133
+ if os.path.exists(config_file_local):
134
+ self._reload_config_file(config_file_local, filename, is_local=True)
135
+ if os.path.exists(config_file_main):
136
+ self._reload_config_file(config_file_main, filename, is_local=False)
137
+ self.configs_by_kind = self.load_all_configs()
138
+
139
+ def _merge_dicts(self, dict1, dict2):
140
+ """
141
+ Recursively merge two dictionaries. Local values in dict2 will overwrite global values in dict1.
142
+
143
+ Args:
144
+ dict1 (dict): The global dictionary.
145
+ dict2 (dict): The local dictionary.
146
+
147
+ Returns:
148
+ dict: The merged dictionary.
149
+ """
150
+ for key, value in dict2.items():
151
+ if isinstance(value, dict) and key in dict1 and isinstance(dict1[key], dict):
152
+ dict1[key] = self._merge_dicts(dict1[key], value)
153
+ else:
154
+ dict1[key] = value
155
+ return dict1
156
+
157
+ def vacConfig(self, key: str):
158
+ """
159
+ Fetch a key from 'vacConfig' kind configuration.
160
+
161
+ Args:
162
+ key (str): The key to fetch from the configuration.
163
+
164
+ Returns:
165
+ str: The value associated with the specified key.
166
+ """
167
+ self._check_and_reload_configs()
168
+ config = self.configs_by_kind.get('vacConfig')
169
+ if not config:
170
+ return None
171
+ if self.vector_name == 'global':
172
+ return config.get(key)
173
+ vac = config['vac']
174
+
175
+ vac_config = vac.get(self.vector_name)
176
+ if not vac_config:
177
+ return None
178
+ return vac_config.get(key)
179
+
180
+ def promptConfig(self, key: str):
181
+ """
182
+ Fetch a key from 'promptConfig' kind configuration.
183
+
184
+ Args:
185
+ key (str): The key to fetch from the configuration.
186
+
187
+ Returns:
188
+ str: The value associated with the specified key.
189
+ """
190
+ self._check_and_reload_configs()
191
+ config = self.configs_by_kind.get('promptConfig')
192
+ if not config:
193
+ return None
194
+ prompts = config['prompts']
195
+ prompt_for_vector_name = prompts.get(self.vector_name)
196
+ if not prompt_for_vector_name:
197
+ return None
198
+ return prompt_for_vector_name.get(key)
199
+
200
+ def agentConfig(self, key: str):
201
+ """
202
+ Fetch a key from 'agentConfig' kind configuration.
203
+
204
+ Args:
205
+ key (str): The key to fetch from the configuration.
206
+
207
+ Returns:
208
+ str: The value associated with the specified key.
209
+ """
210
+ self._check_and_reload_configs()
211
+ config = self.configs_by_kind.get('agentConfig')
212
+ if not config:
213
+ return None
214
+ agents = config.get('agents')
215
+ if key in agents:
216
+ return agents[key]
217
+ else:
218
+ return agents.get("default")
219
+
@@ -10,8 +10,46 @@ from ..utils.parsers import validate_extension_id
10
10
  import base64
11
11
  import json
12
12
  from io import StringIO
13
+ import os
13
14
 
14
15
  class VertexAIExtensions:
16
+ """
17
+ Example
18
+
19
+ ```python
20
+ from sunholo.vertex import VertexAIExtensions
21
+ vex = VertexAIExtensions()
22
+ vex.list_extensions()
23
+ # [{'resource_name': 'projects/374404277595/locations/us-central1/extensions/770924776838397952',
24
+ # 'display_name': 'Code Interpreter',
25
+ # 'description': 'N/A'}]
26
+ ```
27
+
28
+ Creating an extension example as per:
29
+ https://cloud.google.com/vertex-ai/generative-ai/docs/extensions/create-extension
30
+
31
+ ```python
32
+ ## validates before upload
33
+ vex.upload_openapi_file("your-extension-name.yaml")
34
+ vex.openapi_file_gcs
35
+ # 'gs://your-extensions-bucket/your-extension-name.yaml'
36
+
37
+ ## load in examples to be used by creation later
38
+ vex.load_tool_use_examples('your-examples.yaml')
39
+
40
+ vex.create_extension(
41
+ "My New Extension",
42
+ description="Querying the VAC above my database",
43
+ service_account='sa-serviceaccount@my-project.iam.gserviceaccount.com')
44
+ ```
45
+
46
+ Call the extension
47
+ ```python
48
+ operation_params = {"input": {"question":"This needs to be in same schema as your openapi spec"}
49
+ vex.execute_extension("an_operation_id_from_your_openai_spec",
50
+ operation_params = operation_params)
51
+ ```
52
+ """
15
53
  def __init__(self):
16
54
  if extensions is None:
17
55
  raise ImportError("VertexAIExtensions needs vertexai.previewextensions to be installed. Install via `pip install sunholo[gcp]`")
@@ -27,6 +65,10 @@ class VertexAIExtensions:
27
65
  """
28
66
  self.IMAGE_FILE_EXTENSIONS = set(["jpg", "jpeg", "png"])
29
67
  self.location = "us-central1"
68
+ self.openapi_file_gcs = None
69
+ self.tool_use_examples = None
70
+ self.manifest = {}
71
+ self.created_extensions = []
30
72
 
31
73
  def list_extensions(self):
32
74
  the_list = extensions.Extension.list()
@@ -40,92 +82,165 @@ class VertexAIExtensions:
40
82
  })
41
83
 
42
84
  return extensions_list
85
+
86
+ def validate_openapi(self, filename):
87
+ try:
88
+ from openapi_spec_validator import validate
89
+ from openapi_spec_validator.readers import read_from_filename
90
+ except ImportError:
91
+ raise ImportError("Must have openapi-spec-validator installed - install via `pip install sunholo[tools]`")
92
+
93
+ spec_dict, spec_url = read_from_filename(filename)
94
+ validate(spec_dict)
95
+
96
+ def upload_to_gcs(self, filename):
97
+ if not os.getenv('EXTENSIONS_BUCKET'):
98
+ raise ValueError('Please specify env var EXTENSIONS_BUCKET for location to upload openapi spec')
43
99
 
100
+ from ..gcs.add_file import add_file_to_gcs
101
+ file_base = os.path.basename(filename)
44
102
 
45
- def get_extension_import_config(self, display_name: str, description: str,
46
- api_spec_gcs: dict, service_account_name: dict, tool_use_examples: list):
47
- tool_use_examples = [
48
- {
49
- "extensionOperation": {
50
- "operationId": "say_hello",
51
- },
52
- "displayName": "Say hello in the requested language",
53
- "query": "Say hello in French",
54
- "requestParams": {
55
- "fields": [
56
- {
57
- "key": "apiServicePrompt",
58
- "value": {
59
- "string_value": "French",
60
- }
61
- }
62
- ]
63
- },
64
- "responseParams": {
65
- "fields": [
66
- {
67
- "key": "apiServiceOutput",
68
- "value": {
69
- "string_value": "bonjour",
70
- },
71
- }
72
- ],
73
- },
74
- "responseSummary": "Bonjour"
75
- }
76
- ]
77
-
78
- return {
79
- "displayName": display_name,
80
- "description": description,
81
- "manifest": {
82
- "name": "EXTENSION_NAME_LLM",
83
- "description": "DESCRIPTION_LLM",
103
+ self_uri = add_file_to_gcs(file_base, bucket_filepath=file_base)
104
+
105
+ return self_uri
106
+
107
+ def upload_openapi_file(self, filename: str):
108
+ self.validate_openapi(filename)
109
+
110
+ self.openapi_file_gcs = self.upload_to_gcs(filename)
111
+
112
+ def load_tool_use_examples(self, filename: str):
113
+ import yaml
114
+
115
+ with open(filename, 'r') as file:
116
+ self.tool_use_examples = yaml.safe_load(file)
117
+
118
+ # google.cloud.aiplatform_v1beta1.types.ToolUseExample
119
+ return self.tool_use_examples
120
+
121
+
122
+ def update_tool_use_examples_via_patch(self):
123
+ import requests
124
+ import json
125
+ from google.auth import default
126
+ from google.auth.transport.requests import Request
127
+
128
+ extension = self.created_extension
129
+ if extension is None:
130
+ raise ValueError("Need to create the extension first")
131
+
132
+ # Get the access token using Google authentication
133
+ credentials, project_id = default()
134
+ credentials.refresh(Request())
135
+ access_token = credentials.token
136
+
137
+ ENDPOINT=f"{self.location}-aiplatform.googleapis.com"
138
+ URL=f"https://{ENDPOINT}/v1beta1"
139
+
140
+ extension_id = self.created_extension.resource_name
141
+
142
+ # Define the URL and extension ID
143
+ url = f"{URL}/{extension_id}"
144
+ log.info(f"PATCH {url}")
145
+ headers = {
146
+ "Authorization": f"Bearer {access_token}",
147
+ "Content-Type": "application/json"
148
+ }
149
+
150
+ # Define the payload
151
+ payload = {
152
+ "toolUseExamples": self.tool_use_examples['tool_use_examples']
153
+ }
154
+
155
+ # Make the PATCH request
156
+ response = requests.patch(
157
+ url,
158
+ headers=headers,
159
+ params={"update_mask": "toolUseExamples"},
160
+ data=json.dumps(payload)
161
+ )
162
+
163
+ # Check the response
164
+ if response.status_code == 200:
165
+ log.info("Tool use examples updated successfully.")
166
+ else:
167
+ log.info(f"Failed to update tool use examples. Status code: {response.status_code}, Response: {response.text}")
168
+
169
+
170
+ def create_extension_manifest(self,
171
+ display_name,
172
+ description,
173
+ open_api_gcs_uri: str,
174
+ service_account: str):
175
+
176
+ self.manifest = {
177
+ "name": display_name,
178
+ "description": description,
84
179
  "apiSpec": {
85
- "openApiGcsUri": api_spec_gcs,
180
+ "openApiGcsUri": open_api_gcs_uri,
86
181
  },
87
182
  "authConfig": {
88
183
  "authType": "OAUTH",
89
- "oauthConfig": {"service_account": service_account_name}
184
+ "oauthConfig": {"service_account": service_account}
90
185
  }
91
- },
92
- "toolUseExamples": tool_use_examples,
93
186
  }
94
187
 
95
- def create_extension_instance(self, display_name: str, description: str, open_api_gcs_uri: str,
96
- llm_name: str = None, llm_description: str = None, runtime_config: dict = None, service_account: str = None):
188
+ return self.manifest
189
+
190
+ def create_extension(self,
191
+ display_name: str,
192
+ description: str,
193
+ open_api_file: str = None,
194
+ tool_example_file: str = None,
195
+ runtime_config: dict = None,
196
+ service_account: str = None):
197
+
97
198
  project_id = get_gcp_project()
98
199
  extension_name = f"projects/{project_id}/locations/us-central1/extensions/{validate_extension_id(display_name)}"
99
200
 
201
+ if open_api_file:
202
+ self.upload_openapi_file(open_api_file)
203
+
204
+ manifest = self.create_extension_manifest(
205
+ display_name,
206
+ description,
207
+ open_api_gcs_uri = self.openapi_file_gcs,
208
+ service_account = service_account,
209
+ )
210
+
211
+ if tool_example_file:
212
+ self.load_tool_use_examples(tool_example_file)
213
+
100
214
  extension = extensions.Extension.create(
101
215
  extension_name=extension_name,
102
216
  display_name=display_name,
103
217
  description=description,
104
- runtime_config=runtime_config or None,
105
- manifest={
106
- "name": llm_name or display_name,
107
- "description": llm_description or description,
108
- "api_spec": {
109
- "open_api_gcs_uri": open_api_gcs_uri
110
- },
111
- "auth_config": {
112
- "auth_type": "GOOGLE_SERVICE_ACCOUNT_AUTH",
113
- "google_service_account_config": service_account or {},
114
- },
115
- },
218
+ runtime_config=runtime_config or None, # sets things like what bucket will be used
219
+ manifest=manifest,
220
+ #tool_use_examples=self.tool_use_examples
116
221
  )
117
222
  log.info(f"Created Vertex Extension: {extension_name}")
223
+
224
+ self.created_extension = extension
225
+
226
+ if tool_example_file:
227
+ self.update_tool_use_examples_via_patch()
118
228
 
119
- return extension
229
+ return extension.resource_name
120
230
 
121
- def execute_extension(self, operation_id: str, operation_params: dict, extension_id: str):
231
+ def execute_extension(self, operation_id: str, operation_params: dict, extension_id: str=None):
122
232
  init_vertex(location=self.location)
123
233
 
124
- if not extension_id.startswith("projects/"):
125
- project_id = get_gcp_project()
126
- extension_name = f"projects/{project_id}/locations/{self.location}/extensions/{extension_id}"
127
- else:
128
- extension_name = extension_id
234
+ if not extension_id:
235
+ extension_name = self.created_extension.resource_name
236
+ if extension_name is None:
237
+ raise ValueError("Must specify extension_id or init one with class")
238
+ else:
239
+ if not extension_id.startswith("projects/"):
240
+ project_id = get_gcp_project()
241
+ extension_name = f"projects/{project_id}/locations/{self.location}/extensions/{extension_id}"
242
+ else:
243
+ extension_name = extension_id
129
244
 
130
245
  extension = extensions.Extension(extension_name)
131
246
 
@@ -1,6 +1,6 @@
1
1
  try:
2
2
  from vertexai.preview import rag
3
- from vertexai.preview.generative_models import Tool, grounding, GenerationResponse
3
+ from vertexai.preview.generative_models import Tool, grounding
4
4
  except ImportError:
5
5
  rag = None
6
6
 
@@ -1,9 +1,9 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: sunholo
3
- Version: 0.71.29
3
+ Version: 0.73.2
4
4
  Summary: Large Language Model DevOps - a package to help deploy LLMs to the Cloud.
5
5
  Home-page: https://github.com/sunholo-data/sunholo-py
6
- Download-URL: https://github.com/sunholo-data/sunholo-py/archive/refs/tags/v0.71.29.tar.gz
6
+ Download-URL: https://github.com/sunholo-data/sunholo-py/archive/refs/tags/v0.73.2.tar.gz
7
7
  Author: Holosun ApS
8
8
  Author-email: multivac@sunholo.com
9
9
  License: Apache License, Version 2.0
@@ -87,7 +87,7 @@ Requires-Dist: google-api-python-client ; extra == 'gcp'
87
87
  Requires-Dist: google-cloud-alloydb-connector[pg8000] ; extra == 'gcp'
88
88
  Requires-Dist: google-auth-httplib2 ; extra == 'gcp'
89
89
  Requires-Dist: google-auth-oauthlib ; extra == 'gcp'
90
- Requires-Dist: google-cloud-aiplatform ; extra == 'gcp'
90
+ Requires-Dist: google-cloud-aiplatform >=1.58.0 ; extra == 'gcp'
91
91
  Requires-Dist: google-cloud-bigquery ; extra == 'gcp'
92
92
  Requires-Dist: google-cloud-build ; extra == 'gcp'
93
93
  Requires-Dist: google-cloud-service-control ; extra == 'gcp'
@@ -119,6 +119,7 @@ Requires-Dist: pytesseract ; extra == 'pipeline'
119
119
  Requires-Dist: tabulate ; extra == 'pipeline'
120
120
  Requires-Dist: unstructured[local-inference] ; extra == 'pipeline'
121
121
  Provides-Extra: tools
122
+ Requires-Dist: openapi-spec-validator ; extra == 'tools'
122
123
  Requires-Dist: playwright ; extra == 'tools'
123
124
 
124
125
  ## Introduction
@@ -2,10 +2,10 @@ sunholo/__init__.py,sha256=0CdpufyRKWyZe7J7UKigL6j_qOorM-p0OjHIAuf9M38,864
2
2
  sunholo/logging.py,sha256=YfIN1oP3dOEkkYkyRBU8BGS3uJFGwUDsFCl8mIVbwvE,12225
3
3
  sunholo/agents/__init__.py,sha256=Hb4NXy2rN-83Z0-UDRwX-LXv2R29lcbSFPf8G6q4fZg,380
4
4
  sunholo/agents/chat_history.py,sha256=8iX1bgvRW6fdp6r_DQR_caPHYrZ_9QJJgPxCiSDf3q8,5380
5
- sunholo/agents/dispatch_to_qa.py,sha256=nFNdxhkr7rVYuUwVoBCBNYBI2Dke6-_z_ZApBEWb_cU,8291
6
- sunholo/agents/langserve.py,sha256=FdhQjorAY2bMn2rpuabNT6bU3uqSKWrl8DjpH3L_V7k,4375
5
+ sunholo/agents/dispatch_to_qa.py,sha256=A8skiZ-CtDvYdP0tnXL4sWM3BCDBgdjFVyrqy-h8Aa4,8374
6
+ sunholo/agents/langserve.py,sha256=eSNJ4G5eGKjmyMQLM_uTOjiS-D_W4QhCLrsC4Vsnk7E,4407
7
7
  sunholo/agents/pubsub.py,sha256=5hbbhbBGyVWRpt2sAGC5FEheYH1mCCwVUhZEB1S7vGg,1337
8
- sunholo/agents/route.py,sha256=xh8ZJuIs60AhGk-1lw-b9LLuvOIVD2sx8m41BnWMJUI,2606
8
+ sunholo/agents/route.py,sha256=YL9a99X1vwSWH8XWo3En1UryxhBFEFhjkbNN1X_YDHg,2905
9
9
  sunholo/agents/special_commands.py,sha256=ecD5jrBVXo170sdgPILi0m_m_4nRFEv6qKn5zYEvEK8,6494
10
10
  sunholo/agents/swagger.py,sha256=wK90aGOgUojZjfMcjqhhJ_ksJ6ZCsVT1Iy02oU6Q5XM,10786
11
11
  sunholo/agents/fastapi/__init__.py,sha256=S_pj4_bTUmDGoq_exaREHlOKThi0zTuGT0VZY0YfODQ,88
@@ -33,19 +33,19 @@ sunholo/chunker/pdfs.py,sha256=daCZ1xjn1YvxlifIyxskWNpLJLe-Q9D_Jq12MWx3tZo,2473
33
33
  sunholo/chunker/publish.py,sha256=tiO615A2uo_ZjzdFDzNH1PL_1kJeLMUQwLJ4w67rNIc,2932
34
34
  sunholo/chunker/splitter.py,sha256=jtGfi_ZdhVdyFhfw0e4ynEpmwIyrxQtV63OituYWy6o,6729
35
35
  sunholo/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
36
- sunholo/cli/chat_vac.py,sha256=wvpFF2MRLVeomLcd31TK6tX61u-pL5nGEtMSE33wAK8,20705
37
- sunholo/cli/cli.py,sha256=8e00HBN6eYIUJ8cnvKteBJNn7aZPRMk4b82jwcGg9D4,3741
36
+ sunholo/cli/chat_vac.py,sha256=nDhBwUW7RHj7s4qhUcSK2FK4ae031iM71eKQ_WLBxgc,18695
37
+ sunholo/cli/cli.py,sha256=u70fcSQzQx2iPvE23SVCVYRFabmZ-XtgEd6vHcrABi0,3725
38
38
  sunholo/cli/cli_init.py,sha256=JMZ9AX2cPDZ-_mv3adiv2ToFVNyRPtjk9Biszl1kiR0,2358
39
39
  sunholo/cli/configs.py,sha256=QUM9DvKOdZmEQRM5uI3Nh887T0YDiSMr7O240zTLqws,4546
40
40
  sunholo/cli/deploy.py,sha256=zxdwUsRTRMC8U5vyRv0JiKBLFn84Ug_Tc88-_h9hJSs,1609
41
- sunholo/cli/embedder.py,sha256=w7LT1CANSoQbOz8xAP3Zt4C_hP4lzGJOf8XD2jY5jBQ,7291
41
+ sunholo/cli/embedder.py,sha256=NAiJy6DmIB3x8wY3ZZ2qHdTubjrwk603eiofWfakfCk,7311
42
42
  sunholo/cli/merge_texts.py,sha256=U9vdMwKmcPoc6iPOWX5MKSxn49dNGbNzVLw8ui5PhEU,1823
43
43
  sunholo/cli/run_proxy.py,sha256=OeR12ZfnasbJ-smBZQznmGufoDa4iNjUN9FCFo5JxSc,11520
44
44
  sunholo/cli/sun_rich.py,sha256=UpMqeJ0C8i0pkue1AHnnyyX0bFJ9zZeJ7HBR6yhuA8A,54
45
45
  sunholo/cli/swagger.py,sha256=absYKAU-7Yd2eiVNUY-g_WLl2zJfeRUNdWQ0oH8M_HM,1564
46
46
  sunholo/components/__init__.py,sha256=IDoylb74zFKo6NIS3RQqUl0PDFBGVxM1dfUmO7OJ44U,176
47
47
  sunholo/components/llm.py,sha256=T4we3tGmqUj4tPwxQr9M6AXv_BALqZV_dRSvINan-oU,10374
48
- sunholo/components/retriever.py,sha256=szXyQ-cgFOw6uokl7ajQt9AGXC0N2nLB900TVtjNRa4,6528
48
+ sunholo/components/retriever.py,sha256=BFUw_6turT3CQJZWv_uXylmH5fHdb0gKfKJrQ_j6MGY,6533
49
49
  sunholo/components/vectorstore.py,sha256=zUJ90L1S4IyxLB0JUWopeuwVjcsSqdhj1QreEfsJhsE,5548
50
50
  sunholo/database/__init__.py,sha256=Zz0Shcq-CtStf9rJGIYB_Ybzb8rY_Q9mfSj-nviM490,241
51
51
  sunholo/database/alloydb.py,sha256=d9W0pbZB0jTVIGF5OVaQ6kXHo-X3-6e9NpWNmV5e9UY,10464
@@ -67,16 +67,18 @@ sunholo/discovery_engine/discovery_engine_client.py,sha256=YYsFeaW41l8jmWCruQnYx
67
67
  sunholo/embedder/__init__.py,sha256=sI4N_CqgEVcrMDxXgxKp1FsfsB4FpjoXgPGkl4N_u4I,44
68
68
  sunholo/embedder/embed_chunk.py,sha256=d_dIzeNF630Q0Ar-u1hxos60s0tLIImJccAvuo_LTIw,6814
69
69
  sunholo/gcs/__init__.py,sha256=SZvbsMFDko40sIRHTHppA37IijvJTae54vrhooEF5-4,90
70
- sunholo/gcs/add_file.py,sha256=Nj75z1MH9fp3fvwd1BVLcHNFm0CVCR2uS4uByThos-o,6924
70
+ sunholo/gcs/add_file.py,sha256=vWRjxuHBQkrPNrr9tRSFGT0N_nVIw120mqDEHiaHwuQ,7115
71
71
  sunholo/gcs/download_url.py,sha256=Kg9EdPnc---YSUTAZEdzJeITjDtQSLMYwb4uiU9LhIQ,6440
72
72
  sunholo/gcs/metadata.py,sha256=C9sMPsHsq1ETetdQCqB3EBs3Kws8b8QHS9L7ei_v5aw,891
73
+ sunholo/invoke/__init__.py,sha256=Dxivd9cU92X4v2JAZet4f7L2RJ5l_30rt9t2NiD-iLA,55
74
+ sunholo/invoke/invoke_vac_utils.py,sha256=0JkCZDBEkRImzuB-nf70dF75t0WKtgA9G4TdaQJUB08,5240
73
75
  sunholo/langfuse/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
74
76
  sunholo/langfuse/callback.py,sha256=CTaos8sYcrga949BG6lIZ4I62DiiQSHxwz5re9XjDWQ,1677
75
- sunholo/langfuse/prompts.py,sha256=HO4Zy9usn5tKooBPCKksuw4Lff3c03Ny5wqn4ce_xZM,1217
77
+ sunholo/langfuse/prompts.py,sha256=EkbzSw9Jr05ULMsRDoGOp-frbtCZpnvdYSJEYNpzfX8,1293
76
78
  sunholo/llamaindex/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
77
79
  sunholo/llamaindex/generate.py,sha256=l1Picr-hVwkmAUD7XmTCa63qY9ERliFHQXwyX3BqB2Q,686
78
80
  sunholo/llamaindex/get_files.py,sha256=6rhXCDqQ_lrIapISQ_OYQDjiSATXvS_9m3qq53-oIl0,781
79
- sunholo/llamaindex/import_files.py,sha256=DmBS4tTSZW39FhKGff0qjMTP07VO7xl-LaQuxQYoc8M,5888
81
+ sunholo/llamaindex/import_files.py,sha256=Iy_wkZCUSyrue_tAEHgnYaKDgg3-5GVygokHn3kd134,5747
80
82
  sunholo/lookup/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
81
83
  sunholo/lookup/model_lookup.yaml,sha256=O7o-jP53MLA06C8pI-ILwERShO-xf6z_258wtpZBv6A,739
82
84
  sunholo/patches/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -91,17 +93,18 @@ sunholo/qna/parsers.py,sha256=Wn2X47_yeE39oeqxxgDr7jgBT-N1anYpJtVBq-623O4,2146
91
93
  sunholo/qna/retry.py,sha256=gFgOf9AxrZMIO9OwOYu1EW7rhNhyfnw_o4XAsNLBOVQ,2021
92
94
  sunholo/streaming/__init__.py,sha256=MpbydI2UYo_adttPQFkxNM33b-QRyNEbrKJx0C2AGPc,241
93
95
  sunholo/streaming/content_buffer.py,sha256=fWcg0oTf470M3U40VAChfmHmWRFgRD8VaT90jNfBCH0,6455
94
- sunholo/streaming/langserve.py,sha256=4AeNt4FPv461s20_5q17Nx83cHjK7Dl3gVOcWAxMgOk,6350
96
+ sunholo/streaming/langserve.py,sha256=Etbbo9crq4kXurgQtfG4p1yj_MwU5_KCYDINHS-tJl0,6507
95
97
  sunholo/streaming/stream_lookup.py,sha256=uTTUjf96mV7OCc-Sc8N09Fpu5g0T_mD_HbSzivtHMFQ,353
96
98
  sunholo/streaming/streaming.py,sha256=9z6pXINEopuL_Z1RnmgXAoZJum9dzyuOxqYtEYnjf8w,16405
97
99
  sunholo/summarise/__init__.py,sha256=MZk3dblUMODcPb1crq4v-Z508NrFIpkSWNf9FIO8BcU,38
98
100
  sunholo/summarise/summarise.py,sha256=C3HhjepTjUhUC8FLk4jMQIBvq1BcORniwuTFHjPVhVo,3784
99
101
  sunholo/tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
100
102
  sunholo/tools/web_browser.py,sha256=NgsAeVcndl-vMAbAfIzDJ8eRfCh5LDZan16OCNEKFmI,7094
101
- sunholo/utils/__init__.py,sha256=G11nN_6ATjxpuMfG_BvcUr9UU8onPIgkpTK6CjOcbr8,48
103
+ sunholo/utils/__init__.py,sha256=Hv02T5L2zYWvCso5hzzwm8FQogwBq0OgtUbN_7Quzqc,89
102
104
  sunholo/utils/api_key.py,sha256=Ct4bIAQZxzPEw14hP586LpVxBAVi_W9Serpy0BK-7KI,244
103
105
  sunholo/utils/big_context.py,sha256=gJIP7_ZL-YSLhOMq8jmFTMqH1wq8eB1NK7oKPeZAq2s,5578
104
- sunholo/utils/config.py,sha256=5lzO9CkLpDslp66ZwSBC_95aA1FQs-zpiOLi5YaYWbM,8907
106
+ sunholo/utils/config.py,sha256=Ute6SORPtkMnZy-BVVv0rtN28qSQ77GAzb7XtZGIAT0,8901
107
+ sunholo/utils/config_class.py,sha256=uyAsPXdxOY47CbQ8RifhUDL2BlxWP2QI-DIWBNlv6yk,8421
105
108
  sunholo/utils/config_schema.py,sha256=Wv-ncitzljOhgbDaq9qnFqH5LCuxNv59dTGDWgd1qdk,4189
106
109
  sunholo/utils/gcp.py,sha256=uueODEpA-P6O15-t0hmcGC9dONLO_hLfzSsSoQnkUss,4854
107
110
  sunholo/utils/gcp_project.py,sha256=0ozs6tzI4qEvEeXb8MxLnCdEVoWKxlM6OH05htj7_tc,1325
@@ -110,14 +113,13 @@ sunholo/utils/timedelta.py,sha256=BbLabEx7_rbErj_YbNM0MBcaFN76DC4PTe4zD2ucezg,49
110
113
  sunholo/utils/user_ids.py,sha256=SQd5_H7FE7vcTZp9AQuQDWBXd4FEEd7TeVMQe1H4Ny8,292
111
114
  sunholo/utils/version.py,sha256=P1QAJQdZfT2cMqdTSmXmcxrD2PssMPEGM-WI6083Fck,237
112
115
  sunholo/vertex/__init__.py,sha256=XH7FUKxdIgN9H2iDcWxL3sRnVHC3297G24RqEn4Ob0Y,240
113
- sunholo/vertex/extensions.py,sha256=d-Ikt9gHFf-jUMPmyU-xHwYe22QtEyr90Ua1LDKgTws,11026
114
- sunholo/vertex/extensions_class.py,sha256=E0ix4YqFQG9EglKeTmp2-zwuZUA2crileGahAhe4g5k,12164
116
+ sunholo/vertex/extensions_class.py,sha256=4PsUM9dSYrIPpq9bZ3K2rL9MRb_rlqAgnMsW0o9gHck,15855
115
117
  sunholo/vertex/init.py,sha256=-w7b9GKsyJnAJpYHYz6_zBUtmeJeLXlEkgOfwoe4DEI,2715
116
- sunholo/vertex/memory_tools.py,sha256=WpedE5yDZcQiFOFBSOtwr-tRCnCXW9G6aZ01rFDfsMo,6862
118
+ sunholo/vertex/memory_tools.py,sha256=pomHrDKqvY8MZxfUqoEwhdlpCvSGP6KmFJMVKOimXjs,6842
117
119
  sunholo/vertex/safety.py,sha256=S9PgQT1O_BQAkcqauWncRJaydiP8Q_Jzmu9gxYfy1VA,2482
118
- sunholo-0.71.29.dist-info/LICENSE.txt,sha256=SdE3QjnD3GEmqqg9EX3TM9f7WmtOzqS1KJve8rhbYmU,11345
119
- sunholo-0.71.29.dist-info/METADATA,sha256=d6FfqsjFFquwLAd3WvMfS7WSiaYDEhB8oamqx1gpFpU,6845
120
- sunholo-0.71.29.dist-info/WHEEL,sha256=y4mX-SOX4fYIkonsAGA5N0Oy-8_gI4FXw5HNI1xqvWg,91
121
- sunholo-0.71.29.dist-info/entry_points.txt,sha256=bZuN5AIHingMPt4Ro1b_T-FnQvZ3teBes-3OyO0asl4,49
122
- sunholo-0.71.29.dist-info/top_level.txt,sha256=wt5tadn5--5JrZsjJz2LceoUvcrIvxjHJe-RxuudxAk,8
123
- sunholo-0.71.29.dist-info/RECORD,,
120
+ sunholo-0.73.2.dist-info/LICENSE.txt,sha256=SdE3QjnD3GEmqqg9EX3TM9f7WmtOzqS1KJve8rhbYmU,11345
121
+ sunholo-0.73.2.dist-info/METADATA,sha256=TUj-qcbRdSqJj0mt0Nz3mhoiz2oYwRgWEfVt3vDqgag,6909
122
+ sunholo-0.73.2.dist-info/WHEEL,sha256=y4mX-SOX4fYIkonsAGA5N0Oy-8_gI4FXw5HNI1xqvWg,91
123
+ sunholo-0.73.2.dist-info/entry_points.txt,sha256=bZuN5AIHingMPt4Ro1b_T-FnQvZ3teBes-3OyO0asl4,49
124
+ sunholo-0.73.2.dist-info/top_level.txt,sha256=wt5tadn5--5JrZsjJz2LceoUvcrIvxjHJe-RxuudxAk,8
125
+ sunholo-0.73.2.dist-info/RECORD,,