npcsh 1.1.13__tar.gz → 1.1.14__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.
- {npcsh-1.1.13 → npcsh-1.1.14}/PKG-INFO +1 -1
- {npcsh-1.1.13 → npcsh-1.1.14}/npcsh/_state.py +3 -3
- {npcsh-1.1.13 → npcsh-1.1.14}/npcsh.egg-info/PKG-INFO +1 -1
- {npcsh-1.1.13 → npcsh-1.1.14}/npcsh.egg-info/SOURCES.txt +2 -1
- {npcsh-1.1.13 → npcsh-1.1.14}/setup.py +1 -1
- npcsh-1.1.14/tests/test_tool_routing.py +81 -0
- {npcsh-1.1.13 → npcsh-1.1.14}/LICENSE +0 -0
- {npcsh-1.1.13 → npcsh-1.1.14}/README.md +0 -0
- {npcsh-1.1.13 → npcsh-1.1.14}/npcsh/__init__.py +0 -0
- {npcsh-1.1.13 → npcsh-1.1.14}/npcsh/alicanto.py +0 -0
- {npcsh-1.1.13 → npcsh-1.1.14}/npcsh/build.py +0 -0
- {npcsh-1.1.13 → npcsh-1.1.14}/npcsh/completion.py +0 -0
- {npcsh-1.1.13 → npcsh-1.1.14}/npcsh/config.py +0 -0
- {npcsh-1.1.13 → npcsh-1.1.14}/npcsh/corca.py +0 -0
- {npcsh-1.1.13 → npcsh-1.1.14}/npcsh/execution.py +0 -0
- {npcsh-1.1.13 → npcsh-1.1.14}/npcsh/guac.py +0 -0
- {npcsh-1.1.13 → npcsh-1.1.14}/npcsh/mcp_helpers.py +0 -0
- {npcsh-1.1.13 → npcsh-1.1.14}/npcsh/mcp_server.py +0 -0
- {npcsh-1.1.13 → npcsh-1.1.14}/npcsh/npc.py +0 -0
- {npcsh-1.1.13 → npcsh-1.1.14}/npcsh/npc_team/alicanto.npc +0 -0
- {npcsh-1.1.13 → npcsh-1.1.14}/npcsh/npc_team/alicanto.png +0 -0
- {npcsh-1.1.13 → npcsh-1.1.14}/npcsh/npc_team/corca.npc +0 -0
- {npcsh-1.1.13 → npcsh-1.1.14}/npcsh/npc_team/corca.png +0 -0
- {npcsh-1.1.13 → npcsh-1.1.14}/npcsh/npc_team/corca_example.png +0 -0
- {npcsh-1.1.13 → npcsh-1.1.14}/npcsh/npc_team/foreman.npc +0 -0
- {npcsh-1.1.13 → npcsh-1.1.14}/npcsh/npc_team/frederic.npc +0 -0
- {npcsh-1.1.13 → npcsh-1.1.14}/npcsh/npc_team/frederic4.png +0 -0
- {npcsh-1.1.13 → npcsh-1.1.14}/npcsh/npc_team/guac.png +0 -0
- {npcsh-1.1.13 → npcsh-1.1.14}/npcsh/npc_team/jinxs/code/python.jinx +0 -0
- {npcsh-1.1.13 → npcsh-1.1.14}/npcsh/npc_team/jinxs/code/sh.jinx +0 -0
- {npcsh-1.1.13 → npcsh-1.1.14}/npcsh/npc_team/jinxs/code/sql.jinx +0 -0
- {npcsh-1.1.13 → npcsh-1.1.14}/npcsh/npc_team/jinxs/modes/alicanto.jinx +0 -0
- {npcsh-1.1.13 → npcsh-1.1.14}/npcsh/npc_team/jinxs/modes/corca.jinx +0 -0
- {npcsh-1.1.13 → npcsh-1.1.14}/npcsh/npc_team/jinxs/modes/guac.jinx +0 -0
- {npcsh-1.1.13 → npcsh-1.1.14}/npcsh/npc_team/jinxs/modes/plonk.jinx +0 -0
- {npcsh-1.1.13 → npcsh-1.1.14}/npcsh/npc_team/jinxs/modes/pti.jinx +0 -0
- {npcsh-1.1.13 → npcsh-1.1.14}/npcsh/npc_team/jinxs/modes/spool.jinx +0 -0
- {npcsh-1.1.13 → npcsh-1.1.14}/npcsh/npc_team/jinxs/modes/wander.jinx +0 -0
- {npcsh-1.1.13 → npcsh-1.1.14}/npcsh/npc_team/jinxs/modes/yap.jinx +0 -0
- {npcsh-1.1.13 → npcsh-1.1.14}/npcsh/npc_team/jinxs/npc_studio/npc-studio.jinx +0 -0
- {npcsh-1.1.13 → npcsh-1.1.14}/npcsh/npc_team/jinxs/utils/agent.jinx +0 -0
- {npcsh-1.1.13 → npcsh-1.1.14}/npcsh/npc_team/jinxs/utils/chat.jinx +0 -0
- {npcsh-1.1.13 → npcsh-1.1.14}/npcsh/npc_team/jinxs/utils/cmd.jinx +0 -0
- {npcsh-1.1.13 → npcsh-1.1.14}/npcsh/npc_team/jinxs/utils/compress.jinx +0 -0
- {npcsh-1.1.13 → npcsh-1.1.14}/npcsh/npc_team/jinxs/utils/core/build.jinx +0 -0
- {npcsh-1.1.13 → npcsh-1.1.14}/npcsh/npc_team/jinxs/utils/core/compile.jinx +0 -0
- {npcsh-1.1.13 → npcsh-1.1.14}/npcsh/npc_team/jinxs/utils/core/help.jinx +0 -0
- {npcsh-1.1.13 → npcsh-1.1.14}/npcsh/npc_team/jinxs/utils/core/init.jinx +0 -0
- {npcsh-1.1.13 → npcsh-1.1.14}/npcsh/npc_team/jinxs/utils/core/jinxs.jinx +0 -0
- {npcsh-1.1.13 → npcsh-1.1.14}/npcsh/npc_team/jinxs/utils/core/set.jinx +0 -0
- {npcsh-1.1.13 → npcsh-1.1.14}/npcsh/npc_team/jinxs/utils/edit_file.jinx +0 -0
- {npcsh-1.1.13 → npcsh-1.1.14}/npcsh/npc_team/jinxs/utils/load_file.jinx +0 -0
- {npcsh-1.1.13 → npcsh-1.1.14}/npcsh/npc_team/jinxs/utils/ots.jinx +0 -0
- {npcsh-1.1.13 → npcsh-1.1.14}/npcsh/npc_team/jinxs/utils/roll.jinx +0 -0
- {npcsh-1.1.13 → npcsh-1.1.14}/npcsh/npc_team/jinxs/utils/sample.jinx +0 -0
- {npcsh-1.1.13 → npcsh-1.1.14}/npcsh/npc_team/jinxs/utils/search.jinx +0 -0
- {npcsh-1.1.13 → npcsh-1.1.14}/npcsh/npc_team/jinxs/utils/serve.jinx +0 -0
- {npcsh-1.1.13 → npcsh-1.1.14}/npcsh/npc_team/jinxs/utils/sleep.jinx +0 -0
- {npcsh-1.1.13 → npcsh-1.1.14}/npcsh/npc_team/jinxs/utils/trigger.jinx +0 -0
- {npcsh-1.1.13 → npcsh-1.1.14}/npcsh/npc_team/jinxs/utils/usage.jinx +0 -0
- {npcsh-1.1.13 → npcsh-1.1.14}/npcsh/npc_team/jinxs/utils/vixynt.jinx +0 -0
- {npcsh-1.1.13 → npcsh-1.1.14}/npcsh/npc_team/kadiefa.npc +0 -0
- {npcsh-1.1.13 → npcsh-1.1.14}/npcsh/npc_team/kadiefa.png +0 -0
- {npcsh-1.1.13 → npcsh-1.1.14}/npcsh/npc_team/npcsh.ctx +0 -0
- {npcsh-1.1.13 → npcsh-1.1.14}/npcsh/npc_team/npcsh_sibiji.png +0 -0
- {npcsh-1.1.13 → npcsh-1.1.14}/npcsh/npc_team/plonk.npc +0 -0
- {npcsh-1.1.13 → npcsh-1.1.14}/npcsh/npc_team/plonk.png +0 -0
- {npcsh-1.1.13 → npcsh-1.1.14}/npcsh/npc_team/plonkjr.npc +0 -0
- {npcsh-1.1.13 → npcsh-1.1.14}/npcsh/npc_team/plonkjr.png +0 -0
- {npcsh-1.1.13 → npcsh-1.1.14}/npcsh/npc_team/sibiji.npc +0 -0
- {npcsh-1.1.13 → npcsh-1.1.14}/npcsh/npc_team/sibiji.png +0 -0
- {npcsh-1.1.13 → npcsh-1.1.14}/npcsh/npc_team/spool.png +0 -0
- {npcsh-1.1.13 → npcsh-1.1.14}/npcsh/npc_team/yap.png +0 -0
- {npcsh-1.1.13 → npcsh-1.1.14}/npcsh/npcsh.py +0 -0
- {npcsh-1.1.13 → npcsh-1.1.14}/npcsh/parsing.py +0 -0
- {npcsh-1.1.13 → npcsh-1.1.14}/npcsh/plonk.py +0 -0
- {npcsh-1.1.13 → npcsh-1.1.14}/npcsh/pti.py +0 -0
- {npcsh-1.1.13 → npcsh-1.1.14}/npcsh/routes.py +0 -0
- {npcsh-1.1.13 → npcsh-1.1.14}/npcsh/spool.py +0 -0
- {npcsh-1.1.13 → npcsh-1.1.14}/npcsh/ui.py +0 -0
- {npcsh-1.1.13 → npcsh-1.1.14}/npcsh/wander.py +0 -0
- {npcsh-1.1.13 → npcsh-1.1.14}/npcsh/yap.py +0 -0
- {npcsh-1.1.13 → npcsh-1.1.14}/npcsh.egg-info/dependency_links.txt +0 -0
- {npcsh-1.1.13 → npcsh-1.1.14}/npcsh.egg-info/entry_points.txt +0 -0
- {npcsh-1.1.13 → npcsh-1.1.14}/npcsh.egg-info/requires.txt +0 -0
- {npcsh-1.1.13 → npcsh-1.1.14}/npcsh.egg-info/top_level.txt +0 -0
- {npcsh-1.1.13 → npcsh-1.1.14}/setup.cfg +0 -0
|
@@ -2524,8 +2524,7 @@ def process_pipeline_command(
|
|
|
2524
2524
|
# Only add tool_choice for providers that support it (not gemini)
|
|
2525
2525
|
is_gemini = (exec_provider and "gemini" in exec_provider.lower()) or \
|
|
2526
2526
|
(exec_model and "gemini" in exec_model.lower())
|
|
2527
|
-
|
|
2528
|
-
llm_kwargs["tool_choice"] = {"type": "auto"}
|
|
2527
|
+
llm_kwargs["tool_choice"] = 'auto'
|
|
2529
2528
|
|
|
2530
2529
|
llm_result = get_llm_response(
|
|
2531
2530
|
full_llm_cmd,
|
|
@@ -2552,7 +2551,8 @@ def process_pipeline_command(
|
|
|
2552
2551
|
images=state.attachments,
|
|
2553
2552
|
stream=stream_final,
|
|
2554
2553
|
context=info,
|
|
2555
|
-
extra_globals=application_globals_for_jinx
|
|
2554
|
+
extra_globals=application_globals_for_jinx,
|
|
2555
|
+
tool_capable=tool_capable,
|
|
2556
2556
|
)
|
|
2557
2557
|
except KeyboardInterrupt:
|
|
2558
2558
|
print(colored("\nLLM processing interrupted by user.", "yellow"))
|
|
@@ -81,4 +81,5 @@ npcsh/npc_team/jinxs/utils/core/compile.jinx
|
|
|
81
81
|
npcsh/npc_team/jinxs/utils/core/help.jinx
|
|
82
82
|
npcsh/npc_team/jinxs/utils/core/init.jinx
|
|
83
83
|
npcsh/npc_team/jinxs/utils/core/jinxs.jinx
|
|
84
|
-
npcsh/npc_team/jinxs/utils/core/set.jinx
|
|
84
|
+
npcsh/npc_team/jinxs/utils/core/set.jinx
|
|
85
|
+
tests/test_tool_routing.py
|
|
@@ -78,7 +78,7 @@ extra_files = package_files("npcsh/npc_team/")
|
|
|
78
78
|
|
|
79
79
|
setup(
|
|
80
80
|
name="npcsh",
|
|
81
|
-
version="1.1.
|
|
81
|
+
version="1.1.14",
|
|
82
82
|
packages=find_packages(exclude=["tests*"]),
|
|
83
83
|
install_requires=base_requirements, # Only install base requirements by default
|
|
84
84
|
extras_require={
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
|
|
3
|
+
import npcsh._state as state_module
|
|
4
|
+
from npcsh._state import ShellState, process_pipeline_command
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@pytest.fixture(autouse=True)
|
|
8
|
+
def stub_available_models(monkeypatch):
|
|
9
|
+
monkeypatch.setattr(state_module, "get_locally_available_models", lambda path: {})
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def test_model_supports_tool_calls_uses_heuristics(monkeypatch):
|
|
13
|
+
# Force ollama inspection to be inconclusive so heuristics are used.
|
|
14
|
+
monkeypatch.setattr(state_module, "_ollama_supports_tools", lambda model: None)
|
|
15
|
+
assert not state_module.model_supports_tool_calls("gemma3:4b", "ollama")
|
|
16
|
+
assert state_module.model_supports_tool_calls("qwen3:0.6b", "ollama")
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def test_react_flow_used_for_non_tool_models(tmp_path, monkeypatch):
|
|
20
|
+
calls = {"check": 0, "llm": 0}
|
|
21
|
+
|
|
22
|
+
def fake_check_llm_command(*args, **kwargs):
|
|
23
|
+
calls["check"] += 1
|
|
24
|
+
return {"output": "react-path", "messages": kwargs.get("messages", [])}
|
|
25
|
+
|
|
26
|
+
monkeypatch.setattr(state_module, "model_supports_tool_calls", lambda m, p: False)
|
|
27
|
+
monkeypatch.setattr(state_module, "check_llm_command", fake_check_llm_command)
|
|
28
|
+
monkeypatch.setattr(state_module, "get_llm_response", lambda *a, **k: None)
|
|
29
|
+
|
|
30
|
+
shell_state = ShellState(current_path=str(tmp_path))
|
|
31
|
+
updated_state, output = process_pipeline_command(
|
|
32
|
+
"explain something", None, shell_state, stream_final=False, router=None
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
assert calls["check"] == 1
|
|
36
|
+
assert output == "react-path"
|
|
37
|
+
# user message should be appended
|
|
38
|
+
assert updated_state.messages and updated_state.messages[0]["role"] == "user"
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def test_tool_call_flow_for_tool_capable_models(tmp_path, monkeypatch):
|
|
42
|
+
calls = {"check": 0, "llm": 0}
|
|
43
|
+
|
|
44
|
+
def fake_get_llm_response(*args, **kwargs):
|
|
45
|
+
calls["llm"] += 1
|
|
46
|
+
msgs = kwargs.get("messages", [])
|
|
47
|
+
return {"response": "tool-route", "messages": msgs + [{"role": "assistant", "content": "tool-route"}]}
|
|
48
|
+
|
|
49
|
+
monkeypatch.setattr(state_module, "model_supports_tool_calls", lambda m, p: True)
|
|
50
|
+
monkeypatch.setattr(state_module, "get_llm_response", fake_get_llm_response)
|
|
51
|
+
monkeypatch.setattr(
|
|
52
|
+
state_module,
|
|
53
|
+
"collect_llm_tools",
|
|
54
|
+
lambda _state: (
|
|
55
|
+
[
|
|
56
|
+
{
|
|
57
|
+
"type": "function",
|
|
58
|
+
"function": {"name": "dummy", "description": "d", "parameters": {"type": "object", "properties": {}}},
|
|
59
|
+
}
|
|
60
|
+
],
|
|
61
|
+
{"dummy": lambda **kwargs: "ok"},
|
|
62
|
+
),
|
|
63
|
+
)
|
|
64
|
+
monkeypatch.setattr(
|
|
65
|
+
state_module,
|
|
66
|
+
"check_llm_command",
|
|
67
|
+
lambda *args, **kwargs: (
|
|
68
|
+
calls.__setitem__("check", calls["check"] + 1)
|
|
69
|
+
or {"output": "should-not-run", "messages": kwargs.get("messages", [])}
|
|
70
|
+
),
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
shell_state = ShellState(current_path=str(tmp_path))
|
|
74
|
+
updated_state, output = process_pipeline_command(
|
|
75
|
+
"explain something", None, shell_state, stream_final=False, router=None
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
assert calls["llm"] == 1
|
|
79
|
+
assert calls["check"] == 0
|
|
80
|
+
assert output == "tool-route"
|
|
81
|
+
assert updated_state.messages and updated_state.messages[-1]["role"] == "assistant"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|