semantic-router 0.1.0.dev4__tar.gz → 0.1.0.dev6__tar.gz

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 (50) hide show
  1. {semantic_router-0.1.0.dev4 → semantic_router-0.1.0.dev6}/PKG-INFO +3 -3
  2. {semantic_router-0.1.0.dev4 → semantic_router-0.1.0.dev6}/pyproject.toml +2 -2
  3. {semantic_router-0.1.0.dev4 → semantic_router-0.1.0.dev6}/semantic_router/__init__.py +1 -1
  4. {semantic_router-0.1.0.dev4 → semantic_router-0.1.0.dev6}/semantic_router/index/base.py +189 -30
  5. {semantic_router-0.1.0.dev4 → semantic_router-0.1.0.dev6}/semantic_router/index/hybrid_local.py +8 -10
  6. {semantic_router-0.1.0.dev4 → semantic_router-0.1.0.dev6}/semantic_router/index/local.py +21 -12
  7. {semantic_router-0.1.0.dev4 → semantic_router-0.1.0.dev6}/semantic_router/index/pinecone.py +265 -45
  8. {semantic_router-0.1.0.dev4 → semantic_router-0.1.0.dev6}/semantic_router/index/postgres.py +22 -11
  9. {semantic_router-0.1.0.dev4 → semantic_router-0.1.0.dev6}/semantic_router/index/qdrant.py +26 -12
  10. {semantic_router-0.1.0.dev4 → semantic_router-0.1.0.dev6}/semantic_router/routers/base.py +266 -112
  11. {semantic_router-0.1.0.dev4 → semantic_router-0.1.0.dev6}/semantic_router/routers/hybrid.py +136 -16
  12. {semantic_router-0.1.0.dev4 → semantic_router-0.1.0.dev6}/semantic_router/routers/semantic.py +0 -3
  13. {semantic_router-0.1.0.dev4 → semantic_router-0.1.0.dev6}/LICENSE +0 -0
  14. {semantic_router-0.1.0.dev4 → semantic_router-0.1.0.dev6}/README.md +0 -0
  15. {semantic_router-0.1.0.dev4 → semantic_router-0.1.0.dev6}/semantic_router/encoders/__init__.py +0 -0
  16. {semantic_router-0.1.0.dev4 → semantic_router-0.1.0.dev6}/semantic_router/encoders/aurelio.py +0 -0
  17. {semantic_router-0.1.0.dev4 → semantic_router-0.1.0.dev6}/semantic_router/encoders/base.py +0 -0
  18. {semantic_router-0.1.0.dev4 → semantic_router-0.1.0.dev6}/semantic_router/encoders/bedrock.py +0 -0
  19. {semantic_router-0.1.0.dev4 → semantic_router-0.1.0.dev6}/semantic_router/encoders/bm25.py +0 -0
  20. {semantic_router-0.1.0.dev4 → semantic_router-0.1.0.dev6}/semantic_router/encoders/clip.py +0 -0
  21. {semantic_router-0.1.0.dev4 → semantic_router-0.1.0.dev6}/semantic_router/encoders/cohere.py +0 -0
  22. {semantic_router-0.1.0.dev4 → semantic_router-0.1.0.dev6}/semantic_router/encoders/fastembed.py +0 -0
  23. {semantic_router-0.1.0.dev4 → semantic_router-0.1.0.dev6}/semantic_router/encoders/google.py +0 -0
  24. {semantic_router-0.1.0.dev4 → semantic_router-0.1.0.dev6}/semantic_router/encoders/huggingface.py +0 -0
  25. {semantic_router-0.1.0.dev4 → semantic_router-0.1.0.dev6}/semantic_router/encoders/mistral.py +0 -0
  26. {semantic_router-0.1.0.dev4 → semantic_router-0.1.0.dev6}/semantic_router/encoders/openai.py +0 -0
  27. {semantic_router-0.1.0.dev4 → semantic_router-0.1.0.dev6}/semantic_router/encoders/tfidf.py +0 -0
  28. {semantic_router-0.1.0.dev4 → semantic_router-0.1.0.dev6}/semantic_router/encoders/vit.py +0 -0
  29. {semantic_router-0.1.0.dev4 → semantic_router-0.1.0.dev6}/semantic_router/encoders/zure.py +0 -0
  30. {semantic_router-0.1.0.dev4 → semantic_router-0.1.0.dev6}/semantic_router/index/__init__.py +0 -0
  31. {semantic_router-0.1.0.dev4 → semantic_router-0.1.0.dev6}/semantic_router/linear.py +0 -0
  32. {semantic_router-0.1.0.dev4 → semantic_router-0.1.0.dev6}/semantic_router/llms/__init__.py +0 -0
  33. {semantic_router-0.1.0.dev4 → semantic_router-0.1.0.dev6}/semantic_router/llms/base.py +0 -0
  34. {semantic_router-0.1.0.dev4 → semantic_router-0.1.0.dev6}/semantic_router/llms/cohere.py +0 -0
  35. {semantic_router-0.1.0.dev4 → semantic_router-0.1.0.dev6}/semantic_router/llms/grammars/json.gbnf +0 -0
  36. {semantic_router-0.1.0.dev4 → semantic_router-0.1.0.dev6}/semantic_router/llms/llamacpp.py +0 -0
  37. {semantic_router-0.1.0.dev4 → semantic_router-0.1.0.dev6}/semantic_router/llms/mistral.py +0 -0
  38. {semantic_router-0.1.0.dev4 → semantic_router-0.1.0.dev6}/semantic_router/llms/ollama.py +0 -0
  39. {semantic_router-0.1.0.dev4 → semantic_router-0.1.0.dev6}/semantic_router/llms/openai.py +0 -0
  40. {semantic_router-0.1.0.dev4 → semantic_router-0.1.0.dev6}/semantic_router/llms/openrouter.py +0 -0
  41. {semantic_router-0.1.0.dev4 → semantic_router-0.1.0.dev6}/semantic_router/llms/zure.py +0 -0
  42. {semantic_router-0.1.0.dev4 → semantic_router-0.1.0.dev6}/semantic_router/py.typed +0 -0
  43. {semantic_router-0.1.0.dev4 → semantic_router-0.1.0.dev6}/semantic_router/route.py +0 -0
  44. {semantic_router-0.1.0.dev4 → semantic_router-0.1.0.dev6}/semantic_router/routers/__init__.py +0 -0
  45. {semantic_router-0.1.0.dev4 → semantic_router-0.1.0.dev6}/semantic_router/schema.py +0 -0
  46. {semantic_router-0.1.0.dev4 → semantic_router-0.1.0.dev6}/semantic_router/utils/__init__.py +0 -0
  47. {semantic_router-0.1.0.dev4 → semantic_router-0.1.0.dev6}/semantic_router/utils/defaults.py +0 -0
  48. {semantic_router-0.1.0.dev4 → semantic_router-0.1.0.dev6}/semantic_router/utils/function_call.py +0 -0
  49. {semantic_router-0.1.0.dev4 → semantic_router-0.1.0.dev6}/semantic_router/utils/llm.py +0 -0
  50. {semantic_router-0.1.0.dev4 → semantic_router-0.1.0.dev6}/semantic_router/utils/logger.py +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.3
2
2
  Name: semantic-router
3
- Version: 0.1.0.dev4
3
+ Version: 0.1.0.dev6
4
4
  Summary: Super fast semantic router for AI decision making
5
5
  License: MIT
6
6
  Author: Aurelio AI
@@ -40,7 +40,7 @@ Requires-Dist: numpy (>=1.25.2,<2.0.0)
40
40
  Requires-Dist: openai (>=1.10.0,<2.0.0)
41
41
  Requires-Dist: pillow (>=10.2.0,<11.0.0) ; (python_version < "3.13") and (extra == "vision")
42
42
  Requires-Dist: pinecone (>=5.0.0) ; extra == "pinecone"
43
- Requires-Dist: pinecone-text (>=0.7.1,<0.10.0) ; extra == "hybrid"
43
+ Requires-Dist: pinecone-text (>=0.7.1) ; extra == "hybrid"
44
44
  Requires-Dist: psycopg2-binary (>=2.9.9,<3.0.0)
45
45
  Requires-Dist: pydantic (>=2.10.2,<3.0.0)
46
46
  Requires-Dist: pyyaml (>=6.0.1,<7.0.0)
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "semantic-router"
3
- version = "0.1.0.dev4"
3
+ version = "0.1.0.dev6"
4
4
  description = "Super fast semantic router for AI decision making"
5
5
  authors = ["Aurelio AI <hello@aurelio.ai>"]
6
6
  readme = "README.md"
@@ -17,7 +17,7 @@ numpy = "^1.25.2"
17
17
  colorlog = "^6.8.0"
18
18
  pyyaml = "^6.0.1"
19
19
  aurelio-sdk = {version = "^0.0.16"}
20
- pinecone-text = {version = ">=0.7.1,<0.10.0", optional = true}
20
+ pinecone-text = {version = ">=0.7.1", optional = true}
21
21
  torch = {version = ">=2.1.0,<2.6.0", optional = true, python = "<3.13" }
22
22
  transformers = {version = ">=4.36.2", optional = true, python = "<3.13" }
23
23
  tokenizers = {version = ">=0.19", optional = true, python = "<3.13" }
@@ -3,4 +3,4 @@ from semantic_router.route import Route
3
3
 
4
4
  __all__ = ["SemanticRouter", "HybridRouter", "Route", "RouterConfig"]
5
5
 
6
- __version__ = "0.1.0.dev4"
6
+ __version__ = "0.1.0.dev6"
@@ -1,3 +1,4 @@
1
+ import asyncio
1
2
  from datetime import datetime
2
3
  import time
3
4
  from typing import Any, List, Optional, Tuple, Union, Dict
@@ -11,6 +12,15 @@ from semantic_router.route import Route
11
12
  from semantic_router.utils.logger import logger
12
13
 
13
14
 
15
+ RETRY_WAIT_TIME = 2.5
16
+
17
+
18
+ class IndexConfig(BaseModel):
19
+ type: str
20
+ dimensions: int
21
+ vectors: int
22
+
23
+
14
24
  class BaseIndex(BaseModel):
15
25
  """
16
26
  Base class for indices using Pydantic's BaseModel.
@@ -34,26 +44,73 @@ class BaseIndex(BaseModel):
34
44
  utterances: List[Any],
35
45
  function_schemas: Optional[List[Dict[str, Any]]] = None,
36
46
  metadata_list: List[Dict[str, Any]] = [],
47
+ **kwargs,
37
48
  ):
38
- """
39
- Add embeddings to the index.
49
+ """Add embeddings to the index.
40
50
  This method should be implemented by subclasses.
41
51
  """
42
52
  raise NotImplementedError("This method should be implemented by subclasses.")
43
53
 
44
- def get_utterances(self) -> List[Utterance]:
54
+ async def aadd(
55
+ self,
56
+ embeddings: List[List[float]],
57
+ routes: List[str],
58
+ utterances: List[str],
59
+ function_schemas: Optional[Optional[List[Dict[str, Any]]]] = None,
60
+ metadata_list: List[Dict[str, Any]] = [],
61
+ **kwargs,
62
+ ):
63
+ """Add vectors to the index asynchronously.
64
+ This method should be implemented by subclasses.
65
+ """
66
+ logger.warning("Async method not implemented.")
67
+ return self.add(
68
+ embeddings=embeddings,
69
+ routes=routes,
70
+ utterances=utterances,
71
+ function_schemas=function_schemas,
72
+ metadata_list=metadata_list,
73
+ **kwargs,
74
+ )
75
+
76
+ def get_utterances(self, include_metadata: bool = False) -> List[Utterance]:
45
77
  """Gets a list of route and utterance objects currently stored in the
46
78
  index, including additional metadata.
47
79
 
48
- :return: A list of tuples, each containing route, utterance, function
49
- schema and additional metadata.
50
- :rtype: List[Tuple]
80
+ :param include_metadata: Whether to include function schemas and metadata in
81
+ the returned Utterance objects.
82
+ :type include_metadata: bool
83
+ :return: A list of Utterance objects.
84
+ :rtype: List[Utterance]
51
85
  """
52
86
  if self.index is None:
53
87
  logger.warning("Index is None, could not retrieve utterances.")
54
88
  return []
55
- _, metadata = self._get_all(include_metadata=True)
89
+ _, metadata = self._get_all(include_metadata=True) # include_metadata required
56
90
  route_tuples = parse_route_info(metadata=metadata)
91
+ if not include_metadata:
92
+ # we remove the metadata from the tuples (ie only keep 0, 1 items)
93
+ route_tuples = [x[:2] for x in route_tuples]
94
+ return [Utterance.from_tuple(x) for x in route_tuples]
95
+
96
+ async def aget_utterances(self, include_metadata: bool = False) -> List[Utterance]:
97
+ """Gets a list of route and utterance objects currently stored in the
98
+ index, including additional metadata.
99
+
100
+ :param include_metadata: Whether to include function schemas and metadata in
101
+ the returned Utterance objects.
102
+ :type include_metadata: bool
103
+ :return: A list of Utterance objects.
104
+ :rtype: List[Utterance]
105
+ """
106
+ if self.index is None:
107
+ logger.warning("Index is None, could not retrieve utterances.")
108
+ return []
109
+ _, metadata = await self._async_get_all(include_metadata=True)
110
+ route_tuples = parse_route_info(metadata=metadata)
111
+ if not include_metadata:
112
+ # we remove the metadata from the tuples (ie only keep 0, 1 items)
113
+ route_tuples = [x[:2] for x in route_tuples]
57
114
  return [Utterance.from_tuple(x) for x in route_tuples]
58
115
 
59
116
  def get_routes(self) -> List[Route]:
@@ -62,7 +119,7 @@ class BaseIndex(BaseModel):
62
119
  :return: A list of Route objects.
63
120
  :rtype: List[Route]
64
121
  """
65
- utterances = self.get_utterances()
122
+ utterances = self.get_utterances(include_metadata=True)
66
123
  routes_dict: Dict[str, Route] = {}
67
124
  # first create a dictionary of route names to Route objects
68
125
  for utt in utterances:
@@ -90,6 +147,14 @@ class BaseIndex(BaseModel):
90
147
  """
91
148
  raise NotImplementedError("This method should be implemented by subclasses.")
92
149
 
150
+ async def _async_remove_and_sync(self, routes_to_delete: dict):
151
+ """
152
+ Remove embeddings in a routes syncing process from the index asynchronously.
153
+ This method should be implemented by subclasses.
154
+ """
155
+ logger.warning("Async method not implemented.")
156
+ return self._remove_and_sync(routes_to_delete=routes_to_delete)
157
+
93
158
  def delete(self, route_name: str):
94
159
  """
95
160
  Deletes route by route name.
@@ -97,10 +162,17 @@ class BaseIndex(BaseModel):
97
162
  """
98
163
  raise NotImplementedError("This method should be implemented by subclasses.")
99
164
 
100
- def describe(self) -> Dict:
165
+ def describe(self) -> IndexConfig:
101
166
  """
102
- Returns a dictionary with index details such as type, dimensions, and total
103
- vector count.
167
+ Returns an IndexConfig object with index details such as type, dimensions, and
168
+ total vector count.
169
+ This method should be implemented by subclasses.
170
+ """
171
+ raise NotImplementedError("This method should be implemented by subclasses.")
172
+
173
+ def is_ready(self) -> bool:
174
+ """
175
+ Checks if the index is ready to be used.
104
176
  This method should be implemented by subclasses.
105
177
  """
106
178
  raise NotImplementedError("This method should be implemented by subclasses.")
@@ -159,6 +231,10 @@ class BaseIndex(BaseModel):
159
231
  logger.warning("This method should be implemented by subclasses.")
160
232
  self.index = None
161
233
 
234
+ # ___________________________ CONFIG ___________________________
235
+ # When implementing a new index, the following methods should be implemented
236
+ # to enable synchronization of remote indexes.
237
+
162
238
  def _read_config(self, field: str, scope: str | None = None) -> ConfigParameter:
163
239
  """Read a config parameter from the index.
164
240
 
@@ -176,13 +252,20 @@ class BaseIndex(BaseModel):
176
252
  scope=scope,
177
253
  )
178
254
 
179
- def _read_hash(self) -> ConfigParameter:
180
- """Read the hash of the previously written index.
255
+ async def _async_read_config(
256
+ self, field: str, scope: str | None = None
257
+ ) -> ConfigParameter:
258
+ """Read a config parameter from the index asynchronously.
181
259
 
260
+ :param field: The field to read.
261
+ :type field: str
262
+ :param scope: The scope to read.
263
+ :type scope: str | None
182
264
  :return: The config parameter that was read.
183
265
  :rtype: ConfigParameter
184
266
  """
185
- return self._read_config(field="sr_hash")
267
+ logger.warning("_async_read_config method not implemented.")
268
+ return self._read_config(field=field, scope=scope)
186
269
 
187
270
  def _write_config(self, config: ConfigParameter) -> ConfigParameter:
188
271
  """Write a config parameter to the index.
@@ -195,6 +278,67 @@ class BaseIndex(BaseModel):
195
278
  logger.warning("This method should be implemented by subclasses.")
196
279
  return config
197
280
 
281
+ async def _async_write_config(self, config: ConfigParameter) -> ConfigParameter:
282
+ """Write a config parameter to the index asynchronously.
283
+
284
+ :param config: The config parameter to write.
285
+ :type config: ConfigParameter
286
+ :return: The config parameter that was written.
287
+ :rtype: ConfigParameter
288
+ """
289
+ logger.warning("Async method not implemented.")
290
+ return self._write_config(config=config)
291
+
292
+ # _________________________ END CONFIG _________________________
293
+
294
+ def _read_hash(self) -> ConfigParameter:
295
+ """Read the hash of the previously written index.
296
+
297
+ :return: The config parameter that was read.
298
+ :rtype: ConfigParameter
299
+ """
300
+ return self._read_config(field="sr_hash")
301
+
302
+ async def _async_read_hash(self) -> ConfigParameter:
303
+ """Read the hash of the previously written index asynchronously.
304
+
305
+ :return: The config parameter that was read.
306
+ :rtype: ConfigParameter
307
+ """
308
+ return await self._async_read_config(field="sr_hash")
309
+
310
+ def _is_locked(self, scope: str | None = None) -> bool:
311
+ """Check if the index is locked for a given scope (if applicable).
312
+
313
+ :param scope: The scope to check.
314
+ :type scope: str | None
315
+ :return: True if the index is locked, False otherwise.
316
+ :rtype: bool
317
+ """
318
+ lock_config = self._read_config(field="sr_lock", scope=scope)
319
+ if lock_config.value == "True":
320
+ return True
321
+ elif lock_config.value == "False" or not lock_config.value:
322
+ return False
323
+ else:
324
+ raise ValueError(f"Invalid lock value: {lock_config.value}")
325
+
326
+ async def _ais_locked(self, scope: str | None = None) -> bool:
327
+ """Check if the index is locked for a given scope (if applicable).
328
+
329
+ :param scope: The scope to check.
330
+ :type scope: str | None
331
+ :return: True if the index is locked, False otherwise.
332
+ :rtype: bool
333
+ """
334
+ lock_config = await self._async_read_config(field="sr_lock", scope=scope)
335
+ if lock_config.value == "True":
336
+ return True
337
+ elif lock_config.value == "False" or not lock_config.value:
338
+ return False
339
+ else:
340
+ raise ValueError(f"Invalid lock value: {lock_config.value}")
341
+
198
342
  def lock(
199
343
  self, value: bool, wait: int = 0, scope: str | None = None
200
344
  ) -> ConfigParameter:
@@ -214,9 +358,14 @@ class BaseIndex(BaseModel):
214
358
  if self._is_locked(scope=scope) != value:
215
359
  # in this case, we can set the lock value
216
360
  break
361
+ elif not value:
362
+ # if unlocking, we can break immediately — often with Pinecone the
363
+ # lock/unlocked state takes a few seconds to update, so locking then
364
+ # unlocking quickly will fail without this check
365
+ break
217
366
  if (datetime.now() - start_time).total_seconds() < wait:
218
- # wait for 2.5 seconds before checking again
219
- time.sleep(2.5)
367
+ # wait for a few seconds before checking again
368
+ time.sleep(RETRY_WAIT_TIME)
220
369
  else:
221
370
  raise ValueError(
222
371
  f"Index is already {'locked' if value else 'unlocked'}."
@@ -229,21 +378,31 @@ class BaseIndex(BaseModel):
229
378
  self._write_config(lock_param)
230
379
  return lock_param
231
380
 
232
- def _is_locked(self, scope: str | None = None) -> bool:
233
- """Check if the index is locked for a given scope (if applicable).
234
-
235
- :param scope: The scope to check.
236
- :type scope: str | None
237
- :return: True if the index is locked, False otherwise.
238
- :rtype: bool
381
+ async def alock(
382
+ self, value: bool, wait: int = 0, scope: str | None = None
383
+ ) -> ConfigParameter:
384
+ """Lock/unlock the index for a given scope (if applicable). If index
385
+ already locked/unlocked, raises ValueError.
239
386
  """
240
- lock_config = self._read_config(field="sr_lock", scope=scope)
241
- if lock_config.value == "True":
242
- return True
243
- elif lock_config.value == "False" or not lock_config.value:
244
- return False
245
- else:
246
- raise ValueError(f"Invalid lock value: {lock_config.value}")
387
+ start_time = datetime.now()
388
+ while True:
389
+ if await self._ais_locked(scope=scope) != value:
390
+ # in this case, we can set the lock value
391
+ break
392
+ if (datetime.now() - start_time).total_seconds() < wait:
393
+ # wait for a few seconds before checking again
394
+ await asyncio.sleep(RETRY_WAIT_TIME)
395
+ else:
396
+ raise ValueError(
397
+ f"Index is already {'locked' if value else 'unlocked'}."
398
+ )
399
+ lock_param = ConfigParameter(
400
+ field="sr_lock",
401
+ value=str(value),
402
+ scope=scope,
403
+ )
404
+ await self._async_write_config(lock_param)
405
+ return lock_param
247
406
 
248
407
  def _get_all(self, prefix: Optional[str] = None, include_metadata: bool = False):
249
408
  """
@@ -25,6 +25,7 @@ class HybridLocalIndex(LocalIndex):
25
25
  function_schemas: Optional[List[Dict[str, Any]]] = None,
26
26
  metadata_list: List[Dict[str, Any]] = [],
27
27
  sparse_embeddings: Optional[List[SparseEmbedding]] = None,
28
+ **kwargs,
28
29
  ):
29
30
  if sparse_embeddings is None:
30
31
  raise ValueError("Sparse embeddings are required for HybridLocalIndex.")
@@ -56,23 +57,20 @@ class HybridLocalIndex(LocalIndex):
56
57
  self.routes = np.concatenate([self.routes, routes_arr])
57
58
  self.utterances = np.concatenate([self.utterances, utterances_arr])
58
59
 
59
- def get_utterances(self) -> List[Utterance]:
60
+ def get_utterances(self, include_metadata: bool = False) -> List[Utterance]:
60
61
  """Gets a list of route and utterance objects currently stored in the index.
61
62
 
62
- Returns:
63
- List[Tuple]: A list of (route_name, utterance) objects.
63
+ :param include_metadata: Whether to include function schemas and metadata in
64
+ the returned Utterance objects - HybridLocalIndex doesn't include metadata so
65
+ this parameter is ignored.
66
+ :type include_metadata: bool
67
+ :return: A list of Utterance objects.
68
+ :rtype: List[Utterance]
64
69
  """
65
70
  if self.routes is None or self.utterances is None:
66
71
  return []
67
72
  return [Utterance.from_tuple(x) for x in zip(self.routes, self.utterances)]
68
73
 
69
- def describe(self) -> Dict:
70
- return {
71
- "type": self.type,
72
- "dimensions": self.index.shape[1] if self.index is not None else 0,
73
- "vectors": self.index.shape[0] if self.index is not None else 0,
74
- }
75
-
76
74
  def _sparse_dot_product(
77
75
  self, vec_a: dict[int, float], vec_b: dict[int, float]
78
76
  ) -> float:
@@ -3,7 +3,7 @@ from typing import List, Optional, Tuple, Dict
3
3
  import numpy as np
4
4
 
5
5
  from semantic_router.schema import ConfigParameter, SparseEmbedding, Utterance
6
- from semantic_router.index.base import BaseIndex
6
+ from semantic_router.index.base import BaseIndex, IndexConfig
7
7
  from semantic_router.linear import similarity_matrix, top_scores
8
8
  from semantic_router.utils.logger import logger
9
9
  from typing import Any
@@ -26,6 +26,7 @@ class LocalIndex(BaseIndex):
26
26
  utterances: List[str],
27
27
  function_schemas: Optional[List[Dict[str, Any]]] = None,
28
28
  metadata_list: List[Dict[str, Any]] = [],
29
+ **kwargs,
29
30
  ):
30
31
  embeds = np.array(embeddings) # type: ignore
31
32
  routes_arr = np.array(routes)
@@ -63,23 +64,31 @@ class LocalIndex(BaseIndex):
63
64
  # return what was removed
64
65
  return route_utterances[~mask]
65
66
 
66
- def get_utterances(self) -> List[Utterance]:
67
- """
68
- Gets a list of route and utterance objects currently stored in the index.
67
+ def get_utterances(self, include_metadata: bool = False) -> List[Utterance]:
68
+ """Gets a list of route and utterance objects currently stored in the index.
69
69
 
70
- Returns:
71
- List[Tuple]: A list of (route_name, utterance) objects.
70
+ :param include_metadata: Whether to include function schemas and metadata in
71
+ the returned Utterance objects - LocalIndex doesn't include metadata so this
72
+ parameter is ignored.
73
+ :return: A list of Utterance objects.
74
+ :rtype: List[Utterance]
72
75
  """
73
76
  if self.routes is None or self.utterances is None:
74
77
  return []
75
78
  return [Utterance.from_tuple(x) for x in zip(self.routes, self.utterances)]
76
79
 
77
- def describe(self) -> Dict:
78
- return {
79
- "type": self.type,
80
- "dimensions": self.index.shape[1] if self.index is not None else 0,
81
- "vectors": self.index.shape[0] if self.index is not None else 0,
82
- }
80
+ def describe(self) -> IndexConfig:
81
+ return IndexConfig(
82
+ type=self.type,
83
+ dimensions=self.index.shape[1] if self.index is not None else 0,
84
+ vectors=self.index.shape[0] if self.index is not None else 0,
85
+ )
86
+
87
+ def is_ready(self) -> bool:
88
+ """
89
+ Checks if the index is ready to be used.
90
+ """
91
+ return self.index is not None and self.routes is not None
83
92
 
84
93
  def query(
85
94
  self,