@allansantos-dev/smart-tool 0.9.23 → 0.9.25
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.
- package/CHANGELOG.md +19 -0
- package/README.md +1 -1
- package/hook_decision.py +3 -3
- package/package.json +1 -1
- package/smart_tool_daemon.py +19 -3
- package/tool_redirect.py +9 -0
- package/version.py +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.9.25 - beta
|
|
4
|
+
|
|
5
|
+
- A redirected search made while the first index of a folder is still being built no longer waits in the folder's queue
|
|
6
|
+
behind the build (22 s measured, past the hook's 15 s, so the agent got the native result with no notice): it is
|
|
7
|
+
answered at once by the keyword search of the disk, with the redirect notice and the index-loading warning.
|
|
8
|
+
- The first search of a cold folder also gets the index-loading sentence in the notice (it was read from a job field that
|
|
9
|
+
the answer text does not carry; it is now read from the answer's own warning).
|
|
10
|
+
|
|
11
|
+
## 0.9.24 - beta
|
|
12
|
+
|
|
13
|
+
- A redirected search now tells the agent what happened: the answer opens with a line saying the search was redirected to
|
|
14
|
+
`smart_search` (index, related code, dependency map), that the index of the project is still loading when the answer is
|
|
15
|
+
a keyword search of the disk (the next searches will have it ready), and to keep using `smart_search`. Before, the
|
|
16
|
+
answer carried no word of the redirect.
|
|
17
|
+
- The deny text of a search that cannot be redirected no longer says that reading or searching inside one known file is
|
|
18
|
+
never blocked: no message the agent receives offers a way around the redirect (file by file, narrower scope).
|
|
19
|
+
`NoWayAroundTheRedirectTest` fails if any of those texts (deny, advice, redirect notice, cold-index and stale-index
|
|
20
|
+
warnings) suggests one.
|
|
21
|
+
|
|
3
22
|
## 0.9.23 - beta
|
|
4
23
|
|
|
5
24
|
- The hook no longer blocks. A content search over a project folder (the Grep tool on a folder, `grep -r`, `rg`,
|
package/README.md
CHANGED
|
@@ -15,7 +15,7 @@ registered as the `playwright` server where this machine lets a browser be drive
|
|
|
15
15
|
An optional hook routes the agent's native Grep/Glob/Read/Bash/WebSearch/WebFetch calls to these tools when they
|
|
16
16
|
are cheaper, or just tells the agent what Smart Tool would do.
|
|
17
17
|
|
|
18
|
-
**Status:** 0.9.
|
|
18
|
+
**Status:** 0.9.25 beta. Windows only. What changed in each version: [CHANGELOG.md](CHANGELOG.md).
|
|
19
19
|
|
|
20
20
|
## How it works
|
|
21
21
|
|
package/hook_decision.py
CHANGED
|
@@ -138,14 +138,14 @@ def _load_hint(client, tool):
|
|
|
138
138
|
|
|
139
139
|
def redirect_message(client, tool_name, target, reason, cwd):
|
|
140
140
|
"""Deny text for a broad raw search: the exact tool and arguments to call (project_root from the folder the search
|
|
141
|
-
reads), and that rewriting the same search in Bash, python, node or PowerShell is the bypass the rule stops.
|
|
141
|
+
reads), and that rewriting the same search in Bash, python, node or PowerShell is the bypass the rule stops. It
|
|
142
|
+
never suggests a way around the rule (narrower or per-file searches): the only way offered is smart_search."""
|
|
142
143
|
root = _search_root(target, cwd).replace("\\", "/")
|
|
143
144
|
return (f"Blocked by Smart Tool, a routing rule set by the user, not a failure ({tool_name}: {clean_reason(reason)}). "
|
|
144
145
|
f'Run this search with {_tool_name(client, "smart_search")}: project_root="{root}", query_identifiers = what '
|
|
145
146
|
f"you are looking for in identifier terms (plus query_comments when the project has two languages)."
|
|
146
147
|
f'{_load_hint(client, "smart_search")} Do not repeat the same search through Bash, python, node or '
|
|
147
|
-
f"PowerShell: that bypasses the rule.
|
|
148
|
-
f"blocked.")
|
|
148
|
+
f"PowerShell: that bypasses the rule.")
|
|
149
149
|
|
|
150
150
|
|
|
151
151
|
def web_message(client, tool_name, url, why):
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@allansantos-dev/smart-tool",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.25",
|
|
4
4
|
"description": "Local MCP server that gives coding agents (Claude Code, Codex) cheaper, sharper tools than their built-in search. Windows.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "Allan Santos",
|
package/smart_tool_daemon.py
CHANGED
|
@@ -3654,12 +3654,27 @@ def _decide_within_budget(payload, client):
|
|
|
3654
3654
|
return output
|
|
3655
3655
|
|
|
3656
3656
|
|
|
3657
|
+
def _cold_index_building(root):
|
|
3658
|
+
"""Whether the folder has no index yet and the job that builds it is queued or running. A search job of that folder
|
|
3659
|
+
would wait behind it in the per-folder queue (21.9 s measured, past the hook's wait), so a redirected search is
|
|
3660
|
+
answered at once by `_perform_smart_search`'s cold path: keyword matches read from disk, with the notice."""
|
|
3661
|
+
if indexer.info(root).get("chunks") or not _cold_index(root, config.load_config(), _gateway_problem()):
|
|
3662
|
+
return False
|
|
3663
|
+
project_id = project_identity.project_id(root)
|
|
3664
|
+
with _JOBS_LOCK:
|
|
3665
|
+
return any(job.get("kind") == "project_index" and job.get("status") == "pending"
|
|
3666
|
+
and job.get("project_id") == project_id for job in _jobs.values())
|
|
3667
|
+
|
|
3668
|
+
|
|
3657
3669
|
def _redirected_search(arguments):
|
|
3658
3670
|
"""smart_search text for a redirected native search, waiting up to SMART_SEARCH_SYNC_WAIT_S; raises when the search
|
|
3659
|
-
is rejected, fails or is still running then. The hook's single_language_reason only passes the language check
|
|
3660
|
-
|
|
3671
|
+
is rejected, fails or is still running then. The hook's single_language_reason only passes the language check, it is
|
|
3672
|
+
not repeated as a warning. The answer opens with `tool_redirect.search_notice`: the agent is told its search was
|
|
3673
|
+
redirected, whether the index is still loading, and to keep using smart_search."""
|
|
3661
3674
|
checked = _smart_search_arguments(arguments)
|
|
3662
3675
|
checked.pop("single_language_reason", None)
|
|
3676
|
+
if _cold_index_building(checked["project_root"]):
|
|
3677
|
+
return f"{tool_redirect.search_notice(True)}\n{_perform_smart_search(checked, '')}"
|
|
3663
3678
|
job_id, _future = _submit_project_job("smart_search", checked)
|
|
3664
3679
|
deadline = time.monotonic() + SMART_SEARCH_SYNC_WAIT_S
|
|
3665
3680
|
payload = _smart_search_job_payload(job_id)
|
|
@@ -3668,7 +3683,8 @@ def _redirected_search(arguments):
|
|
|
3668
3683
|
payload = _smart_search_job_payload(job_id)
|
|
3669
3684
|
if payload["status"] != "done":
|
|
3670
3685
|
raise RuntimeError(f"smart_search job {job_id} is {payload['status']}: {payload.get('error') or ''}"[:300])
|
|
3671
|
-
|
|
3686
|
+
answer = _agent_search_answer(payload)
|
|
3687
|
+
return f"{tool_redirect.search_notice('Indexing in progress' in answer.partition(chr(10) + 'code:')[0])}\n{answer}"
|
|
3672
3688
|
|
|
3673
3689
|
|
|
3674
3690
|
def _redirected_text(handler):
|
package/tool_redirect.py
CHANGED
|
@@ -60,6 +60,15 @@ class Jobs:
|
|
|
60
60
|
self._futures.pop(key, None)
|
|
61
61
|
|
|
62
62
|
|
|
63
|
+
def search_notice(indexing):
|
|
64
|
+
"""First line of a redirected search's answer: the agent made a native search, Smart Tool answered it. While the
|
|
65
|
+
index loads the answer is a keyword search of the disk; either way the agent is told to keep using smart_search."""
|
|
66
|
+
state = ("The index of this project is still loading, so this answer is a keyword search of the files on disk; "
|
|
67
|
+
"the next searches will have the index ready. " if indexing else "")
|
|
68
|
+
return ("Smart Tool: your search was redirected to smart_search, which searches the project index and returns "
|
|
69
|
+
f"related code with its dependency map. {state}Keep using smart_search for searches of the project.")
|
|
70
|
+
|
|
71
|
+
|
|
63
72
|
def output_for(tool_name, response, text):
|
|
64
73
|
"""`updatedToolOutput` for a native tool: its own response with the Smart Tool text in the field the model reads,
|
|
65
74
|
or None when the response has an unknown shape."""
|
package/version.py
CHANGED