modis-py-tools 0.1.0__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 (40) hide show
  1. modis_py_tools-0.1.0/PKG-INFO +281 -0
  2. modis_py_tools-0.1.0/README.md +262 -0
  3. modis_py_tools-0.1.0/pyproject.toml +57 -0
  4. modis_py_tools-0.1.0/setup.cfg +4 -0
  5. modis_py_tools-0.1.0/src/modis_py_tools.egg-info/PKG-INFO +281 -0
  6. modis_py_tools-0.1.0/src/modis_py_tools.egg-info/SOURCES.txt +38 -0
  7. modis_py_tools-0.1.0/src/modis_py_tools.egg-info/dependency_links.txt +1 -0
  8. modis_py_tools-0.1.0/src/modis_py_tools.egg-info/requires.txt +15 -0
  9. modis_py_tools-0.1.0/src/modis_py_tools.egg-info/top_level.txt +1 -0
  10. modis_py_tools-0.1.0/src/modis_tools/__init__.py +65 -0
  11. modis_py_tools-0.1.0/src/modis_tools/_version.py +3 -0
  12. modis_py_tools-0.1.0/src/modis_tools/builtins/__init__.py +25 -0
  13. modis_py_tools-0.1.0/src/modis_tools/builtins/python.py +119 -0
  14. modis_py_tools-0.1.0/src/modis_tools/builtins/shell.py +227 -0
  15. modis_py_tools-0.1.0/src/modis_tools/builtins/shell_policy.py +240 -0
  16. modis_py_tools-0.1.0/src/modis_tools/builtins/web.py +281 -0
  17. modis_py_tools-0.1.0/src/modis_tools/conversion.py +175 -0
  18. modis_py_tools-0.1.0/src/modis_tools/providers/__init__.py +13 -0
  19. modis_py_tools-0.1.0/src/modis_tools/providers/valyu.py +268 -0
  20. modis_py_tools-0.1.0/src/modis_tools/providers/web.py +166 -0
  21. modis_py_tools-0.1.0/src/modis_tools/py.typed +1 -0
  22. modis_py_tools-0.1.0/src/modis_tools/registry.py +165 -0
  23. modis_py_tools-0.1.0/src/modis_tools/results.py +48 -0
  24. modis_py_tools-0.1.0/src/modis_tools/schemas.py +121 -0
  25. modis_py_tools-0.1.0/src/modis_tools/serialization.py +59 -0
  26. modis_py_tools-0.1.0/src/modis_tools/skills/__init__.py +22 -0
  27. modis_py_tools-0.1.0/src/modis_tools/skills/models.py +45 -0
  28. modis_py_tools-0.1.0/src/modis_tools/skills/prompt.py +60 -0
  29. modis_py_tools-0.1.0/src/modis_tools/skills/registry.py +153 -0
  30. modis_py_tools-0.1.0/src/modis_tools/skills/tools.py +128 -0
  31. modis_py_tools-0.1.0/tests/test_conversion.py +76 -0
  32. modis_py_tools-0.1.0/tests/test_live_web.py +70 -0
  33. modis_py_tools-0.1.0/tests/test_live_web_eval.py +104 -0
  34. modis_py_tools-0.1.0/tests/test_python_tool.py +55 -0
  35. modis_py_tools-0.1.0/tests/test_registry.py +87 -0
  36. modis_py_tools-0.1.0/tests/test_results.py +48 -0
  37. modis_py_tools-0.1.0/tests/test_shell_tool.py +171 -0
  38. modis_py_tools-0.1.0/tests/test_skills.py +171 -0
  39. modis_py_tools-0.1.0/tests/test_valyu_provider.py +164 -0
  40. modis_py_tools-0.1.0/tests/test_web_group.py +157 -0
@@ -0,0 +1,281 @@
1
+ Metadata-Version: 2.4
2
+ Name: modis-py-tools
3
+ Version: 0.1.0
4
+ Summary: Common MoDIS-compatible Python tools and tool-call execution helpers
5
+ Requires-Python: >=3.11
6
+ Description-Content-Type: text/markdown
7
+ Requires-Dist: pydantic>=2.7.0
8
+ Provides-Extra: web
9
+ Requires-Dist: valyu>=2.0.0; extra == "web"
10
+ Provides-Extra: browser
11
+ Requires-Dist: markdownify>=0.12.0; extra == "browser"
12
+ Requires-Dist: playwright>=1.45.0; extra == "browser"
13
+ Requires-Dist: readability-lxml>=0.8.1; extra == "browser"
14
+ Provides-Extra: dev
15
+ Requires-Dist: build>=1.2.0; extra == "dev"
16
+ Requires-Dist: mypy>=1.10.0; extra == "dev"
17
+ Requires-Dist: pytest>=8.0.0; extra == "dev"
18
+ Requires-Dist: ruff>=0.8.0; extra == "dev"
19
+
20
+ # MoDIS Python Tools
21
+
22
+ `modis-py-tools` provides MoDIS-compatible function tool definitions, tool
23
+ groups, and tool-call execution helpers for Python applications.
24
+
25
+ The distribution name is currently `modis-py-tools`; the import package is
26
+ `modis_tools`.
27
+
28
+ ## Install
29
+
30
+ ```bash
31
+ python -m pip install modis-py-tools
32
+ ```
33
+
34
+ Optional web provider dependency:
35
+
36
+ ```bash
37
+ python -m pip install "modis-py-tools[web]"
38
+ ```
39
+
40
+ Development:
41
+
42
+ ```bash
43
+ python -m pip install -e ".[dev,web]"
44
+ .venv/bin/python -m pytest
45
+ .venv/bin/python -m ruff check .
46
+ .venv/bin/python -m ruff format --check .
47
+ .venv/bin/python -m mypy src
48
+ .venv/bin/python -m build
49
+ ```
50
+
51
+ ## Function Conversion
52
+
53
+ ```python
54
+ from modis_tools import function_to_tool
55
+
56
+ def lookup_order(order_id: str, include_history: bool = False) -> dict:
57
+ """Look up an order.
58
+
59
+ Args:
60
+ order_id: Order identifier.
61
+ include_history: Whether to include status history.
62
+ """
63
+ return {"order_id": order_id, "status": "processing"}
64
+
65
+ tool = function_to_tool(lookup_order, name="orders.lookup")
66
+ tool_definition = tool.to_wire()
67
+ ```
68
+
69
+ ## Registry Execution
70
+
71
+ ```python
72
+ from modis_tools import ToolRegistry
73
+ from modis_tools.builtins import python_group, shell_group
74
+
75
+ registry = ToolRegistry()
76
+ registry.include(shell_group())
77
+ registry.include(python_group())
78
+
79
+ tool_definitions = registry.definitions()
80
+ results = registry.execute_tool_calls(model_tool_calls)
81
+ messages = [result.to_chat_message() for result in results]
82
+ ```
83
+
84
+ `execute_tool_call()` and `execute_tool_calls()` return failed `ToolResult`
85
+ objects by default for unknown tools, invalid arguments, and tool exceptions.
86
+ Pass `raise_on_error=True` when the host application should handle exceptions.
87
+
88
+ For a fuller host integration guide, including unattended pipeline setup and
89
+ future image generation extension notes, see `docs/INTEGRATION.md`.
90
+
91
+ ## Built-In Tools
92
+
93
+ ```python
94
+ from modis_tools.builtins import python_group, shell_group, skills_group, web_group
95
+
96
+ shell_tools = shell_group()
97
+ python_tools = python_group()
98
+ skill_tools = skills_group(skill_home="./skills")
99
+ web_tools = web_group(api_key="...")
100
+ ```
101
+
102
+ `shell.run` captures `stdout`, `stderr`, exit code, duration, timeout state,
103
+ working directory, policy decision metadata, and truncation metadata.
104
+ `python.run` executes Python source in a subprocess using the current
105
+ interpreter by default.
106
+
107
+ Shell and Python tools execute local code. Only expose them in trusted contexts
108
+ where the caller owns policy, sandboxing, and approval decisions.
109
+
110
+ Shell tools support host-owned policies. Policies are bound by the application
111
+ when registering the group and are not exposed as model tool-call parameters.
112
+
113
+ ```python
114
+ from modis_tools import ToolRegistry
115
+ from modis_tools.builtins import ShellPolicy, shell_group
116
+
117
+ registry = ToolRegistry()
118
+ registry.include(shell_group(policy=ShellPolicy.readonly_project("./")))
119
+ ```
120
+
121
+ Built-in shell policy profiles:
122
+
123
+ | Profile | Purpose |
124
+ | --- | --- |
125
+ | `trusted_local` | Backward-compatible default for trusted local use. |
126
+ | `disabled` | Denies every shell request. |
127
+ | `restricted` | Deterministic allowlist for unattended pipelines. |
128
+ | `readonly_project` | Read-oriented `argv` commands inside one project root. |
129
+
130
+ `shell.run` accepts exactly one of `cmd` or `argv`. `cmd` executes with
131
+ `shell=True`; `argv` executes with `shell=False`. Restricted policies should
132
+ prefer `argv` mode. Policy controls are guardrails, not a strong OS sandbox; use
133
+ containers, VMs, or other isolation for untrusted execution.
134
+
135
+ ## Skill Tools
136
+
137
+ Skill support is split into runtime visibility, optional host-owned matching, and
138
+ tool-based skill use. `modis-tools` provides the use layer: a registry, a prompt
139
+ generator, and `skills.*` tools for progressive loading.
140
+
141
+ `skill_home` is required in every mode because all skill files must resolve from
142
+ a trusted root.
143
+
144
+ ```python
145
+ from modis_tools import ToolRegistry
146
+ from modis_tools.builtins import skills_group
147
+ from modis_tools.skills import SkillRegistry, build_skill_system_prompt
148
+
149
+ skill_home = "./skills"
150
+ registry = ToolRegistry()
151
+ registry.include(skills_group(skill_home=skill_home, mode="hybrid"))
152
+
153
+ skill_registry = SkillRegistry.from_home(skill_home)
154
+ system_prompt = build_skill_system_prompt(skill_registry, mode="hybrid")
155
+ ```
156
+
157
+ The skills group exposes:
158
+
159
+ - `skills.list()`
160
+ - `skills.read(name)`
161
+ - `skills.list_resources(name)`
162
+ - `skills.read_resource(name, path)`
163
+ - `skills.system_prompt(active_skill=None)`
164
+
165
+ Execution modes:
166
+
167
+ | Mode | Behavior |
168
+ | --- | --- |
169
+ | `tools_only` | Models use only `skills.*` tools to read instructions and resources. |
170
+ | `shell_only` | Prompt tells the model where `skill_home` is; host shell/file policy must handle access. |
171
+ | `hybrid` | Models use `skills.*` for reads and policy-gated shell for commands only when needed. |
172
+
173
+ Skill matching is intentionally optional and host-owned. The package defines
174
+ `PromptSkillEvaluator` as a protocol, but does not decide when a skill should be
175
+ used.
176
+
177
+ ## Web Tools
178
+
179
+ The web group exposes:
180
+
181
+ - `web.search(query, num_results=10, search_type="all", relevance_threshold=0.5, included_sources=None, excluded_sources=None, country_code=None, response_length=None, category=None, start_date=None, end_date=None, max_price=None, fast_mode=False, url_only=False, source_biases=None, instructions=None)`
182
+ - `web.open(id=None, cursor=-1, loc=-1, num_lines=-1)`
183
+ - `web.find(pattern, cursor=-1, context_lines=3)`
184
+
185
+ Valyu is the default provider when no provider is supplied. Search uses Valyu
186
+ search, and direct URL opens use Valyu contents extraction.
187
+ Opened pages and find results include source ids, URLs, and one-based line
188
+ ranges so responses can be cited or re-opened later in the same tool session.
189
+
190
+ ```python
191
+ from modis_tools import ToolRegistry
192
+ from modis_tools.builtins import web_group
193
+
194
+ registry = ToolRegistry()
195
+ registry.include(web_group(api_key="..."))
196
+ ```
197
+
198
+ Search options map to Valyu search controls. For example:
199
+
200
+ ```python
201
+ result = registry.execute_tool_call({
202
+ "id": "search_1",
203
+ "type": "function",
204
+ "function": {
205
+ "name": "web.search",
206
+ "arguments": """
207
+ {
208
+ "query": "recent multimodal retrieval papers",
209
+ "num_results": 5,
210
+ "relevance_threshold": 0.45,
211
+ "included_sources": ["valyu/valyu-arxiv"],
212
+ "response_length": "medium",
213
+ "start_date": "2026-04-29",
214
+ "end_date": "2026-05-06",
215
+ "country_code": "US"
216
+ }
217
+ """
218
+ }
219
+ })
220
+ ```
221
+
222
+ Default search values are copied from the installed Valyu SDK where exposed:
223
+
224
+ | Option | Default | Notes |
225
+ | --- | --- | --- |
226
+ | `num_results` | `10` | Sent to Valyu as `max_num_results`. |
227
+ | `search_type` | `"all"` | Valyu scopes are `web`, `proprietary`, `all`, and `news`. |
228
+ | `relevance_threshold` | `0.5` | Set to `None` to omit the threshold parameter. |
229
+ | `included_sources` | `None` | Valyu source ids or arbitrary URLs. |
230
+ | `excluded_sources` | `None` | Valyu source ids or arbitrary URLs. |
231
+ | `country_code` | `None` | Optional ISO country code. |
232
+ | `response_length` | `None` | Supports `short`, `medium`, `large`, `max`, integer, or numeric string. |
233
+ | `category` | `None` | Provider-specific category. |
234
+ | `start_date` / `end_date` | `None` | Optional `YYYY-MM-DD` bounds. |
235
+ | `max_price` | `None` | Provider cost limit if used. |
236
+ | `fast_mode` | `False` | Sent explicitly. |
237
+ | `url_only` | `False` | Sent explicitly. |
238
+ | `source_biases` | `None` | Optional per-source integer biases. |
239
+ | `instructions` | `None` | Optional provider instructions. |
240
+
241
+ `is_tool_call` is not exposed to the model; the Valyu provider sends it as
242
+ `True`.
243
+
244
+ Valyu provider metadata that is not part of the normalized result shape, such as
245
+ scores or ranking fields when returned by the SDK, is preserved in each result's
246
+ `metadata` object.
247
+
248
+ Custom providers implement `SearchProvider`:
249
+
250
+ ```python
251
+ from modis_tools.providers.web import Page, SearchResult
252
+
253
+ class MyProvider:
254
+ def search(self, query: str, *, num_results: int = 10, **kwargs: object) -> list[SearchResult]:
255
+ return [SearchResult(title="Example", url="https://example.test", content="Page text")]
256
+
257
+ def fetch(self, url: str) -> Page:
258
+ return Page(title="Fetched", url=url, markdown="Fetched markdown")
259
+ ```
260
+
261
+ `web.open` can open prior search results by index/result id/URL, or an arbitrary
262
+ direct URL. Browser-backed fetching is still kept behind the optional `browser`
263
+ extra for future extension.
264
+
265
+ ## Live Web Tests
266
+
267
+ Live web tests are skipped unless `VALYU_API_KEY` is set and the `web` extra is
268
+ installed:
269
+
270
+ ```bash
271
+ python -m pip install -e ".[dev,web]"
272
+ VALYU_API_KEY=... pytest -m live
273
+ ```
274
+
275
+ The broader web quality eval is opt-in because it consumes live provider quota:
276
+
277
+ ```bash
278
+ VALYU_API_KEY=... MODIS_TOOLS_RUN_WEB_EVAL=1 pytest -m "live and eval" -vv
279
+ ```
280
+
281
+ See `docs/WEB_EVAL.md` for the current query set and comparison checklist.
@@ -0,0 +1,262 @@
1
+ # MoDIS Python Tools
2
+
3
+ `modis-py-tools` provides MoDIS-compatible function tool definitions, tool
4
+ groups, and tool-call execution helpers for Python applications.
5
+
6
+ The distribution name is currently `modis-py-tools`; the import package is
7
+ `modis_tools`.
8
+
9
+ ## Install
10
+
11
+ ```bash
12
+ python -m pip install modis-py-tools
13
+ ```
14
+
15
+ Optional web provider dependency:
16
+
17
+ ```bash
18
+ python -m pip install "modis-py-tools[web]"
19
+ ```
20
+
21
+ Development:
22
+
23
+ ```bash
24
+ python -m pip install -e ".[dev,web]"
25
+ .venv/bin/python -m pytest
26
+ .venv/bin/python -m ruff check .
27
+ .venv/bin/python -m ruff format --check .
28
+ .venv/bin/python -m mypy src
29
+ .venv/bin/python -m build
30
+ ```
31
+
32
+ ## Function Conversion
33
+
34
+ ```python
35
+ from modis_tools import function_to_tool
36
+
37
+ def lookup_order(order_id: str, include_history: bool = False) -> dict:
38
+ """Look up an order.
39
+
40
+ Args:
41
+ order_id: Order identifier.
42
+ include_history: Whether to include status history.
43
+ """
44
+ return {"order_id": order_id, "status": "processing"}
45
+
46
+ tool = function_to_tool(lookup_order, name="orders.lookup")
47
+ tool_definition = tool.to_wire()
48
+ ```
49
+
50
+ ## Registry Execution
51
+
52
+ ```python
53
+ from modis_tools import ToolRegistry
54
+ from modis_tools.builtins import python_group, shell_group
55
+
56
+ registry = ToolRegistry()
57
+ registry.include(shell_group())
58
+ registry.include(python_group())
59
+
60
+ tool_definitions = registry.definitions()
61
+ results = registry.execute_tool_calls(model_tool_calls)
62
+ messages = [result.to_chat_message() for result in results]
63
+ ```
64
+
65
+ `execute_tool_call()` and `execute_tool_calls()` return failed `ToolResult`
66
+ objects by default for unknown tools, invalid arguments, and tool exceptions.
67
+ Pass `raise_on_error=True` when the host application should handle exceptions.
68
+
69
+ For a fuller host integration guide, including unattended pipeline setup and
70
+ future image generation extension notes, see `docs/INTEGRATION.md`.
71
+
72
+ ## Built-In Tools
73
+
74
+ ```python
75
+ from modis_tools.builtins import python_group, shell_group, skills_group, web_group
76
+
77
+ shell_tools = shell_group()
78
+ python_tools = python_group()
79
+ skill_tools = skills_group(skill_home="./skills")
80
+ web_tools = web_group(api_key="...")
81
+ ```
82
+
83
+ `shell.run` captures `stdout`, `stderr`, exit code, duration, timeout state,
84
+ working directory, policy decision metadata, and truncation metadata.
85
+ `python.run` executes Python source in a subprocess using the current
86
+ interpreter by default.
87
+
88
+ Shell and Python tools execute local code. Only expose them in trusted contexts
89
+ where the caller owns policy, sandboxing, and approval decisions.
90
+
91
+ Shell tools support host-owned policies. Policies are bound by the application
92
+ when registering the group and are not exposed as model tool-call parameters.
93
+
94
+ ```python
95
+ from modis_tools import ToolRegistry
96
+ from modis_tools.builtins import ShellPolicy, shell_group
97
+
98
+ registry = ToolRegistry()
99
+ registry.include(shell_group(policy=ShellPolicy.readonly_project("./")))
100
+ ```
101
+
102
+ Built-in shell policy profiles:
103
+
104
+ | Profile | Purpose |
105
+ | --- | --- |
106
+ | `trusted_local` | Backward-compatible default for trusted local use. |
107
+ | `disabled` | Denies every shell request. |
108
+ | `restricted` | Deterministic allowlist for unattended pipelines. |
109
+ | `readonly_project` | Read-oriented `argv` commands inside one project root. |
110
+
111
+ `shell.run` accepts exactly one of `cmd` or `argv`. `cmd` executes with
112
+ `shell=True`; `argv` executes with `shell=False`. Restricted policies should
113
+ prefer `argv` mode. Policy controls are guardrails, not a strong OS sandbox; use
114
+ containers, VMs, or other isolation for untrusted execution.
115
+
116
+ ## Skill Tools
117
+
118
+ Skill support is split into runtime visibility, optional host-owned matching, and
119
+ tool-based skill use. `modis-tools` provides the use layer: a registry, a prompt
120
+ generator, and `skills.*` tools for progressive loading.
121
+
122
+ `skill_home` is required in every mode because all skill files must resolve from
123
+ a trusted root.
124
+
125
+ ```python
126
+ from modis_tools import ToolRegistry
127
+ from modis_tools.builtins import skills_group
128
+ from modis_tools.skills import SkillRegistry, build_skill_system_prompt
129
+
130
+ skill_home = "./skills"
131
+ registry = ToolRegistry()
132
+ registry.include(skills_group(skill_home=skill_home, mode="hybrid"))
133
+
134
+ skill_registry = SkillRegistry.from_home(skill_home)
135
+ system_prompt = build_skill_system_prompt(skill_registry, mode="hybrid")
136
+ ```
137
+
138
+ The skills group exposes:
139
+
140
+ - `skills.list()`
141
+ - `skills.read(name)`
142
+ - `skills.list_resources(name)`
143
+ - `skills.read_resource(name, path)`
144
+ - `skills.system_prompt(active_skill=None)`
145
+
146
+ Execution modes:
147
+
148
+ | Mode | Behavior |
149
+ | --- | --- |
150
+ | `tools_only` | Models use only `skills.*` tools to read instructions and resources. |
151
+ | `shell_only` | Prompt tells the model where `skill_home` is; host shell/file policy must handle access. |
152
+ | `hybrid` | Models use `skills.*` for reads and policy-gated shell for commands only when needed. |
153
+
154
+ Skill matching is intentionally optional and host-owned. The package defines
155
+ `PromptSkillEvaluator` as a protocol, but does not decide when a skill should be
156
+ used.
157
+
158
+ ## Web Tools
159
+
160
+ The web group exposes:
161
+
162
+ - `web.search(query, num_results=10, search_type="all", relevance_threshold=0.5, included_sources=None, excluded_sources=None, country_code=None, response_length=None, category=None, start_date=None, end_date=None, max_price=None, fast_mode=False, url_only=False, source_biases=None, instructions=None)`
163
+ - `web.open(id=None, cursor=-1, loc=-1, num_lines=-1)`
164
+ - `web.find(pattern, cursor=-1, context_lines=3)`
165
+
166
+ Valyu is the default provider when no provider is supplied. Search uses Valyu
167
+ search, and direct URL opens use Valyu contents extraction.
168
+ Opened pages and find results include source ids, URLs, and one-based line
169
+ ranges so responses can be cited or re-opened later in the same tool session.
170
+
171
+ ```python
172
+ from modis_tools import ToolRegistry
173
+ from modis_tools.builtins import web_group
174
+
175
+ registry = ToolRegistry()
176
+ registry.include(web_group(api_key="..."))
177
+ ```
178
+
179
+ Search options map to Valyu search controls. For example:
180
+
181
+ ```python
182
+ result = registry.execute_tool_call({
183
+ "id": "search_1",
184
+ "type": "function",
185
+ "function": {
186
+ "name": "web.search",
187
+ "arguments": """
188
+ {
189
+ "query": "recent multimodal retrieval papers",
190
+ "num_results": 5,
191
+ "relevance_threshold": 0.45,
192
+ "included_sources": ["valyu/valyu-arxiv"],
193
+ "response_length": "medium",
194
+ "start_date": "2026-04-29",
195
+ "end_date": "2026-05-06",
196
+ "country_code": "US"
197
+ }
198
+ """
199
+ }
200
+ })
201
+ ```
202
+
203
+ Default search values are copied from the installed Valyu SDK where exposed:
204
+
205
+ | Option | Default | Notes |
206
+ | --- | --- | --- |
207
+ | `num_results` | `10` | Sent to Valyu as `max_num_results`. |
208
+ | `search_type` | `"all"` | Valyu scopes are `web`, `proprietary`, `all`, and `news`. |
209
+ | `relevance_threshold` | `0.5` | Set to `None` to omit the threshold parameter. |
210
+ | `included_sources` | `None` | Valyu source ids or arbitrary URLs. |
211
+ | `excluded_sources` | `None` | Valyu source ids or arbitrary URLs. |
212
+ | `country_code` | `None` | Optional ISO country code. |
213
+ | `response_length` | `None` | Supports `short`, `medium`, `large`, `max`, integer, or numeric string. |
214
+ | `category` | `None` | Provider-specific category. |
215
+ | `start_date` / `end_date` | `None` | Optional `YYYY-MM-DD` bounds. |
216
+ | `max_price` | `None` | Provider cost limit if used. |
217
+ | `fast_mode` | `False` | Sent explicitly. |
218
+ | `url_only` | `False` | Sent explicitly. |
219
+ | `source_biases` | `None` | Optional per-source integer biases. |
220
+ | `instructions` | `None` | Optional provider instructions. |
221
+
222
+ `is_tool_call` is not exposed to the model; the Valyu provider sends it as
223
+ `True`.
224
+
225
+ Valyu provider metadata that is not part of the normalized result shape, such as
226
+ scores or ranking fields when returned by the SDK, is preserved in each result's
227
+ `metadata` object.
228
+
229
+ Custom providers implement `SearchProvider`:
230
+
231
+ ```python
232
+ from modis_tools.providers.web import Page, SearchResult
233
+
234
+ class MyProvider:
235
+ def search(self, query: str, *, num_results: int = 10, **kwargs: object) -> list[SearchResult]:
236
+ return [SearchResult(title="Example", url="https://example.test", content="Page text")]
237
+
238
+ def fetch(self, url: str) -> Page:
239
+ return Page(title="Fetched", url=url, markdown="Fetched markdown")
240
+ ```
241
+
242
+ `web.open` can open prior search results by index/result id/URL, or an arbitrary
243
+ direct URL. Browser-backed fetching is still kept behind the optional `browser`
244
+ extra for future extension.
245
+
246
+ ## Live Web Tests
247
+
248
+ Live web tests are skipped unless `VALYU_API_KEY` is set and the `web` extra is
249
+ installed:
250
+
251
+ ```bash
252
+ python -m pip install -e ".[dev,web]"
253
+ VALYU_API_KEY=... pytest -m live
254
+ ```
255
+
256
+ The broader web quality eval is opt-in because it consumes live provider quota:
257
+
258
+ ```bash
259
+ VALYU_API_KEY=... MODIS_TOOLS_RUN_WEB_EVAL=1 pytest -m "live and eval" -vv
260
+ ```
261
+
262
+ See `docs/WEB_EVAL.md` for the current query set and comparison checklist.
@@ -0,0 +1,57 @@
1
+ [build-system]
2
+ requires = ["setuptools>=67", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "modis-py-tools"
7
+ version = "0.1.0"
8
+ description = "Common MoDIS-compatible Python tools and tool-call execution helpers"
9
+ readme = "README.md"
10
+ requires-python = ">=3.11"
11
+ dependencies = [
12
+ "pydantic>=2.7.0"
13
+ ]
14
+
15
+ [project.optional-dependencies]
16
+ web = [
17
+ "valyu>=2.0.0"
18
+ ]
19
+ browser = [
20
+ "markdownify>=0.12.0",
21
+ "playwright>=1.45.0",
22
+ "readability-lxml>=0.8.1"
23
+ ]
24
+ dev = [
25
+ "build>=1.2.0",
26
+ "mypy>=1.10.0",
27
+ "pytest>=8.0.0",
28
+ "ruff>=0.8.0"
29
+ ]
30
+
31
+ [tool.setuptools.packages.find]
32
+ where = ["src"]
33
+ include = ["modis_tools*"]
34
+
35
+ [tool.setuptools.package-data]
36
+ modis_tools = ["py.typed"]
37
+
38
+ [tool.ruff]
39
+ line-length = 120
40
+ target-version = "py311"
41
+
42
+ [tool.ruff.lint]
43
+ select = ["E", "F", "I"]
44
+
45
+ [tool.mypy]
46
+ python_version = "3.11"
47
+ check_untyped_defs = true
48
+ ignore_missing_imports = true
49
+ no_implicit_optional = true
50
+ warn_unused_configs = true
51
+
52
+ [tool.pytest.ini_options]
53
+ testpaths = ["tests"]
54
+ markers = [
55
+ "live: tests that call live external providers",
56
+ "eval: opt-in quality evaluation tests that may be slower or provider-costly"
57
+ ]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+