modaic 0.1.2__py3-none-any.whl → 0.3.0__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.

Potentially problematic release.


This version of modaic might be problematic. Click here for more details.

modaic/__init__.py CHANGED
@@ -1,4 +1,4 @@
1
- from .auto_agent import AutoAgent, AutoConfig, AutoRetriever
1
+ from .auto import AutoAgent, AutoConfig, AutoRetriever
2
2
  from .indexing import Embedder
3
3
  from .observability import Trackable, configure, track, track_modaic_obj
4
4
  from .precompiled import Indexer, PrecompiledAgent, PrecompiledConfig, Retriever
@@ -22,4 +22,16 @@ __all__ = [
22
22
  "Prop",
23
23
  "Value",
24
24
  "parse_modaic_filter",
25
+ "Condition",
25
26
  ]
27
+ _configured = False
28
+
29
+
30
+ def _auto_configure():
31
+ global _configured
32
+ if not _configured:
33
+ configure()
34
+ _configured = True
35
+
36
+
37
+ _auto_configure()
@@ -4,24 +4,38 @@ import os
4
4
  import sys
5
5
  from functools import lru_cache
6
6
  from pathlib import Path
7
- from typing import Literal, Optional, Type
7
+ from typing import Callable, Literal, Optional, Type, TypedDict
8
8
 
9
- from .hub import load_repo
9
+ from .hub import AGENTS_CACHE, load_repo
10
10
  from .precompiled import PrecompiledAgent, PrecompiledConfig, Retriever, is_local_path
11
11
 
12
12
  MODAIC_TOKEN = os.getenv("MODAIC_TOKEN")
13
13
 
14
14
 
15
- _REGISTRY = {} # maps model_type string -> (ConfigCls, ModelCls)
15
+ class RegisteredRepo(TypedDict, total=False):
16
+ AutoConfig: Type[PrecompiledConfig]
17
+ AutoAgent: Type[PrecompiledAgent]
18
+ AutoRetriever: Type[Retriever]
16
19
 
17
20
 
18
- def register(model_type: str, config_cls: Type[PrecompiledConfig], model_cls: Type[PrecompiledAgent]):
19
- _REGISTRY[model_type] = (config_cls, model_cls)
21
+ _REGISTRY: dict[str, RegisteredRepo] = {}
20
22
 
21
23
 
24
+ def register(
25
+ name: str,
26
+ auto_type: Literal["AutoConfig", "AutoAgent", "AutoRetriever"],
27
+ cls: Type[PrecompiledConfig | PrecompiledAgent | Retriever],
28
+ ):
29
+ if name in _REGISTRY:
30
+ _REGISTRY[name][auto_type] = cls
31
+ else:
32
+ _REGISTRY[name] = {auto_type: cls}
33
+
34
+
35
+ # TODO: Cleanup code still using parent_mdoule
22
36
  @lru_cache
23
37
  def _load_dynamic_class(
24
- repo_dir: str, class_path: str, parent_module: Optional[str] = None
38
+ repo_dir: Path, class_path: str, hub_path: str = None
25
39
  ) -> Type[PrecompiledConfig | PrecompiledAgent | Retriever]:
26
40
  """
27
41
  Load a class from a given repository directory and fully qualified class path.
@@ -29,27 +43,24 @@ def _load_dynamic_class(
29
43
  Args:
30
44
  repo_dir: Absolute path to a local repository directory containing the code.
31
45
  class_path: Dotted path to the target class (e.g., "pkg.module.Class").
32
- parent_module: Optional dotted module prefix (e.g., "swagginty.TableRAG"). If provided,
33
- class_path is treated as relative to this module and only the agents cache
34
- root is added to sys.path.
46
+ hub_path: The path to the repo on modaic hub (if its a hub repo) *Must be specified if its a hub repo*
35
47
 
36
48
  Returns:
37
49
  The resolved class object.
38
50
  """
39
-
40
- repo_path = Path(repo_dir)
41
-
42
- repo_dir_str = str(repo_path)
43
- print(f"repo_dir_str: {repo_dir_str}")
44
- print(f"sys.path: {sys.path}")
45
- if repo_dir_str not in sys.path:
46
- # print(f"Inserting {repo_dir_str} into sys.path")
47
- sys.path.insert(0, repo_dir_str)
48
- full_path = (
49
- f"{parent_module}.{class_path}"
50
- if parent_module and not class_path.startswith(parent_module + ".")
51
- else class_path
52
- )
51
+ if hub_path is None:
52
+ # Local folder case
53
+ repo_dir_str = str(repo_dir)
54
+ if repo_dir_str not in sys.path:
55
+ sys.path.insert(0, repo_dir_str)
56
+ full_path = f"{class_path}"
57
+ else:
58
+ # loaded hub repo case
59
+ agents_cache_str = str(AGENTS_CACHE)
60
+ if agents_cache_str not in sys.path:
61
+ sys.path.insert(0, agents_cache_str)
62
+ parent_module = hub_path.replace("/", ".")
63
+ full_path = f"{parent_module}.{class_path}"
53
64
 
54
65
  module_name, _, attr = full_path.rpartition(".")
55
66
  module = importlib.import_module(module_name)
@@ -62,27 +73,31 @@ class AutoConfig:
62
73
  """
63
74
 
64
75
  @staticmethod
65
- def from_precompiled(repo_path: str, *, parent_module: Optional[str] = None, **kwargs) -> PrecompiledConfig:
76
+ def from_precompiled(repo_path: str, **kwargs) -> PrecompiledConfig:
77
+ local = is_local_path(repo_path)
78
+ repo_dir = load_repo(repo_path, local)
79
+ return AutoConfig._from_precompiled(repo_dir, hub_path=repo_path if not local else None, **kwargs)
80
+
81
+ @staticmethod
82
+ def _from_precompiled(repo_dir: Path, hub_path: str = None, **kwargs) -> PrecompiledConfig:
66
83
  """
67
84
  Load a config for an agent or retriever from a precompiled repo.
68
85
 
69
86
  Args:
70
- repo_path: Hub path ("user/repo") or a local directory.
71
- parent_module: Optional dotted module prefix (e.g., "swagginty.TableRAG") to use to import classes from repo_path. If provided, overides default parent_module behavior.
87
+ repo_dir: The path to the repo directory. the loaded local repository directory.
88
+ hub_path: The path to the repo on modaic hub (if its a hub repo) *Must be specified if its a hub repo*
72
89
 
73
90
  Returns:
74
91
  A config object constructed via the resolved config class.
75
92
  """
76
- local = is_local_path(repo_path)
77
- repo_dir = load_repo(repo_path, local)
78
93
 
79
94
  cfg_path = repo_dir / "config.json"
80
95
  if not cfg_path.exists():
81
- raise FileNotFoundError(f"Failed to load AutoConfig, config.json not found in {repo_path}")
96
+ raise FileNotFoundError(f"Failed to load AutoConfig, config.json not found in {hub_path or str(repo_dir)}")
82
97
  with open(cfg_path, "r") as fp:
83
98
  cfg = json.load(fp)
84
99
 
85
- ConfigClass = _load_auto_class(repo_path, repo_dir, "AutoConfig", parent_module=parent_module) # noqa: N806
100
+ ConfigClass = _load_auto_class(repo_dir, "AutoConfig", hub_path=hub_path) # noqa: N806
86
101
  return ConfigClass(**{**cfg, **kwargs})
87
102
 
88
103
 
@@ -96,7 +111,6 @@ class AutoAgent:
96
111
  repo_path: str,
97
112
  *,
98
113
  config_options: Optional[dict] = None,
99
- parent_module: Optional[str] = None,
100
114
  project: Optional[str] = None,
101
115
  **kw,
102
116
  ) -> PrecompiledAgent:
@@ -105,23 +119,25 @@ class AutoAgent:
105
119
 
106
120
  Args:
107
121
  repo_path: Hub path ("user/repo") or local directory.
108
- parent_module: Optional dotted module prefix (e.g., "swagginty.TableRAG") to use to import classes from repo_path. If provided, overides default parent_module behavior.
109
122
  project: Optional project name. If not provided and repo_path is a hub path, defaults to the repo name.
110
123
  **kw: Additional keyword arguments forwarded to the Agent constructor.
111
124
 
112
125
  Returns:
113
126
  An instantiated Agent subclass.
114
127
  """
128
+ # TODO: fast lookups via registry
115
129
  local = is_local_path(repo_path)
116
130
  repo_dir = load_repo(repo_path, local)
131
+ hub_path = repo_path if not local else None
117
132
 
118
133
  if config_options is None:
119
134
  config_options = {}
120
135
 
121
- cfg = AutoConfig.from_precompiled(repo_dir, local=True, parent_module=parent_module, **config_options)
122
- AgentClass = _load_auto_class(repo_path, repo_dir, "AutoAgent", parent_module=parent_module) # noqa: N806
136
+ cfg = AutoConfig._from_precompiled(repo_dir, hub_path=hub_path, **config_options)
137
+ AgentClass = _load_auto_class(repo_dir, "AutoAgent", hub_path=hub_path) # noqa: N806
123
138
 
124
139
  # automatically configure repo and project from repo_path if not provided
140
+ # TODO: redundant checks in if statement. Investigate removing.
125
141
  if not local and "/" in repo_path and not repo_path.startswith("/"):
126
142
  parts = repo_path.split("/")
127
143
  if len(parts) >= 2:
@@ -146,7 +162,6 @@ class AutoRetriever:
146
162
  repo_path: str,
147
163
  *,
148
164
  config_options: Optional[dict] = None,
149
- parent_module: Optional[str] = None,
150
165
  project: Optional[str] = None,
151
166
  **kw,
152
167
  ) -> Retriever:
@@ -155,7 +170,6 @@ class AutoRetriever:
155
170
 
156
171
  Args:
157
172
  repo_path: hub path ("user/repo"), or local directory.
158
- parent_module: Optional dotted module prefix (e.g., "swagginty.TableRAG") to use to import classes from repo_path. If provided, overides default parent_module behavior.
159
173
  project: Optional project name. If not provided and repo_path is a hub path, defaults to the repo name.
160
174
  **kw: Additional keyword arguments forwarded to the Retriever constructor.
161
175
 
@@ -164,14 +178,16 @@ class AutoRetriever:
164
178
  """
165
179
  local = is_local_path(repo_path)
166
180
  repo_dir = load_repo(repo_path, local)
181
+ hub_path = repo_path if not local else None
167
182
 
168
183
  if config_options is None:
169
184
  config_options = {}
170
185
 
171
- cfg = AutoConfig.from_precompiled(repo_dir, local=True, parent_module=parent_module, **config_options)
172
- RetrieverClass = _load_auto_class(repo_path, repo_dir, "AutoRetriever", parent_module=parent_module) # noqa: N806
186
+ cfg = AutoConfig._from_precompiled(repo_dir, hub_path=hub_path, **config_options)
187
+ RetrieverClass = _load_auto_class(repo_dir, "AutoRetriever", hub_path=hub_path) # noqa: N806
173
188
 
174
189
  # automatically configure repo and project from repo_path if not provided
190
+ # TODO: redundant checks in if statement. Investigate removing.
175
191
  if not local and "/" in repo_path and not repo_path.startswith("/"):
176
192
  parts = repo_path.split("/")
177
193
  if len(parts) >= 2:
@@ -186,27 +202,25 @@ class AutoRetriever:
186
202
 
187
203
 
188
204
  def _load_auto_class(
189
- repo_path: str,
190
205
  repo_dir: Path,
191
206
  auto_name: Literal["AutoConfig", "AutoAgent", "AutoRetriever"],
192
- parent_module: Optional[str] = None,
207
+ hub_path: str = None,
193
208
  ) -> Type[PrecompiledConfig | PrecompiledAgent | Retriever]:
194
209
  """
195
210
  Load a class from the auto_classes.json file.
196
211
 
197
212
  Args:
198
- repo_path: The path to the repo. (local or hub path)
199
213
  repo_dir: The path to the repo directory. the loaded local repository directory.
200
214
  auto_name: The name of the auto class to load. (AutoConfig, AutoAgent, AutoRetriever)
201
- parent_module: The parent module to use to import the class.
215
+ hub_path: The path to the repo on modaic hub (if its a hub repo) *Must be specified if its a hub repo*
202
216
  """
203
217
  # determine if the repo was loaded from local or hub
204
- local = is_local_path(repo_path)
218
+ local = hub_path is None
205
219
  auto_classes_path = repo_dir / "auto_classes.json"
206
220
 
207
221
  if not auto_classes_path.exists():
208
222
  raise FileNotFoundError(
209
- f"Failed to load {auto_name}, auto_classes.json not found in {repo_path}, if this is your repo, make sure you push_to_hub() with `with_code=True`"
223
+ f"Failed to load {auto_name}, auto_classes.json not found in {hub_path or str(repo_dir)}, if this is your repo, make sure you push_to_hub() with `with_code=True`"
210
224
  )
211
225
 
212
226
  with open(auto_classes_path, "r") as fp:
@@ -214,15 +228,33 @@ def _load_auto_class(
214
228
 
215
229
  if not (auto_class_path := auto_classes.get(auto_name)):
216
230
  raise KeyError(
217
- f"{auto_name} not found in {repo_path}/auto_classes.json. Please check that the auto_classes.json file is correct."
231
+ f"{auto_name} not found in {hub_path or str(repo_dir)}/auto_classes.json. Please check that the auto_classes.json file is correct."
218
232
  ) from None
219
233
 
220
- if auto_class_path in _REGISTRY:
221
- _, LoadedClass = _REGISTRY[auto_class_path] # noqa: N806
222
- else:
223
- if parent_module is None and not local:
224
- parent_module = str(repo_path).replace("/", ".")
225
-
226
- repo_dir = repo_dir.parent.parent if not local else repo_dir
227
- LoadedClass = _load_dynamic_class(repo_dir, auto_class_path, parent_module=parent_module) # noqa: N806
234
+ repo_dir = repo_dir.parent.parent if not local else repo_dir
235
+ LoadedClass = _load_dynamic_class(repo_dir, auto_class_path, hub_path=hub_path) # noqa: N806
228
236
  return LoadedClass
237
+
238
+
239
+ def builtin_agent(name: str) -> Callable[[Type], Type]:
240
+ def _wrap(cls: Type) -> Type:
241
+ register(name, "AutoAgent", cls)
242
+ return cls
243
+
244
+ return _wrap
245
+
246
+
247
+ def builtin_indexer(name: str) -> Callable[[Type], Type]:
248
+ def _wrap(cls: Type) -> Type:
249
+ register(name, "AutoRetriever", cls)
250
+ return cls
251
+
252
+ return _wrap
253
+
254
+
255
+ def builtin_config(name: str) -> Callable[[Type], Type]:
256
+ def _wrap(cls: Type) -> Type:
257
+ register(name, "AutoConfig", cls)
258
+ return cls
259
+
260
+ return _wrap
@@ -12,7 +12,7 @@ from .table import (
12
12
  Table,
13
13
  TableFile,
14
14
  )
15
- from .text import Text
15
+ from .text import Text, TextFile
16
16
 
17
17
  __all__ = [
18
18
  "MultiTabbedTable",
@@ -31,4 +31,5 @@ __all__ = [
31
31
  "Prop",
32
32
  "HydratedAttr",
33
33
  "requires_hydration",
34
+ "TextFile",
34
35
  ]
modaic/context/base.py CHANGED
@@ -22,7 +22,7 @@ from pydantic._internal._model_construction import ModelMetaclass
22
22
  from pydantic.fields import ModelPrivateAttr
23
23
  from pydantic.main import IncEx
24
24
  from pydantic.v1 import Field as V1Field
25
- from pydantic_core import CoreSchema, SchemaSerializer
25
+ from pydantic_core import SchemaSerializer
26
26
 
27
27
  from ..query_language import Prop
28
28
  from ..storage.file_store import FileStore
modaic/context/table.py CHANGED
@@ -38,7 +38,7 @@ class BaseTable(Context, ABC):
38
38
  """
39
39
  Return up to 3 distinct sample values from the given column.
40
40
 
41
- Picks at most three unique, non-null, short (<64 chars) values from
41
+ Picks at most three unique, non-null, short (&lt;64 chars) values from
42
42
  the column, favoring speed by sampling after de-duplicating values.
43
43
 
44
44
  Args:
modaic/context/text.py CHANGED
@@ -47,7 +47,7 @@ class TextFile(Context):
47
47
  file_type: Literal["txt"] = "txt"
48
48
 
49
49
  def hydrate(self, file_store: FileStore) -> None:
50
- file = file_store.get(self.file_ref)
50
+ file = file_store.get(self.file_ref).file
51
51
  if isinstance(file, Path):
52
52
  file = file.read_text()
53
53
  else:
@@ -91,4 +91,4 @@ class TextFile(Context):
91
91
  chunks.append(Text(text=chunk))
92
92
  return chunks
93
93
 
94
- self.apply_to_chunks(chunk_text_fn)
94
+ self.chunk_with(chunk_text_fn)
@@ -12,12 +12,13 @@ from typing import (
12
12
  Type,
13
13
  )
14
14
 
15
- from dotenv import load_dotenv
15
+ from dotenv import find_dotenv, load_dotenv
16
16
 
17
17
  from ..context.base import Context, Relation
18
18
  from ..observability import Trackable, track_modaic_obj
19
19
 
20
- load_dotenv()
20
+ env_file = find_dotenv(usecwd=True)
21
+ load_dotenv(env_file)
21
22
 
22
23
 
23
24
  if TYPE_CHECKING:
modaic/datasets.py ADDED
@@ -0,0 +1,22 @@
1
+ import dspy
2
+
3
+
4
+ class Dataset:
5
+ def __init__(self, data: list):
6
+ self.data = data
7
+
8
+ def to_dspy(self) -> list:
9
+ return dspy.Dataset(self.data)
10
+
11
+ @classmethod
12
+ def from_csv(cls, file_path: str) -> "Dataset":
13
+ with open(file_path, "r") as file:
14
+ data = file.read()
15
+ return cls(data)
16
+
17
+ @classmethod
18
+ def from_hub(cls, dataset_name: str) -> "Dataset":
19
+ from datasets import load_dataset
20
+
21
+ data = load_dataset(dataset_name)
22
+ return cls(data)
modaic/hub.py CHANGED
@@ -1,15 +1,17 @@
1
1
  import os
2
+ import shutil
2
3
  from pathlib import Path
3
4
  from typing import Any, Dict, Optional
4
5
 
5
6
  import git
6
7
  import requests
7
- from dotenv import load_dotenv
8
+ from dotenv import find_dotenv, load_dotenv
8
9
 
9
10
  from .exceptions import AuthenticationError, RepositoryExistsError, RepositoryNotFoundError
10
11
  from .utils import compute_cache_dir
11
12
 
12
- load_dotenv()
13
+ env_file = find_dotenv(usecwd=True)
14
+ load_dotenv(env_file)
13
15
 
14
16
  MODAIC_TOKEN = os.getenv("MODAIC_TOKEN")
15
17
  MODAIC_GIT_URL = os.getenv("MODAIC_GIT_URL", "git.modaic.dev").replace("https://", "").rstrip("/")
@@ -80,6 +82,7 @@ def create_remote_repo(repo_path: str, access_token: str, exist_ok: bool = False
80
82
  raise Exception(f"Request failed: {str(e)}") from e
81
83
 
82
84
 
85
+ # FIXME: make faster. Currently takes ~9 seconds
83
86
  def push_folder_to_hub(
84
87
  folder: str,
85
88
  repo_path: str,
@@ -123,10 +126,11 @@ def push_folder_to_hub(
123
126
  "Modaic fast paths not yet implemented. Please load agents with 'user/repo' or 'org/repo' format"
124
127
  )
125
128
  assert repo_path.count("/") <= 1, f"Extra '/' in repo_path: {repo_path}"
126
-
129
+ # TODO: try pushing first and on error create the repo. create_remote_repo currently takes ~1.5 seconds to run
127
130
  create_remote_repo(repo_path, access_token, exist_ok=True)
128
131
  username = get_user_info(access_token)["login"]
129
132
 
133
+ # FIXME: takes 6 seconds
130
134
  try:
131
135
  # 1) If local folder is not a git repository, initialize it.
132
136
  local_repo = git.Repo.init(folder)
@@ -205,6 +209,7 @@ def get_repo_payload(repo_name: str) -> Dict[str, Any]:
205
209
  return payload
206
210
 
207
211
 
212
+ # TODO: add persistent filesystem based cache mapping access_token to user_info. Currently takes ~1 second
208
213
  def get_user_info(access_token: str) -> Dict[str, Any]:
209
214
  """
210
215
  Returns the user info for the given access token.
@@ -214,12 +219,14 @@ def get_user_info(access_token: str) -> Dict[str, Any]:
214
219
  access_token: The access token to get the user info for.
215
220
 
216
221
  Returns:
222
+ ```python
217
223
  {
218
224
  "login": str,
219
225
  "email": str,
220
226
  "avatar_url": str,
221
227
  "name": str,
222
228
  }
229
+ ```
223
230
  """
224
231
  global user_info
225
232
  if user_info:
@@ -243,6 +250,7 @@ def get_user_info(access_token: str) -> Dict[str, Any]:
243
250
  return user_info
244
251
 
245
252
 
253
+ # TODO:
246
254
  def git_snapshot(
247
255
  repo_path: str,
248
256
  *,
@@ -265,7 +273,6 @@ def git_snapshot(
265
273
  elif access_token is None:
266
274
  raise ValueError("Access token is required")
267
275
 
268
- # If a local folder path is provided, just return it
269
276
  repo_dir = Path(AGENTS_CACHE) / repo_path
270
277
  username = get_user_info(access_token)["login"]
271
278
  try:
@@ -291,10 +298,26 @@ def git_snapshot(
291
298
  repo.git.reset("--hard", f"origin/{target}")
292
299
  return repo_dir
293
300
  except Exception as e:
294
- repo_dir.rmdir()
301
+ shutil.rmtree(repo_dir)
295
302
  raise e
296
303
 
297
304
 
305
+ def _move_to_commit_sha_folder(repo: git.Repo) -> git.Repo:
306
+ """
307
+ Moves the repo to a new path based on the commit SHA. (Unused for now)
308
+ Args:
309
+ repo: The git.Repo object.
310
+
311
+ Returns:
312
+ The new git.Repo object.
313
+ """
314
+ commit = repo.head.commit
315
+ repo_dir = Path(repo.working_dir)
316
+ new_path = repo_dir / commit.hexsha
317
+ repo_dir.rename(new_path)
318
+ return git.Repo(new_path)
319
+
320
+
298
321
  def load_repo(repo_path: str, is_local: bool = False) -> Path:
299
322
  if is_local:
300
323
  path = Path(repo_path)
modaic/indexing.py CHANGED
@@ -77,7 +77,7 @@ class PineconeReranker(Reranker):
77
77
  try:
78
78
  from pinecone import Pinecone
79
79
  except ImportError:
80
- raise ImportError("Pinecone is not installed. Please install it with `uv add pinecone`")
80
+ raise ImportError("Pinecone is not installed. Please install it with `uv add pinecone`") from None
81
81
 
82
82
  if api_key is None:
83
83
  self.pinecone = Pinecone(os.getenv("PINECONE_API_KEY"))
modaic/module_utils.py CHANGED
@@ -16,6 +16,7 @@ from .utils import compute_cache_dir
16
16
  MODAIC_CACHE = compute_cache_dir()
17
17
  AGENTS_CACHE = Path(MODAIC_CACHE) / "agents"
18
18
  EDITABLE_MODE = os.getenv("EDITABLE_MODE", "false").lower() == "true"
19
+ TEMP_DIR = Path(MODAIC_CACHE) / "temp"
19
20
 
20
21
 
21
22
  def is_builtin(module_name: str) -> bool:
@@ -76,6 +77,7 @@ def is_builtin_or_frozen(mod: ModuleType) -> bool:
76
77
  return (name in sys.builtin_module_names) or (origin in ("built-in", "frozen"))
77
78
 
78
79
 
80
+ # FIXME: make faster. Currently takes ~.70 seconds
79
81
  def get_internal_imports() -> Dict[str, ModuleType]:
80
82
  """Return only internal modules currently loaded in sys.modules.
81
83
 
@@ -107,6 +109,10 @@ def get_internal_imports() -> Dict[str, ModuleType]:
107
109
  if is_builtin_or_frozen(module):
108
110
  continue
109
111
 
112
+ # edge case: local modaic package
113
+ if name == "modaic" or "modaic." in name:
114
+ continue
115
+
110
116
  module_file = getattr(module, "__file__", None)
111
117
  if not module_file:
112
118
  continue
@@ -189,8 +195,11 @@ def is_external_package(path: Path) -> bool:
189
195
 
190
196
  def init_agent_repo(repo_path: str, with_code: bool = True) -> Path:
191
197
  """Create a local repository staging directory for agent modules and files, excluding ignored files and folders."""
192
- repo_dir = Path(AGENTS_CACHE) / repo_path
193
- repo_dir.mkdir(parents=True, exist_ok=True)
198
+ repo_dir = TEMP_DIR / repo_path
199
+ shutil.rmtree(repo_dir, ignore_errors=True)
200
+ repo_dir.mkdir(parents=True, exist_ok=False)
201
+
202
+ project_root = resolve_project_root()
194
203
 
195
204
  internal_imports = get_internal_imports()
196
205
  ignored_paths = get_ignored_files()
@@ -207,12 +216,12 @@ def init_agent_repo(repo_path: str, with_code: bool = True) -> Path:
207
216
  if not with_code:
208
217
  return repo_dir
209
218
 
210
- for module_name, module in internal_imports.items():
211
- module_file = getattr(module, "__file__", None)
219
+ for _, module in internal_imports.items():
220
+ module_file = Path(getattr(module, "__file__", None))
212
221
  if not module_file:
213
222
  continue
214
223
  try:
215
- src_path = Path(module_file).resolve()
224
+ src_path = module_file.resolve()
216
225
  except OSError:
217
226
  continue
218
227
  if src_path.suffix != ".py":
@@ -223,25 +232,33 @@ def init_agent_repo(repo_path: str, with_code: bool = True) -> Path:
223
232
  continue
224
233
  seen_files.add(src_path)
225
234
 
226
- # Split modul_name to get the relative path
227
- name_parts = module_name.split(".")
228
- if src_path.name == "__init__.py":
229
- copy_module_layout(repo_dir, name_parts)
230
- dest_path = repo_dir.joinpath(*name_parts) / "__init__.py"
231
- else:
232
- if len(name_parts) > 1:
233
- copy_module_layout(repo_dir, name_parts[:-1])
234
- else:
235
- repo_dir.mkdir(parents=True, exist_ok=True)
236
- # use the file name to name the file
237
- dest_path = repo_dir.joinpath(*name_parts[:-1]) / src_path.name
235
+ rel_path = module_file.relative_to(project_root)
236
+ dest_path = repo_dir / rel_path
238
237
  dest_path.parent.mkdir(parents=True, exist_ok=True)
239
238
  shutil.copy2(src_path, dest_path)
239
+
240
+ # Ensure __init__.py is copied over at every directory level
241
+ src_init = project_root / rel_path.parent / "__init__.py"
242
+ dest_init = dest_path.parent / "__init__.py"
243
+ if src_init.exists() and not dest_init.exists():
244
+ shutil.copy2(src_init, dest_init)
245
+
246
+ for extra_file in get_extra_files():
247
+ if extra_file.is_dir():
248
+ shutil.copytree(extra_file, repo_dir / extra_file.relative_to(project_root))
249
+ else:
250
+ shutil.copy2(extra_file, repo_dir / extra_file.relative_to(project_root))
251
+
240
252
  return repo_dir
241
253
 
242
254
 
243
255
  def create_agent_repo(repo_path: str, with_code: bool = True) -> Path:
244
256
  """
257
+ Args:
258
+ repo_path: The path to the repository.
259
+ with_code: Whether to include the code in the repository.
260
+ branch: The branch to post it to.
261
+ tag: The tag to give it.
245
262
  Create a temporary directory inside the Modaic cache. Containing everything that will be pushed to the hub. This function adds the following files:
246
263
  - All internal modules used to run the agent
247
264
  - The pyproject.toml
@@ -261,23 +278,52 @@ def get_ignored_files() -> list[Path]:
261
278
  pyproject_path = Path("pyproject.toml")
262
279
  doc = tomlk.parse(pyproject_path.read_text(encoding="utf-8"))
263
280
 
264
- # Safely get [tool.modaic.ignore]
265
- ignore_table = (
281
+ # Safely get [tool.modaic.exclude]
282
+ files = (
266
283
  doc.get("tool", {}) # [tool]
267
284
  .get("modaic", {}) # [tool.modaic]
268
- .get("ignore") # [tool.modaic.ignore]
285
+ .get("exclude", {}) # [tool.modaic.exclude]
286
+ .get("files", []) # [tool.modaic.exclude] files = ["file1", "file2"]
269
287
  )
270
288
 
271
- if ignore_table is None or "files" not in ignore_table:
272
- return []
289
+ excluded: list[Path] = []
290
+ for entry in files:
291
+ entry = Path(entry)
292
+ if not entry.is_absolute():
293
+ entry = project_root / entry
294
+ if entry.exists():
295
+ excluded.append(entry)
296
+ return excluded
273
297
 
274
- ignored: list[Path] = []
275
- for entry in ignore_table["files"]:
276
- try:
277
- ignored.append((project_root / entry).resolve())
278
- except OSError:
279
- continue
280
- return ignored
298
+
299
+ def get_extra_files() -> list[Path]:
300
+ """Return a list of extra files that should be excluded from staging."""
301
+ project_root = resolve_project_root()
302
+ pyproject_path = Path("pyproject.toml")
303
+ doc = tomlk.parse(pyproject_path.read_text(encoding="utf-8"))
304
+ files = (
305
+ doc.get("tool", {}) # [tool]
306
+ .get("modaic", {}) # [tool.modaic]
307
+ .get("include", {}) # [tool.modaic.include]
308
+ .get("files", []) # [tool.modaic.include] files = ["file1", "file2"]
309
+ )
310
+ included: list[Path] = []
311
+ for entry in files:
312
+ entry = Path(entry)
313
+ if entry.is_absolute():
314
+ try:
315
+ entry = entry.resolve()
316
+ entry.relative_to(project_root.resolve())
317
+ except ValueError:
318
+ warnings.warn(
319
+ f"{entry} will not be bundled because it is not inside the current working directory", stacklevel=4
320
+ )
321
+ else:
322
+ entry = project_root / entry
323
+ if entry.resolve().exists():
324
+ included.append(entry)
325
+
326
+ return included
281
327
 
282
328
 
283
329
  def create_pyproject_toml(repo_dir: Path, package_name: str):
@@ -293,7 +339,7 @@ def create_pyproject_toml(repo_dir: Path, package_name: str):
293
339
  if "project" not in doc_old:
294
340
  raise KeyError("No [project] table in old TOML")
295
341
  doc_new["project"] = doc_old["project"]
296
- doc_new["project"]["dependencies"] = get_filtered_dependencies(doc_old["project"]["dependencies"])
342
+ doc_new["project"]["dependencies"] = get_final_dependencies(doc_old["project"]["dependencies"])
297
343
  if "tool" in doc_old and "uv" in doc_old["tool"] and "sources" in doc_old["tool"]["uv"]:
298
344
  doc_new["tool"] = {"uv": {"sources": doc_old["tool"]["uv"]["sources"]}}
299
345
  warn_if_local(doc_new["tool"]["uv"]["sources"])
@@ -304,29 +350,32 @@ def create_pyproject_toml(repo_dir: Path, package_name: str):
304
350
  tomlk.dump(doc_new, fp)
305
351
 
306
352
 
307
- def get_filtered_dependencies(dependencies: list[str]) -> list[str]:
353
+ def get_final_dependencies(dependencies: list[str]) -> list[str]:
308
354
  """
309
355
  Get the dependencies that should be included in the bundled agent.
356
+ Filters out "[tool.modaic.ignore] dependencies. Adds [tool.modaic.include] dependencies.
310
357
  """
311
358
  pyproject_path = Path("pyproject.toml")
312
359
  doc = tomlk.parse(pyproject_path.read_text(encoding="utf-8"))
313
360
 
314
- # Safely get [tool.modaic.ignore]
315
- ignore_table = (
361
+ # Safely get [tool.modaic.exclude]
362
+ exclude_deps = (
316
363
  doc.get("tool", {}) # [tool]
317
364
  .get("modaic", {}) # [tool.modaic]
318
- .get("ignore", {}) # [tool.modaic.ignore]
365
+ .get("exclude", {}) # [tool.modaic.exclude]
366
+ .get("dependencies", []) # [tool.modaic.exclude] dependencies = ["praw", "sagemaker"]
367
+ )
368
+ include_deps = (
369
+ doc.get("tool", {}) # [tool]
370
+ .get("modaic", {}) # [tool.modaic]
371
+ .get("include", {}) # [tool.modaic.include]
372
+ .get("dependencies", []) # [tool.modaic.include] dependencies = ["praw", "sagemaker"]
319
373
  )
320
374
 
321
- if "dependencies" not in ignore_table:
322
- return dependencies
323
-
324
- ignored_dependencies = ignore_table["dependencies"]
325
- if not ignored_dependencies:
326
- return dependencies
327
- pattern = re.compile(r"\b(" + "|".join(map(re.escape, ignored_dependencies)) + r")\b")
328
- filtered_dependencies = [pkg for pkg in dependencies if not pattern.search(pkg)]
329
- return filtered_dependencies
375
+ if exclude_deps:
376
+ pattern = re.compile(r"\b(" + "|".join(map(re.escape, exclude_deps)) + r")\b")
377
+ dependencies = [pkg for pkg in dependencies if not pattern.search(pkg)]
378
+ return dependencies + include_deps
330
379
 
331
380
 
332
381
  def warn_if_local(sources: dict[str, dict]):
@@ -339,3 +388,27 @@ def warn_if_local(sources: dict[str, dict]):
339
388
  f"Bundling agent with local package {source} installed from {config['path']}. This is not recommended.",
340
389
  stacklevel=5,
341
390
  )
391
+
392
+
393
+ def _module_path(instance: object) -> str:
394
+ """
395
+ Return a deterministic module path for the given instance.
396
+
397
+ Args:
398
+ instance: The object instance whose class path should be resolved.
399
+
400
+ Returns:
401
+ str: A fully qualified path in the form "<module>.<ClassName>". If the
402
+ class' module is "__main__", use the file system to derive a stable
403
+ module name: the parent directory name when the file is "__main__.py",
404
+ otherwise the file stem.
405
+ """
406
+
407
+ cls = type(instance)
408
+ module_name = cls.__module__
409
+ module = sys.modules[module_name]
410
+ file = Path(module.__file__)
411
+ module_path = str(file.relative_to(resolve_project_root()).with_suffix(""))
412
+ module_path = module_path.replace("/", ".")
413
+
414
+ return f"{module_path}.{cls.__name__}"
modaic/observability.py CHANGED
@@ -38,7 +38,7 @@ _configured = False
38
38
 
39
39
 
40
40
  def configure(
41
- tracing: bool = True,
41
+ tracing: bool = False,
42
42
  repo: Optional[str] = None,
43
43
  project: Optional[str] = None,
44
44
  base_url: str = "https://api.modaic.dev",
@@ -92,7 +92,7 @@ def configure(
92
92
  if project_name:
93
93
  _opik_client = Opik(host=base_url, project_name=project_name)
94
94
 
95
- config.update_session_config("track_disable", not tracing)
95
+ config.update_session_config("track_disable", not tracing)
96
96
 
97
97
  _configured = True
98
98
 
@@ -207,10 +207,17 @@ class Trackable:
207
207
  All Modaic classes except PrecompiledAgent should inherit from this class.
208
208
  """
209
209
 
210
- def __init__(self, repo: Optional[str] = None, project: Optional[str] = None, commit: Optional[str] = None):
210
+ def __init__(
211
+ self,
212
+ repo: Optional[str] = None,
213
+ project: Optional[str] = None,
214
+ commit: Optional[str] = None,
215
+ trace: bool = False,
216
+ ):
211
217
  self.repo = repo
212
218
  self.project = project
213
219
  self.commit = commit
220
+ self.trace = trace
214
221
 
215
222
  def set_repo_project(self, repo: Optional[str] = None, project: Optional[str] = None, trace: bool = True):
216
223
  """Update the repo and project for this trackable object."""
@@ -218,10 +225,7 @@ class Trackable:
218
225
  self.repo = repo
219
226
 
220
227
  self.project = f"{self.repo}-{project}" if project else self.repo
221
-
222
- # configure global tracing
223
- if trace and (repo or project):
224
- configure(tracing=trace, repo=repo or self.repo, project=project or self.project)
228
+ self.trace = trace
225
229
 
226
230
 
227
231
  MethodDecorator = Callable[
@@ -254,8 +258,8 @@ def track_modaic_obj(func: Callable[Concatenate[T, P], R]) -> Callable[Concatena
254
258
  repo = getattr(self, "repo", None)
255
259
  project = getattr(self, "project", None)
256
260
 
257
- # check if tracking is enabled globally
258
- if not _settings.tracing:
261
+ # check if tracking is enabled both globally and for this object
262
+ if not _settings.tracing or not self.trace:
259
263
  # binds the method to self so it can be called with args and kwars, also type cast's it to callable with type vars for static type checking
260
264
  bound = cast(Callable[P, R], func.__get__(self, type(self)))
261
265
  return bound(*args, **kwargs)
modaic/precompiled.py CHANGED
@@ -4,7 +4,15 @@ import os
4
4
  import pathlib
5
5
  from abc import ABC, abstractmethod
6
6
  from pathlib import Path
7
- from typing import TYPE_CHECKING, ClassVar, Dict, Generic, List, Optional, Type, TypeVar, Union
7
+ from typing import (
8
+ TYPE_CHECKING,
9
+ Dict,
10
+ List,
11
+ Optional,
12
+ Type,
13
+ TypeVar,
14
+ Union,
15
+ )
8
16
 
9
17
  import dspy
10
18
  from pydantic import BaseModel
@@ -13,6 +21,7 @@ from modaic.module_utils import create_agent_repo
13
21
  from modaic.observability import Trackable, track_modaic_obj
14
22
 
15
23
  from .hub import load_repo, push_folder_to_hub
24
+ from .module_utils import _module_path
16
25
 
17
26
  if TYPE_CHECKING:
18
27
  from modaic.context.base import Context
@@ -119,6 +128,7 @@ class PrecompiledConfig(BaseModel):
119
128
  return self.model_dump_json()
120
129
 
121
130
 
131
+ # Use a metaclass to enforce super().__init__() with config
122
132
  class PrecompiledAgent(dspy.Module):
123
133
  """
124
134
  Bases: `dspy.Module`
@@ -140,6 +150,7 @@ class PrecompiledAgent(dspy.Module):
140
150
  ):
141
151
  # create DSPy callback for observability if tracing is enabled
142
152
  callbacks = []
153
+ # FIXME This logic is not correct.
143
154
  if trace and (repo or project):
144
155
  try:
145
156
  from opik.integrations.dspy.callback import OpikCallback
@@ -150,7 +161,7 @@ class PrecompiledAgent(dspy.Module):
150
161
  elif repo and not project:
151
162
  project_name = repo
152
163
  else:
153
- raise ValueError("Must provide either repo to enable tracing")
164
+ raise ValueError("Must provide either repo to enable observability tracking")
154
165
 
155
166
  opik_callback = OpikCallback(project_name=project_name, log_graph=True)
156
167
  callbacks.append(opik_callback)
@@ -160,6 +171,7 @@ class PrecompiledAgent(dspy.Module):
160
171
 
161
172
  # initialize DSPy Module with callbacks
162
173
  super().__init__()
174
+ # FIXME this adds the same callback for every agent. Should only be the current agent.
163
175
  if callbacks:
164
176
  # set callbacks using DSPy's configuration
165
177
  import dspy
@@ -269,7 +281,11 @@ class PrecompiledAgent(dspy.Module):
269
281
  with_code: Whether to save the code along with the agent.json and config.json.
270
282
  """
271
283
  _push_to_hub(
272
- self, repo_path=repo_path, access_token=access_token, commit_message=commit_message, with_code=with_code
284
+ self,
285
+ repo_path=repo_path,
286
+ access_token=access_token,
287
+ commit_message=commit_message,
288
+ with_code=with_code,
273
289
  )
274
290
 
275
291
 
@@ -363,41 +379,6 @@ class Indexer(Retriever):
363
379
  pass
364
380
 
365
381
 
366
- def _module_path(instance: object) -> str:
367
- """
368
- Return a deterministic module path for the given instance.
369
-
370
- Args:
371
- instance: The object instance whose class path should be resolved.
372
-
373
- Returns:
374
- str: A fully qualified path in the form "<module>.<ClassName>". If the
375
- class' module is "__main__", use the file system to derive a stable
376
- module name: the parent directory name when the file is "__main__.py",
377
- otherwise the file stem.
378
- """
379
-
380
- cls = type(instance)
381
- module_name = getattr(cls, "__module__", "__main__")
382
- class_name = getattr(cls, "__name__", "Object")
383
- if module_name != "__main__":
384
- return f"{module_name}.{class_name}"
385
-
386
- # When executed as a script, classes often report __module__ == "__main__".
387
- # Normalize to a deterministic name based on the defining file path.
388
- try:
389
- file_path = pathlib.Path(inspect.getfile(cls)).resolve()
390
- except Exception:
391
- # Fallback to a generic name if the file cannot be determined
392
- normalized_root = "main"
393
- else:
394
- if file_path.name == "__main__.py":
395
- normalized_root = file_path.parent.name or "main"
396
- else:
397
- normalized_root = file_path.stem or "main"
398
- return f"{normalized_root}.{class_name}"
399
-
400
-
401
382
  # CAVEAT: PrecompiledConfig does not support push_to_hub() intentionally,
402
383
  # this is to avoid confusion when pushing a config to the hub thinking it
403
384
  # will update the config.json when in reality it will overwrite the entire
@@ -414,7 +395,12 @@ def _push_to_hub(
414
395
  """
415
396
  repo_dir = create_agent_repo(repo_path, with_code=with_code)
416
397
  self.save_precompiled(repo_dir, _with_auto_classes=with_code)
417
- push_folder_to_hub(repo_dir, repo_path=repo_path, access_token=access_token, commit_message=commit_message)
398
+ push_folder_to_hub(
399
+ repo_dir,
400
+ repo_path=repo_path,
401
+ access_token=access_token,
402
+ commit_message=commit_message,
403
+ )
418
404
 
419
405
 
420
406
  def is_local_path(s: str | Path) -> bool:
modaic/query_language.py CHANGED
@@ -1,7 +1,7 @@
1
1
  from types import NoneType
2
- from typing import Any, Literal, Optional, Type, TypeAlias, Union
2
+ from typing import Optional, Type, TypeAlias, Union
3
3
 
4
- from langchain_core.structured_query import Comparator, Comparison, Operation, Operator, StructuredQuery, Visitor
4
+ from langchain_core.structured_query import Comparator, Comparison, Operation, Operator, Visitor
5
5
 
6
6
  ValueType: TypeAlias = Union[int, str, float, bool, NoneType, list, "Value"]
7
7
 
@@ -32,30 +32,6 @@ allowed_types = {
32
32
  }
33
33
 
34
34
 
35
- # def _print_return(func): # noqa: ANN001
36
- # def wrapper(*args, **kwargs):
37
- # result = func(*args, **kwargs)
38
- # if isinstance(op := args[1], str) and op[0] == "$":
39
- # if kwargs.get("recursed", False):
40
- # print( # noqa: T201
41
- # f"{repr(args[0])} ({mql_operator_to_python[op]}) {repr(args[2])} ->:",
42
- # result,
43
- # )
44
- # else:
45
- # print( # noqa: T201
46
- # f"{repr(args[0])} {mql_operator_to_python[op]} {repr(args[2])} ->:",
47
- # result,
48
- # )
49
- # else:
50
- # if func.__name__ == "__and__":
51
- # print(f"{repr(args[0])} & {repr(args[1])} ->:", result) # noqa: T201
52
- # elif func.__name__ == "__rand__":
53
- # print(f"{repr(args[1])} & {repr(args[0])} ->:", result) # noqa: T201
54
- # return result
55
-
56
- # return wrapper
57
-
58
-
59
35
  class Condition:
60
36
  """
61
37
  Modaic Query Language Property class.
modaic/types.py CHANGED
@@ -207,6 +207,8 @@ class InnerField(BaseModel):
207
207
  # NOTE: handle case where the float type was used and therefore not annotated with a format
208
208
  if is_optional:
209
209
  raise SchemaError("Array/List elements cannot be None/null")
210
+ if inspected_type["type"] == "object" or inspected_type["type"] == "array":
211
+ raise SchemaError("Arrays and Dicts are not supported for Array/List elements")
210
212
  return InnerField(
211
213
  type=inspected_type["type"],
212
214
  format=inspected_type.get("format", None),
modaic/utils.py CHANGED
@@ -2,9 +2,10 @@ import os
2
2
  import re
3
3
  from pathlib import Path
4
4
 
5
- from dotenv import load_dotenv
5
+ from dotenv import find_dotenv, load_dotenv
6
6
 
7
- load_dotenv()
7
+ env_file = find_dotenv(usecwd=True)
8
+ load_dotenv(env_file)
8
9
 
9
10
 
10
11
  def compute_cache_dir() -> Path:
@@ -18,4 +19,6 @@ def compute_cache_dir() -> Path:
18
19
 
19
20
  def validate_project_name(text: str) -> bool:
20
21
  """Letters, numbers, underscore, hyphen"""
21
- assert bool(re.match(r'^[a-zA-Z0-9_]+$', text)), "Invalid project name. Must contain only letters, numbers, and underscore."
22
+ assert bool(re.match(r"^[a-zA-Z0-9_]+$", text)), (
23
+ "Invalid project name. Must contain only letters, numbers, and underscore."
24
+ )
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: modaic
3
- Version: 0.1.2
4
- Summary: Modular Agent Infrastructure Collective, a python framework for managing and sharing DSPy agents
3
+ Version: 0.3.0
4
+ Summary: Modular Agent Infrastructure Collection, a python framework for managing and sharing DSPy agents
5
5
  Author-email: Tyrin <tytodd@mit.edu>, Farouk <farouk@modaic.dev>
6
6
  License: MIT License
7
7
 
@@ -48,6 +48,7 @@ Requires-Dist: langchain-community>=0.3.29
48
48
  Requires-Dist: langchain-core>=0.3.72
49
49
  Requires-Dist: langchain-text-splitters>=0.3.9
50
50
  Requires-Dist: more-itertools>=10.8.0
51
+ Requires-Dist: openpyxl>=3.1.5
51
52
  Requires-Dist: opik==1.8.42
52
53
  Requires-Dist: pillow>=11.3.0
53
54
  Requires-Dist: pymilvus>=2.5.14
@@ -58,8 +59,11 @@ Requires-Dist: pinecone>=7.3.0; extra == "pinecone"
58
59
  Dynamic: license-file
59
60
 
60
61
  [![Docs](https://img.shields.io/badge/docs-available-brightgreen.svg)](https://docs.modaic.dev)
62
+ [![PyPI](https://img.shields.io/pypi/v/modaic)](https://pypi.org/project/modaic/)
63
+
64
+
61
65
  # Modaic 🐙
62
- **Mod**ular **A**gent **I**nfrastructure **C**ollective, a Python framework for building AI agents with structured context management, database integration, and retrieval-augmented generation (RAG) capabilities.
66
+ **Mod**ular **A**gent **I**nfrastructure **C**ollection, a Python framework for building AI agents with structured context management, database integration, and retrieval-augmented generation (RAG) capabilities.
63
67
 
64
68
  ## Overview
65
69
 
@@ -255,7 +259,6 @@ from modaic.databases import VectorDatabase, SQLDatabase
255
259
  from modaic.types import Indexer
256
260
 
257
261
  class TableRAGConfig(PrecompiledConfig):
258
- agent_type = "TableRAGAgent"
259
262
  k_recall: int = 50
260
263
  k_rerank: int = 5
261
264
 
@@ -1,23 +1,24 @@
1
- modaic/__init__.py,sha256=rf2O0S7OAz5fBkmOcwygsM3u8Nmq_ios01ToNweNnSk,639
2
- modaic/auto_agent.py,sha256=jegs8HMbE5OICZIDtBrP4kIma_R7rzy-1Kgmb_-eCck,8695
1
+ modaic/__init__.py,sha256=xHu2SUk3OMvb8PIzrVCRS1pBk-Ho9BhwmzKOf_bOjGc,809
2
+ modaic/auto.py,sha256=rPOdQ7s-YGBQLa_v6lVONH8pbOrarPwp4VzRErp0y5c,9091
3
+ modaic/datasets.py,sha256=K-PpPSYIxJI0-yH-SBVpk_EfCM9i_uPz-brmlzP7hzI,513
3
4
  modaic/exceptions.py,sha256=XxzxOWjZTzT3l1BqTr7coJnVGxJq53uppRNrqP__YGo,651
4
- modaic/hub.py,sha256=iWvWjaZxurd2BRXTS2gjhBvqVE1TDtwF0N7Falwj04Q,10527
5
- modaic/indexing.py,sha256=L0O5yV7AhDUJ0gMyGE17BvHN2gwHxwkOMaxNTkyWQ8g,4185
6
- modaic/module_utils.py,sha256=DDXUmcGFdaah_EhTlfdHC26ohmMwLNlIYo6PzYzKzqc,10728
7
- modaic/observability.py,sha256=QEjLbmsVQzWZuxKQU8TBMSHsHVGvTzOeoNlEn_srmyg,9955
8
- modaic/precompiled.py,sha256=g0AsFrHxzTlDETDqxZFqjHaLqW6m5OpGGyI01xDBT5U,15788
9
- modaic/query_language.py,sha256=c-La7jYhHgNyjlQaxz0ALvUoiCDGzH9DpSD_9cozxNQ,10463
10
- modaic/types.py,sha256=sHJ7J9YGfWIkDPfCuRc-n4O9n7g7LNnKSZperAviRFc,9905
11
- modaic/utils.py,sha256=zbeMlrP_hoo8JUKR_bcuYPxrlYcckY3p0KJ_h4CN5VQ,721
5
+ modaic/hub.py,sha256=d5HQjaE26K1qNCBc32qJtrpESyRv6OiniAteasiN_rk,11290
6
+ modaic/indexing.py,sha256=VdILiXiLVzgV1pSTV8Ho7x1dZtd31Y9z60d_Qtqr2NU,4195
7
+ modaic/module_utils.py,sha256=I6kGCmGSuHM9lxz8rpCIkdFHCh0M7OIyw3GZ3966YWY,13442
8
+ modaic/observability.py,sha256=LgR4gJM4DhD-xlVX52mzRQSPgLQzbeh2LYPmQVqSh-A,9947
9
+ modaic/precompiled.py,sha256=_FwosgvItwnliVOc6nUp15RaBinmo1tTYhR9haun020,14864
10
+ modaic/query_language.py,sha256=BJIigR0HLapiIn9fF7jM7PkLM8OWUDjwYuxmzcCVvyo,9487
11
+ modaic/types.py,sha256=gcx8J4oxrHwxA7McyYV4OKHsuPhhmowJtJIgjJQbLto,10081
12
+ modaic/utils.py,sha256=doJs-XL4TswSQFBINZeKrik-cvjZk-tS9XmWH8fOYiw,794
12
13
  modaic/agents/rag_agent.py,sha256=f8s3EILOPUxMpOKDoAvk-cfLE8S9kFNvkEcAC5z2EmQ,798
13
14
  modaic/agents/registry.py,sha256=z6GuPxGrq2dinCamiMJ_HVPsD9Tp9XWDUSMZ-uhWPrU,2446
14
- modaic/context/__init__.py,sha256=WTBo-WqhgeR84P3MEq0snLZyIHnLyv9VYO5Wfp4vrZo,534
15
- modaic/context/base.py,sha256=QrRNBs05fb5EXN4intHT4D-XIG76RzvrO6j8RXJpzd4,40380
15
+ modaic/context/__init__.py,sha256=FK-bxSu36yGFF1rATy4Yzl4Fpv9kYOlRpBRfr_4moiM,560
16
+ modaic/context/base.py,sha256=x66_lcdQ063DiluC6UnFEH4etgJkbAyukrgrp2KLV5U,40368
16
17
  modaic/context/dtype_mapping.py,sha256=xRasW-H92YEuOfH8SbsVnodM9F-90pazott8qF2GWHw,519
17
- modaic/context/table.py,sha256=c0OUVwglaDRtJ2Uo9z7bAKhIJpJXqwWk1VkKwQNOvUY,17696
18
- modaic/context/text.py,sha256=S8E-dbTe-Wip8KCZ5vcIOZVyiVQReIL4bSo0anQw828,2581
18
+ modaic/context/table.py,sha256=9Lh2_UyK3OsWmgUfZQa8jDeVAPAk_iueT89_cruDeSo,17699
19
+ modaic/context/text.py,sha256=gCVQx15FrPcmpr2GYkJca6noh7fw_nTcCt-hISwcnvQ,2581
19
20
  modaic/databases/__init__.py,sha256=-w_yiY-Sqi1SgcPD5oAQL7MU4VXTihPa1GYGlrHfsFw,784
20
- modaic/databases/graph_database.py,sha256=vMCYQrnBu5AIIGF_akkU9lWKFdbIDF3tlcyxiNQ_vSQ,9933
21
+ modaic/databases/graph_database.py,sha256=j44PgWGMeD3dtPZe5sRpKnruTA3snm_TiXncusTzqIQ,9990
21
22
  modaic/databases/sql_database.py,sha256=wqy7AqsalhmYsbNPy0FCAg1FrUKN6Bd8ytwyJireC94,12057
22
23
  modaic/databases/vector_database/__init__.py,sha256=sN1SuSAMC9NHJDOa80BN_olccaHgmiW2Ek57hBvdZWo,306
23
24
  modaic/databases/vector_database/vector_database.py,sha256=RsuRemgFV06opY26CekqLLRoAEFYOGl_CMuFETrYS0c,25238
@@ -32,8 +33,8 @@ modaic/databases/vector_database/vendors/qdrant.py,sha256=AbpHGcgLb-kRsJGnwFEktk
32
33
  modaic/storage/__init__.py,sha256=Zs-Y_9jfYUE8XVp8z-El0ZXFM_ZVMqM9aQ6fgGPZsf8,131
33
34
  modaic/storage/file_store.py,sha256=kSS7gTP_-16wR3Xgq3frF1BZ8Dw8N--kG4V9rrCXPcc,7315
34
35
  modaic/storage/pickle_store.py,sha256=fu9jkmmKNE852Y4R1NhOFePLfd2gskhHSXxuq1G1S3I,778
35
- modaic-0.1.2.dist-info/licenses/LICENSE,sha256=7LMx9j453Vz1DoQbFot8Uhp9SExF5wlOx7c8vw2qhsE,1333
36
- modaic-0.1.2.dist-info/METADATA,sha256=uwXUFpL8YCXXPaeDBVb5zc-luhpDvysCoyHP4VPsC2s,8569
37
- modaic-0.1.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
38
- modaic-0.1.2.dist-info/top_level.txt,sha256=RXWGuF-TsW8-17DveTJMPRiAgg_Rf2mq5F3R7tNu6t8,7
39
- modaic-0.1.2.dist-info/RECORD,,
36
+ modaic-0.3.0.dist-info/licenses/LICENSE,sha256=7LMx9j453Vz1DoQbFot8Uhp9SExF5wlOx7c8vw2qhsE,1333
37
+ modaic-0.3.0.dist-info/METADATA,sha256=Cw0LkkLDfVGdxif1ZSx9HI9q9c5HSIuzDI-VVWRFRO4,8651
38
+ modaic-0.3.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
39
+ modaic-0.3.0.dist-info/top_level.txt,sha256=RXWGuF-TsW8-17DveTJMPRiAgg_Rf2mq5F3R7tNu6t8,7
40
+ modaic-0.3.0.dist-info/RECORD,,
File without changes