modaic 0.1.2__py3-none-any.whl → 0.2.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 +13 -1
- modaic/{auto_agent.py → auto.py} +85 -53
- modaic/context/__init__.py +2 -1
- modaic/context/base.py +1 -1
- modaic/context/table.py +1 -1
- modaic/context/text.py +2 -2
- modaic/databases/graph_database.py +3 -2
- modaic/datasets.py +22 -0
- modaic/hub.py +28 -5
- modaic/indexing.py +1 -1
- modaic/module_utils.py +52 -17
- modaic/observability.py +13 -9
- modaic/precompiled.py +24 -39
- modaic/query_language.py +2 -26
- modaic/types.py +2 -0
- modaic/utils.py +6 -3
- {modaic-0.1.2.dist-info → modaic-0.2.0.dist-info}/METADATA +6 -3
- {modaic-0.1.2.dist-info → modaic-0.2.0.dist-info}/RECORD +21 -20
- {modaic-0.1.2.dist-info → modaic-0.2.0.dist-info}/WHEEL +0 -0
- {modaic-0.1.2.dist-info → modaic-0.2.0.dist-info}/licenses/LICENSE +0 -0
- {modaic-0.1.2.dist-info → modaic-0.2.0.dist-info}/top_level.txt +0 -0
modaic/__init__.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from .
|
|
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()
|
modaic/{auto_agent.py → auto.py}
RENAMED
|
@@ -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
|
-
|
|
15
|
+
class RegisteredRepo(TypedDict, total=False):
|
|
16
|
+
AutoConfig: Type[PrecompiledConfig]
|
|
17
|
+
AutoAgent: Type[PrecompiledAgent]
|
|
18
|
+
AutoRetriever: Type[Retriever]
|
|
16
19
|
|
|
17
20
|
|
|
18
|
-
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
#
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
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,
|
|
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
|
-
|
|
71
|
-
|
|
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 {
|
|
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(
|
|
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.
|
|
122
|
-
AgentClass = _load_auto_class(
|
|
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.
|
|
172
|
-
RetrieverClass = _load_auto_class(
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
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 {
|
|
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 {
|
|
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
|
|
221
|
-
|
|
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
|
modaic/context/__init__.py
CHANGED
|
@@ -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
|
|
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 (
|
|
41
|
+
Picks at most three unique, non-null, short (<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.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
193
|
-
|
|
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
|
|
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 =
|
|
224
|
+
src_path = module_file.resolve()
|
|
216
225
|
except OSError:
|
|
217
226
|
continue
|
|
218
227
|
if src_path.suffix != ".py":
|
|
@@ -223,25 +232,27 @@ 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
|
-
|
|
227
|
-
|
|
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
|
+
|
|
240
246
|
return repo_dir
|
|
241
247
|
|
|
242
248
|
|
|
243
249
|
def create_agent_repo(repo_path: str, with_code: bool = True) -> Path:
|
|
244
250
|
"""
|
|
251
|
+
Args:
|
|
252
|
+
repo_path: The path to the repository.
|
|
253
|
+
with_code: Whether to include the code in the repository.
|
|
254
|
+
branch: The branch to post it to.
|
|
255
|
+
tag: The tag to give it.
|
|
245
256
|
Create a temporary directory inside the Modaic cache. Containing everything that will be pushed to the hub. This function adds the following files:
|
|
246
257
|
- All internal modules used to run the agent
|
|
247
258
|
- The pyproject.toml
|
|
@@ -339,3 +350,27 @@ def warn_if_local(sources: dict[str, dict]):
|
|
|
339
350
|
f"Bundling agent with local package {source} installed from {config['path']}. This is not recommended.",
|
|
340
351
|
stacklevel=5,
|
|
341
352
|
)
|
|
353
|
+
|
|
354
|
+
|
|
355
|
+
def _module_path(instance: object) -> str:
|
|
356
|
+
"""
|
|
357
|
+
Return a deterministic module path for the given instance.
|
|
358
|
+
|
|
359
|
+
Args:
|
|
360
|
+
instance: The object instance whose class path should be resolved.
|
|
361
|
+
|
|
362
|
+
Returns:
|
|
363
|
+
str: A fully qualified path in the form "<module>.<ClassName>". If the
|
|
364
|
+
class' module is "__main__", use the file system to derive a stable
|
|
365
|
+
module name: the parent directory name when the file is "__main__.py",
|
|
366
|
+
otherwise the file stem.
|
|
367
|
+
"""
|
|
368
|
+
|
|
369
|
+
cls = type(instance)
|
|
370
|
+
module_name = cls.__module__
|
|
371
|
+
module = sys.modules[module_name]
|
|
372
|
+
file = Path(module.__file__)
|
|
373
|
+
module_path = str(file.relative_to(resolve_project_root()).with_suffix(""))
|
|
374
|
+
module_path = module_path.replace("/", ".")
|
|
375
|
+
|
|
376
|
+
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 =
|
|
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
|
-
|
|
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__(
|
|
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
|
|
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
|
|
@@ -140,6 +149,7 @@ class PrecompiledAgent(dspy.Module):
|
|
|
140
149
|
):
|
|
141
150
|
# create DSPy callback for observability if tracing is enabled
|
|
142
151
|
callbacks = []
|
|
152
|
+
# FIXME This logic is not correct.
|
|
143
153
|
if trace and (repo or project):
|
|
144
154
|
try:
|
|
145
155
|
from opik.integrations.dspy.callback import OpikCallback
|
|
@@ -150,7 +160,7 @@ class PrecompiledAgent(dspy.Module):
|
|
|
150
160
|
elif repo and not project:
|
|
151
161
|
project_name = repo
|
|
152
162
|
else:
|
|
153
|
-
raise ValueError("Must provide either repo to enable
|
|
163
|
+
raise ValueError("Must provide either repo to enable observability tracking")
|
|
154
164
|
|
|
155
165
|
opik_callback = OpikCallback(project_name=project_name, log_graph=True)
|
|
156
166
|
callbacks.append(opik_callback)
|
|
@@ -160,6 +170,7 @@ class PrecompiledAgent(dspy.Module):
|
|
|
160
170
|
|
|
161
171
|
# initialize DSPy Module with callbacks
|
|
162
172
|
super().__init__()
|
|
173
|
+
# FIXME this adds the same callback for every agent. Should only be the current agent.
|
|
163
174
|
if callbacks:
|
|
164
175
|
# set callbacks using DSPy's configuration
|
|
165
176
|
import dspy
|
|
@@ -269,7 +280,11 @@ class PrecompiledAgent(dspy.Module):
|
|
|
269
280
|
with_code: Whether to save the code along with the agent.json and config.json.
|
|
270
281
|
"""
|
|
271
282
|
_push_to_hub(
|
|
272
|
-
self,
|
|
283
|
+
self,
|
|
284
|
+
repo_path=repo_path,
|
|
285
|
+
access_token=access_token,
|
|
286
|
+
commit_message=commit_message,
|
|
287
|
+
with_code=with_code,
|
|
273
288
|
)
|
|
274
289
|
|
|
275
290
|
|
|
@@ -363,41 +378,6 @@ class Indexer(Retriever):
|
|
|
363
378
|
pass
|
|
364
379
|
|
|
365
380
|
|
|
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
381
|
# CAVEAT: PrecompiledConfig does not support push_to_hub() intentionally,
|
|
402
382
|
# this is to avoid confusion when pushing a config to the hub thinking it
|
|
403
383
|
# will update the config.json when in reality it will overwrite the entire
|
|
@@ -414,7 +394,12 @@ def _push_to_hub(
|
|
|
414
394
|
"""
|
|
415
395
|
repo_dir = create_agent_repo(repo_path, with_code=with_code)
|
|
416
396
|
self.save_precompiled(repo_dir, _with_auto_classes=with_code)
|
|
417
|
-
push_folder_to_hub(
|
|
397
|
+
push_folder_to_hub(
|
|
398
|
+
repo_dir,
|
|
399
|
+
repo_path=repo_path,
|
|
400
|
+
access_token=access_token,
|
|
401
|
+
commit_message=commit_message,
|
|
402
|
+
)
|
|
418
403
|
|
|
419
404
|
|
|
420
405
|
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
|
|
2
|
+
from typing import Optional, Type, TypeAlias, Union
|
|
3
3
|
|
|
4
|
-
from langchain_core.structured_query import Comparator, Comparison, Operation, Operator,
|
|
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
|
-
|
|
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
|
|
22
|
+
assert bool(re.match(r"^[a-zA-Z0-9_]+$", text)), (
|
|
23
|
+
"Invalid project name. Must contain only letters, numbers, and underscore."
|
|
24
|
+
)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: modaic
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
4
4
|
Summary: Modular Agent Infrastructure Collective, 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
|
|
@@ -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
|
[](https://docs.modaic.dev)
|
|
62
|
+
[](https://pypi.org/project/modaic/)
|
|
63
|
+
|
|
64
|
+
|
|
61
65
|
# Modaic 🐙
|
|
62
|
-
**Mod**ular **A**gent **I**nfrastructure **C**
|
|
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=
|
|
2
|
-
modaic/
|
|
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=
|
|
5
|
-
modaic/indexing.py,sha256=
|
|
6
|
-
modaic/module_utils.py,sha256=
|
|
7
|
-
modaic/observability.py,sha256=
|
|
8
|
-
modaic/precompiled.py,sha256=
|
|
9
|
-
modaic/query_language.py,sha256=
|
|
10
|
-
modaic/types.py,sha256=
|
|
11
|
-
modaic/utils.py,sha256=
|
|
5
|
+
modaic/hub.py,sha256=d5HQjaE26K1qNCBc32qJtrpESyRv6OiniAteasiN_rk,11290
|
|
6
|
+
modaic/indexing.py,sha256=VdILiXiLVzgV1pSTV8Ho7x1dZtd31Y9z60d_Qtqr2NU,4195
|
|
7
|
+
modaic/module_utils.py,sha256=oJUOddvNGEIvEABOf7rzMB9erOkjDPm7FWLaBJ0XTSA,11797
|
|
8
|
+
modaic/observability.py,sha256=LgR4gJM4DhD-xlVX52mzRQSPgLQzbeh2LYPmQVqSh-A,9947
|
|
9
|
+
modaic/precompiled.py,sha256=cLRNoDB_ivawGftDpWQbkjjThrtID7bG1E-XVxi5kEM,14804
|
|
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=
|
|
15
|
-
modaic/context/base.py,sha256=
|
|
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=
|
|
18
|
-
modaic/context/text.py,sha256=
|
|
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=
|
|
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.
|
|
36
|
-
modaic-0.
|
|
37
|
-
modaic-0.
|
|
38
|
-
modaic-0.
|
|
39
|
-
modaic-0.
|
|
36
|
+
modaic-0.2.0.dist-info/licenses/LICENSE,sha256=7LMx9j453Vz1DoQbFot8Uhp9SExF5wlOx7c8vw2qhsE,1333
|
|
37
|
+
modaic-0.2.0.dist-info/METADATA,sha256=71CN4H1DdXoN4f-ahbju8JqUaTU4zagjm-E__nIwesY,8651
|
|
38
|
+
modaic-0.2.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
39
|
+
modaic-0.2.0.dist-info/top_level.txt,sha256=RXWGuF-TsW8-17DveTJMPRiAgg_Rf2mq5F3R7tNu6t8,7
|
|
40
|
+
modaic-0.2.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|