npcsh 1.0.14__py3-none-any.whl → 1.0.17__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.
- npcsh/_state.py +1536 -78
- npcsh/corca.py +709 -0
- npcsh/guac.py +1433 -596
- npcsh/mcp_server.py +64 -60
- npcsh/npc.py +125 -98
- npcsh/npcsh.py +41 -1318
- npcsh/pti.py +195 -215
- npcsh/routes.py +106 -36
- npcsh/spool.py +138 -144
- {npcsh-1.0.14.dist-info → npcsh-1.0.17.dist-info}/METADATA +37 -367
- npcsh-1.0.17.dist-info/RECORD +21 -0
- {npcsh-1.0.14.dist-info → npcsh-1.0.17.dist-info}/entry_points.txt +1 -1
- npcsh/mcp_npcsh.py +0 -822
- npcsh-1.0.14.dist-info/RECORD +0 -21
- {npcsh-1.0.14.dist-info → npcsh-1.0.17.dist-info}/WHEEL +0 -0
- {npcsh-1.0.14.dist-info → npcsh-1.0.17.dist-info}/licenses/LICENSE +0 -0
- {npcsh-1.0.14.dist-info → npcsh-1.0.17.dist-info}/top_level.txt +0 -0
npcsh/mcp_server.py
CHANGED
|
@@ -14,7 +14,6 @@ from typing import Optional, Dict, Any, List, Union, Callable
|
|
|
14
14
|
from mcp.server.fastmcp import FastMCP
|
|
15
15
|
import importlib
|
|
16
16
|
# npcpy imports
|
|
17
|
-
from npcpy.gen.response import get_litellm_response
|
|
18
17
|
|
|
19
18
|
|
|
20
19
|
import os
|
|
@@ -28,15 +27,27 @@ except:
|
|
|
28
27
|
from typing import Optional, Dict, Any, List, Union, Callable, get_type_hints
|
|
29
28
|
# Add these imports to the top of your file
|
|
30
29
|
from functools import wraps
|
|
30
|
+
import sys
|
|
31
|
+
|
|
32
|
+
from npcpy.llm_funcs import generate_group_candidates, abstract, extract_facts, zoom_in, execute_llm_command, gen_image
|
|
33
|
+
from npcpy.memory.search import search_similar_texts, execute_search_command, execute_rag_command, answer_with_rag, execute_brainblast_command
|
|
34
|
+
from npcpy.data.load import load_file_contents
|
|
35
|
+
from npcpy.memory.command_history import CommandHistory
|
|
36
|
+
from npcpy.data.image import capture_screenshot
|
|
37
|
+
from npcpy.data.web import search_web
|
|
38
|
+
|
|
39
|
+
from npcsh._state import NPCSH_DB_PATH
|
|
40
|
+
|
|
41
|
+
command_history = CommandHistory(db=NPCSH_DB_PATH)
|
|
42
|
+
|
|
31
43
|
# Initialize the MCP server
|
|
32
|
-
mcp = FastMCP("
|
|
44
|
+
mcp = FastMCP("npcsh_mcp")
|
|
33
45
|
|
|
34
46
|
# Define the default workspace
|
|
35
47
|
DEFAULT_WORKSPACE = os.path.join(os.getcwd(), "workspace")
|
|
36
48
|
os.makedirs(DEFAULT_WORKSPACE, exist_ok=True)
|
|
37
49
|
|
|
38
50
|
# ==================== SYSTEM TOOLS ====================
|
|
39
|
-
|
|
40
51
|
@mcp.tool()
|
|
41
52
|
async def run_server_command(command: str) -> str:
|
|
42
53
|
"""
|
|
@@ -54,45 +65,44 @@ async def run_server_command(command: str) -> str:
|
|
|
54
65
|
cwd=DEFAULT_WORKSPACE,
|
|
55
66
|
shell=True,
|
|
56
67
|
capture_output=True,
|
|
57
|
-
text=True
|
|
68
|
+
text=True,
|
|
69
|
+
timeout=30 # Add timeout to prevent hanging
|
|
58
70
|
)
|
|
59
|
-
return result.stdout or result.stderr
|
|
71
|
+
return result.stdout or result.stderr or "Command completed with no output"
|
|
72
|
+
except subprocess.TimeoutExpired:
|
|
73
|
+
return "Command timed out after 30 seconds"
|
|
60
74
|
except Exception as e:
|
|
61
75
|
return str(e)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
|
|
62
79
|
def make_async_wrapper(func: Callable) -> Callable:
|
|
63
|
-
"""Create an async wrapper for sync functions
|
|
80
|
+
"""Create an async wrapper for sync functions."""
|
|
64
81
|
|
|
65
82
|
@wraps(func)
|
|
66
|
-
async def async_wrapper(
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
params = args[0]
|
|
70
|
-
|
|
71
|
-
# Fix for search_web - add required kwargs parameter
|
|
72
|
-
if "kwargs" not in params:
|
|
73
|
-
# Create a new dict with the kwargs parameter added
|
|
74
|
-
params = {**params, "kwargs": ""}
|
|
75
|
-
|
|
76
|
-
# Call the function with the parameters
|
|
77
|
-
if asyncio.iscoroutinefunction(func):
|
|
78
|
-
return await func(**params)
|
|
79
|
-
else:
|
|
80
|
-
return await asyncio.to_thread(func, **params)
|
|
83
|
+
async def async_wrapper(**kwargs):
|
|
84
|
+
func_name = func.__name__
|
|
85
|
+
print(f"MCP SERVER DEBUG: {func_name} called with kwargs={kwargs}", flush=True)
|
|
81
86
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
+
try:
|
|
88
|
+
result = func(**kwargs)
|
|
89
|
+
print(f"MCP SERVER DEBUG: {func_name} returned type={type(result)}, result={result[:500] if isinstance(result, str) else result}", flush=True)
|
|
90
|
+
return result
|
|
91
|
+
|
|
92
|
+
except Exception as e:
|
|
93
|
+
print(f"MCP SERVER DEBUG: {func_name} exception: {e}", flush=True)
|
|
94
|
+
import traceback
|
|
95
|
+
traceback.print_exc()
|
|
96
|
+
return f"Error in {func_name}: {e}"
|
|
87
97
|
|
|
88
|
-
# Preserve function metadata
|
|
89
98
|
async_wrapper.__name__ = func.__name__
|
|
90
99
|
async_wrapper.__doc__ = func.__doc__
|
|
91
100
|
async_wrapper.__annotations__ = func.__annotations__
|
|
92
101
|
|
|
93
102
|
return async_wrapper
|
|
94
103
|
|
|
95
|
-
|
|
104
|
+
|
|
105
|
+
|
|
96
106
|
def register_module_tools(module_name: str) -> None:
|
|
97
107
|
"""
|
|
98
108
|
Register all suitable functions from a module as MCP tools with improved argument handling.
|
|
@@ -133,45 +143,39 @@ def load_module_functions(module_name: str) -> List[Callable]:
|
|
|
133
143
|
|
|
134
144
|
print("Loading tools from npcpy modules...")
|
|
135
145
|
|
|
136
|
-
# Load modules from npcpy.routes
|
|
137
|
-
try:
|
|
138
|
-
from npcpy.routes import routes
|
|
139
|
-
for route_name, route_func in routes.items():
|
|
140
|
-
if callable(route_func):
|
|
141
|
-
async_func = make_async_wrapper(route_func)
|
|
142
|
-
try:
|
|
143
|
-
mcp.tool()(async_func)
|
|
144
|
-
print(f"Registered route: {route_name}")
|
|
145
|
-
except Exception as e:
|
|
146
|
-
print(f"Failed to register route {route_name}: {e}")
|
|
147
|
-
except ImportError as e:
|
|
148
|
-
print(f"Warning: Could not import routes: {e}")
|
|
149
146
|
|
|
150
147
|
|
|
151
|
-
# Load npc_compiler functions
|
|
152
|
-
print("Loading functions from npcpy.npc_compiler...")
|
|
153
|
-
try:
|
|
154
|
-
import importlib.util
|
|
155
|
-
if importlib.util.find_spec("npcpy.npc_compiler"):
|
|
156
|
-
register_module_tools("npcpy.npc_compiler")
|
|
157
|
-
except ImportError:
|
|
158
|
-
print("npcpy.npc_compiler not found, skipping...")
|
|
159
148
|
|
|
160
|
-
# Load npc_sysenv functions
|
|
161
|
-
#print("Loading functions from npcpy.npc_sysenv...")
|
|
162
|
-
#register_module_tools("npcpy.npc_sysenv")
|
|
163
|
-
register_module_tools("npcpy.memory.search")
|
|
164
149
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
150
|
+
def register_selected_npcpy_tools():
|
|
151
|
+
tools = [generate_group_candidates,
|
|
152
|
+
abstract,
|
|
153
|
+
extract_facts,
|
|
154
|
+
zoom_in,
|
|
155
|
+
execute_llm_command,
|
|
156
|
+
gen_image,
|
|
157
|
+
load_file_contents,
|
|
158
|
+
capture_screenshot,
|
|
159
|
+
search_web, ]
|
|
168
160
|
|
|
169
|
-
|
|
170
|
-
#
|
|
161
|
+
for func in tools:
|
|
162
|
+
# Ensure a docstring exists for schema generation
|
|
163
|
+
if not (getattr(func, "__doc__", None) and func.__doc__.strip()):
|
|
164
|
+
fallback_doc = f"Tool wrapper for {func.__name__}."
|
|
165
|
+
try:
|
|
166
|
+
func.__doc__ = fallback_doc
|
|
167
|
+
except Exception:
|
|
168
|
+
pass # Some builtins may not allow setting __doc__
|
|
169
|
+
|
|
170
|
+
try:
|
|
171
|
+
async_func = make_async_wrapper(func)
|
|
172
|
+
mcp.tool()(async_func)
|
|
173
|
+
print(f"Registered npcpy tool: {func.__name__}")
|
|
174
|
+
except Exception as e:
|
|
175
|
+
print(f"Failed to register npcpy tool {func.__name__}: {e}")
|
|
176
|
+
register_selected_npcpy_tools()
|
|
171
177
|
|
|
172
178
|
|
|
173
|
-
#print("Loading functions from npcpy.npc_sysenv...")
|
|
174
|
-
#register_module_tools("npcpy.llm_funcs")
|
|
175
179
|
|
|
176
180
|
|
|
177
181
|
# ==================== MAIN ENTRY POINT ====================
|
npcsh/npc.py
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import argparse
|
|
2
2
|
import sys
|
|
3
3
|
import os
|
|
4
|
-
import sqlite3
|
|
5
4
|
import traceback
|
|
6
5
|
from typing import Optional
|
|
7
6
|
|
|
@@ -11,7 +10,8 @@ from npcsh._state import (
|
|
|
11
10
|
NPCSH_API_URL,
|
|
12
11
|
NPCSH_DB_PATH,
|
|
13
12
|
NPCSH_STREAM_OUTPUT,
|
|
14
|
-
|
|
13
|
+
initial_state,
|
|
14
|
+
)
|
|
15
15
|
from npcpy.npc_sysenv import (
|
|
16
16
|
print_and_process_stream_with_markdown,
|
|
17
17
|
render_markdown,
|
|
@@ -19,8 +19,17 @@ from npcpy.npc_sysenv import (
|
|
|
19
19
|
from npcpy.npc_compiler import NPC, Team
|
|
20
20
|
from npcsh.routes import router
|
|
21
21
|
from npcpy.llm_funcs import check_llm_command
|
|
22
|
+
from sqlalchemy import create_engine
|
|
23
|
+
|
|
24
|
+
# Import the key functions from npcsh
|
|
25
|
+
from npcsh._state import (
|
|
26
|
+
setup_shell,
|
|
27
|
+
execute_slash_command,
|
|
28
|
+
execute_command,
|
|
29
|
+
)
|
|
22
30
|
|
|
23
31
|
def load_npc_by_name(npc_name: str = "sibiji", db_path: str = NPCSH_DB_PATH) -> Optional[NPC]:
|
|
32
|
+
"""Load NPC by name, with fallback logic matching npcsh"""
|
|
24
33
|
if not npc_name:
|
|
25
34
|
npc_name = "sibiji"
|
|
26
35
|
|
|
@@ -37,7 +46,7 @@ def load_npc_by_name(npc_name: str = "sibiji", db_path: str = NPCSH_DB_PATH) ->
|
|
|
37
46
|
|
|
38
47
|
if chosen_path:
|
|
39
48
|
try:
|
|
40
|
-
db_conn =
|
|
49
|
+
db_conn = create_engine(f'sqlite:///{NPCSH_DB_PATH}')
|
|
41
50
|
npc = NPC(file=chosen_path, db_conn=db_conn)
|
|
42
51
|
return npc
|
|
43
52
|
except Exception as e:
|
|
@@ -50,6 +59,8 @@ def load_npc_by_name(npc_name: str = "sibiji", db_path: str = NPCSH_DB_PATH) ->
|
|
|
50
59
|
return None
|
|
51
60
|
|
|
52
61
|
def main():
|
|
62
|
+
from npcsh.routes import router
|
|
63
|
+
|
|
53
64
|
parser = argparse.ArgumentParser(
|
|
54
65
|
description="NPC Command Line Utilities. Call a command or provide a prompt for the default NPC.",
|
|
55
66
|
usage="npc <command> [command_args...] | <prompt> [--npc NAME] [--model MODEL] [--provider PROV]"
|
|
@@ -64,34 +75,38 @@ def main():
|
|
|
64
75
|
"-n", "--npc", help="Name of the NPC to use (default: sibiji)", type=str, default="sibiji"
|
|
65
76
|
)
|
|
66
77
|
|
|
67
|
-
#
|
|
68
|
-
|
|
69
|
-
# First, get any arguments without parsing commands
|
|
78
|
+
# Parse arguments
|
|
70
79
|
args, all_args = parser.parse_known_args()
|
|
71
80
|
global_model = args.model
|
|
72
81
|
global_provider = args.provider
|
|
73
82
|
|
|
74
|
-
# Check if the first argument is a known command
|
|
75
83
|
is_valid_command = False
|
|
76
84
|
command_name = None
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
85
|
+
|
|
86
|
+
if all_args:
|
|
87
|
+
first_arg = all_args[0]
|
|
88
|
+
if first_arg.startswith('/'):
|
|
89
|
+
is_valid_command = True
|
|
90
|
+
command_name = first_arg
|
|
91
|
+
all_args = all_args[1:]
|
|
92
|
+
elif first_arg in router.get_commands():
|
|
93
|
+
is_valid_command = True
|
|
94
|
+
command_name = '/' + first_arg
|
|
95
|
+
all_args = all_args[1:]
|
|
96
|
+
|
|
97
|
+
|
|
81
98
|
|
|
82
|
-
# Only set up subparsers if we have a valid command
|
|
83
99
|
if is_valid_command:
|
|
84
100
|
subparsers = parser.add_subparsers(dest="command", title="Available Commands",
|
|
85
101
|
help="Run 'npc <command> --help' for command-specific help")
|
|
86
102
|
|
|
87
103
|
for cmd_name, help_text in router.help_info.items():
|
|
88
|
-
|
|
89
104
|
cmd_parser = subparsers.add_parser(cmd_name, help=help_text, add_help=False)
|
|
90
105
|
cmd_parser.add_argument('command_args', nargs=argparse.REMAINDER,
|
|
91
106
|
help='Arguments passed directly to the command handler')
|
|
92
107
|
|
|
93
108
|
# Re-parse with command subparsers
|
|
94
|
-
args = parser.parse_args([command_name] + all_args)
|
|
109
|
+
args = parser.parse_args([command_name.lstrip('/')] + all_args)
|
|
95
110
|
command_args = args.command_args if hasattr(args, 'command_args') else []
|
|
96
111
|
unknown_args = []
|
|
97
112
|
else:
|
|
@@ -104,67 +119,86 @@ def main():
|
|
|
104
119
|
args.model = global_model
|
|
105
120
|
if args.provider is None:
|
|
106
121
|
args.provider = global_provider
|
|
107
|
-
# --- END OF FIX ---
|
|
108
|
-
npc_instance = load_npc_by_name(args.npc, NPCSH_DB_PATH)
|
|
109
|
-
|
|
110
|
-
effective_model = args.model or NPCSH_CHAT_MODEL
|
|
111
|
-
effective_provider = args.provider or NPCSH_CHAT_PROVIDER
|
|
112
|
-
|
|
113
122
|
|
|
123
|
+
# Use npcsh's setup_shell to get proper team and NPC setup
|
|
124
|
+
try:
|
|
125
|
+
command_history, team, forenpc_obj = setup_shell()
|
|
126
|
+
except Exception as e:
|
|
127
|
+
print(f"Warning: Could not set up full npcsh environment: {e}", file=sys.stderr)
|
|
128
|
+
print("Falling back to basic NPC loading...", file=sys.stderr)
|
|
129
|
+
team = None
|
|
130
|
+
forenpc_obj = load_npc_by_name(args.npc, NPCSH_DB_PATH)
|
|
131
|
+
|
|
132
|
+
# Determine which NPC to use
|
|
133
|
+
npc_instance = None
|
|
134
|
+
if team and args.npc in team.npcs:
|
|
135
|
+
npc_instance = team.npcs[args.npc]
|
|
136
|
+
elif team and args.npc == team.forenpc.name if team.forenpc else False:
|
|
137
|
+
npc_instance = team.forenpc
|
|
138
|
+
else:
|
|
139
|
+
npc_instance = load_npc_by_name(args.npc, NPCSH_DB_PATH)
|
|
114
140
|
|
|
115
|
-
|
|
141
|
+
if not npc_instance:
|
|
142
|
+
print(f"Error: Could not load NPC '{args.npc}'", file=sys.stderr)
|
|
143
|
+
sys.exit(1)
|
|
116
144
|
|
|
117
|
-
#
|
|
118
|
-
if is_valid_command:
|
|
119
|
-
|
|
120
|
-
if command_args:
|
|
121
|
-
i = 0
|
|
122
|
-
while i < len(command_args):
|
|
123
|
-
arg = command_args[i]
|
|
124
|
-
if arg.startswith("--"):
|
|
125
|
-
param = arg[2:] # Remove --
|
|
126
|
-
if "=" in param:
|
|
127
|
-
param_name, param_value = param.split("=", 1)
|
|
128
|
-
extras[param_name] = param_value
|
|
129
|
-
i += 1
|
|
130
|
-
elif i + 1 < len(command_args) and not command_args[i+1].startswith("--"):
|
|
131
|
-
extras[param] = command_args[i+1]
|
|
132
|
-
i += 2
|
|
133
|
-
else:
|
|
134
|
-
extras[param] = True
|
|
135
|
-
i += 1
|
|
136
|
-
else:
|
|
137
|
-
i += 1
|
|
138
|
-
|
|
139
|
-
handler = router.get_route(command_name)
|
|
140
|
-
if not handler:
|
|
141
|
-
print(f"Error: Command '{command_name}' recognized but no handler found.", file=sys.stderr)
|
|
142
|
-
sys.exit(1)
|
|
143
|
-
|
|
144
|
-
full_command_str = command_name
|
|
145
|
-
if command_args:
|
|
146
|
-
full_command_str += " " + " ".join(command_args)
|
|
145
|
+
# Now check for jinxs if we haven't identified a command yet
|
|
146
|
+
if not is_valid_command and all_args:
|
|
147
|
+
first_arg = all_args[0]
|
|
147
148
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
149
|
+
# Check if first argument is a jinx name
|
|
150
|
+
jinx_found = False
|
|
151
|
+
if team and first_arg in team.jinxs_dict:
|
|
152
|
+
jinx_found = True
|
|
153
|
+
elif isinstance(npc_instance, NPC) and hasattr(npc_instance, 'jinxs_dict') and first_arg in npc_instance.jinxs_dict:
|
|
154
|
+
jinx_found = True
|
|
155
|
+
|
|
156
|
+
if jinx_found:
|
|
157
|
+
is_valid_command = True
|
|
158
|
+
command_name = '/' + first_arg
|
|
159
|
+
all_args = all_args[1:]
|
|
160
|
+
|
|
161
|
+
# Create a shell state object similar to npcsh
|
|
162
|
+
shell_state = initial_state
|
|
163
|
+
shell_state.npc = npc_instance
|
|
164
|
+
shell_state.team = team
|
|
165
|
+
shell_state.current_path = os.getcwd()
|
|
166
|
+
shell_state.stream_output = NPCSH_STREAM_OUTPUT
|
|
167
|
+
|
|
168
|
+
# Override model/provider if specified
|
|
169
|
+
effective_model = args.model or (npc_instance.model if npc_instance.model else NPCSH_CHAT_MODEL)
|
|
170
|
+
effective_provider = args.provider or (npc_instance.provider if npc_instance.provider else NPCSH_CHAT_PROVIDER)
|
|
171
|
+
|
|
172
|
+
# Update the NPC's model/provider for this session if overridden
|
|
173
|
+
if args.model:
|
|
174
|
+
npc_instance.model = effective_model
|
|
175
|
+
if args.provider:
|
|
176
|
+
npc_instance.provider = effective_provider
|
|
177
|
+
try:
|
|
178
|
+
if is_valid_command:
|
|
179
|
+
# Handle slash command using npcsh's execute_slash_command
|
|
180
|
+
full_command_str = command_name
|
|
181
|
+
if command_args:
|
|
182
|
+
full_command_str += " " + " ".join(command_args)
|
|
183
|
+
|
|
184
|
+
print(f"Executing command: {full_command_str}")
|
|
185
|
+
|
|
186
|
+
updated_state, result = execute_slash_command(
|
|
187
|
+
full_command_str,
|
|
188
|
+
stdin_input=None,
|
|
189
|
+
state=shell_state,
|
|
190
|
+
stream=NPCSH_STREAM_OUTPUT,
|
|
191
|
+
router = router
|
|
192
|
+
)
|
|
162
193
|
|
|
194
|
+
# Process and display the result
|
|
163
195
|
if isinstance(result, dict):
|
|
164
196
|
output = result.get("output") or result.get("response")
|
|
197
|
+
model_for_stream = result.get('model', effective_model)
|
|
198
|
+
provider_for_stream = result.get('provider', effective_provider)
|
|
165
199
|
|
|
166
200
|
if NPCSH_STREAM_OUTPUT and not isinstance(output, str):
|
|
167
|
-
print_and_process_stream_with_markdown(output,
|
|
201
|
+
print_and_process_stream_with_markdown(output, model_for_stream, provider_for_stream)
|
|
168
202
|
elif output is not None:
|
|
169
203
|
render_markdown(str(output))
|
|
170
204
|
elif result is not None:
|
|
@@ -172,45 +206,38 @@ def main():
|
|
|
172
206
|
else:
|
|
173
207
|
print(f"Command '{command_name}' executed.")
|
|
174
208
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
sys.exit(1)
|
|
179
|
-
else:
|
|
180
|
-
# Process as a prompt
|
|
181
|
-
prompt = " ".join(unknown_args)
|
|
209
|
+
else:
|
|
210
|
+
# Process as a regular prompt using npcsh's execution logic
|
|
211
|
+
prompt = " ".join(unknown_args)
|
|
182
212
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
213
|
+
if not prompt:
|
|
214
|
+
# If no prompt and no command, show help
|
|
215
|
+
parser.print_help()
|
|
216
|
+
sys.exit(1)
|
|
187
217
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
provider=effective_provider,
|
|
194
|
-
npc=npc_instance,
|
|
195
|
-
stream=NPCSH_STREAM_OUTPUT,
|
|
196
|
-
messages=[],
|
|
197
|
-
team=None,
|
|
198
|
-
api_url=NPCSH_API_URL,
|
|
199
|
-
)
|
|
218
|
+
print(f"Processing prompt: '{prompt}' with NPC: '{args.npc}'...")
|
|
219
|
+
|
|
220
|
+
# Use npcsh's execute_command but force it to chat mode for simple prompts
|
|
221
|
+
shell_state.current_mode = 'chat'
|
|
222
|
+
updated_state, result = execute_command(prompt, shell_state)
|
|
200
223
|
|
|
201
|
-
|
|
202
|
-
|
|
224
|
+
# Process and display the result
|
|
225
|
+
if isinstance(result, dict):
|
|
226
|
+
output = result.get("output")
|
|
227
|
+
model_for_stream = result.get('model', effective_model)
|
|
228
|
+
provider_for_stream = result.get('provider', effective_provider)
|
|
229
|
+
|
|
203
230
|
if NPCSH_STREAM_OUTPUT and hasattr(output, '__iter__') and not isinstance(output, (str, bytes, dict, list)):
|
|
204
|
-
print_and_process_stream_with_markdown(output,
|
|
231
|
+
print_and_process_stream_with_markdown(output, model_for_stream, provider_for_stream)
|
|
205
232
|
elif output is not None:
|
|
206
233
|
render_markdown(str(output))
|
|
207
|
-
elif
|
|
208
|
-
render_markdown(str(
|
|
234
|
+
elif result is not None:
|
|
235
|
+
render_markdown(str(result))
|
|
209
236
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
237
|
+
except Exception as e:
|
|
238
|
+
print(f"Error executing command: {e}", file=sys.stderr)
|
|
239
|
+
traceback.print_exc()
|
|
240
|
+
sys.exit(1)
|
|
214
241
|
|
|
215
242
|
if __name__ == "__main__":
|
|
216
243
|
main()
|