npcsh 0.3.31__py3-none-any.whl → 1.0.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.
Files changed (91) hide show
  1. npcsh/_state.py +942 -0
  2. npcsh/alicanto.py +1074 -0
  3. npcsh/guac.py +785 -0
  4. npcsh/mcp_helpers.py +357 -0
  5. npcsh/mcp_npcsh.py +822 -0
  6. npcsh/mcp_server.py +184 -0
  7. npcsh/npc.py +218 -0
  8. npcsh/npcsh.py +1161 -0
  9. npcsh/plonk.py +387 -269
  10. npcsh/pti.py +234 -0
  11. npcsh/routes.py +958 -0
  12. npcsh/spool.py +315 -0
  13. npcsh/wander.py +550 -0
  14. npcsh/yap.py +573 -0
  15. npcsh-1.0.0.dist-info/METADATA +596 -0
  16. npcsh-1.0.0.dist-info/RECORD +21 -0
  17. {npcsh-0.3.31.dist-info → npcsh-1.0.0.dist-info}/WHEEL +1 -1
  18. npcsh-1.0.0.dist-info/entry_points.txt +9 -0
  19. {npcsh-0.3.31.dist-info → npcsh-1.0.0.dist-info}/licenses/LICENSE +1 -1
  20. npcsh/audio.py +0 -210
  21. npcsh/cli.py +0 -545
  22. npcsh/command_history.py +0 -566
  23. npcsh/conversation.py +0 -291
  24. npcsh/data_models.py +0 -46
  25. npcsh/dataframes.py +0 -163
  26. npcsh/embeddings.py +0 -168
  27. npcsh/helpers.py +0 -641
  28. npcsh/image.py +0 -298
  29. npcsh/image_gen.py +0 -79
  30. npcsh/knowledge_graph.py +0 -1006
  31. npcsh/llm_funcs.py +0 -2027
  32. npcsh/load_data.py +0 -83
  33. npcsh/main.py +0 -5
  34. npcsh/model_runner.py +0 -189
  35. npcsh/npc_compiler.py +0 -2870
  36. npcsh/npc_sysenv.py +0 -383
  37. npcsh/npc_team/assembly_lines/test_pipeline.py +0 -181
  38. npcsh/npc_team/corca.npc +0 -13
  39. npcsh/npc_team/foreman.npc +0 -7
  40. npcsh/npc_team/npcsh.ctx +0 -11
  41. npcsh/npc_team/sibiji.npc +0 -4
  42. npcsh/npc_team/templates/analytics/celona.npc +0 -0
  43. npcsh/npc_team/templates/hr_support/raone.npc +0 -0
  44. npcsh/npc_team/templates/humanities/eriane.npc +0 -4
  45. npcsh/npc_team/templates/it_support/lineru.npc +0 -0
  46. npcsh/npc_team/templates/marketing/slean.npc +0 -4
  47. npcsh/npc_team/templates/philosophy/maurawa.npc +0 -0
  48. npcsh/npc_team/templates/sales/turnic.npc +0 -4
  49. npcsh/npc_team/templates/software/welxor.npc +0 -0
  50. npcsh/npc_team/tools/bash_executer.tool +0 -32
  51. npcsh/npc_team/tools/calculator.tool +0 -8
  52. npcsh/npc_team/tools/code_executor.tool +0 -16
  53. npcsh/npc_team/tools/generic_search.tool +0 -27
  54. npcsh/npc_team/tools/image_generation.tool +0 -25
  55. npcsh/npc_team/tools/local_search.tool +0 -149
  56. npcsh/npc_team/tools/npcsh_executor.tool +0 -9
  57. npcsh/npc_team/tools/screen_cap.tool +0 -27
  58. npcsh/npc_team/tools/sql_executor.tool +0 -26
  59. npcsh/response.py +0 -623
  60. npcsh/search.py +0 -248
  61. npcsh/serve.py +0 -1460
  62. npcsh/shell.py +0 -538
  63. npcsh/shell_helpers.py +0 -3529
  64. npcsh/stream.py +0 -700
  65. npcsh/video.py +0 -49
  66. npcsh-0.3.31.data/data/npcsh/npc_team/bash_executer.tool +0 -32
  67. npcsh-0.3.31.data/data/npcsh/npc_team/calculator.tool +0 -8
  68. npcsh-0.3.31.data/data/npcsh/npc_team/celona.npc +0 -0
  69. npcsh-0.3.31.data/data/npcsh/npc_team/code_executor.tool +0 -16
  70. npcsh-0.3.31.data/data/npcsh/npc_team/corca.npc +0 -13
  71. npcsh-0.3.31.data/data/npcsh/npc_team/eriane.npc +0 -4
  72. npcsh-0.3.31.data/data/npcsh/npc_team/foreman.npc +0 -7
  73. npcsh-0.3.31.data/data/npcsh/npc_team/generic_search.tool +0 -27
  74. npcsh-0.3.31.data/data/npcsh/npc_team/image_generation.tool +0 -25
  75. npcsh-0.3.31.data/data/npcsh/npc_team/lineru.npc +0 -0
  76. npcsh-0.3.31.data/data/npcsh/npc_team/local_search.tool +0 -149
  77. npcsh-0.3.31.data/data/npcsh/npc_team/maurawa.npc +0 -0
  78. npcsh-0.3.31.data/data/npcsh/npc_team/npcsh.ctx +0 -11
  79. npcsh-0.3.31.data/data/npcsh/npc_team/npcsh_executor.tool +0 -9
  80. npcsh-0.3.31.data/data/npcsh/npc_team/raone.npc +0 -0
  81. npcsh-0.3.31.data/data/npcsh/npc_team/screen_cap.tool +0 -27
  82. npcsh-0.3.31.data/data/npcsh/npc_team/sibiji.npc +0 -4
  83. npcsh-0.3.31.data/data/npcsh/npc_team/slean.npc +0 -4
  84. npcsh-0.3.31.data/data/npcsh/npc_team/sql_executor.tool +0 -26
  85. npcsh-0.3.31.data/data/npcsh/npc_team/test_pipeline.py +0 -181
  86. npcsh-0.3.31.data/data/npcsh/npc_team/turnic.npc +0 -4
  87. npcsh-0.3.31.data/data/npcsh/npc_team/welxor.npc +0 -0
  88. npcsh-0.3.31.dist-info/METADATA +0 -1853
  89. npcsh-0.3.31.dist-info/RECORD +0 -76
  90. npcsh-0.3.31.dist-info/entry_points.txt +0 -3
  91. {npcsh-0.3.31.dist-info → npcsh-1.0.0.dist-info}/top_level.txt +0 -0
npcsh/shell.py DELETED
@@ -1,538 +0,0 @@
1
- import os
2
- import sys
3
- import readline
4
- import atexit
5
- import re
6
- import pty
7
- import select
8
- import termios
9
- import tty
10
- import shlex
11
- import json
12
-
13
- from datetime import datetime
14
- from inspect import isgenerator
15
-
16
-
17
- # Third-party imports
18
- import pandas as pd
19
- import sqlite3
20
- import numpy as np
21
- from termcolor import colored
22
- from dotenv import load_dotenv
23
- import subprocess
24
- from typing import Dict, Any, List, Optional
25
-
26
-
27
- try:
28
- from sentence_transformers import SentenceTransformer
29
- except:
30
- print("Could not load the sentence-transformers package.")
31
- # Local imports
32
-
33
- from .npc_sysenv import (
34
- get_system_message,
35
- lookup_provider,
36
- NPCSH_STREAM_OUTPUT,
37
- NPCSH_CHAT_MODEL,
38
- NPCSH_CHAT_PROVIDER,
39
- NPCSH_API_URL,
40
- )
41
-
42
- from .command_history import (
43
- CommandHistory,
44
- start_new_conversation,
45
- save_conversation_message,
46
- save_attachment_to_message,
47
- )
48
- from .llm_funcs import (
49
- execute_llm_command,
50
- execute_llm_question,
51
- generate_image,
52
- check_llm_command,
53
- get_conversation,
54
- get_system_message,
55
- )
56
- from .search import rag_search, search_web
57
- from .helpers import (
58
- load_all_files,
59
- setup_npcsh_config,
60
- is_npcsh_initialized,
61
- initialize_base_npcs_if_needed,
62
- )
63
- from .shell_helpers import (
64
- complete, # For command completion
65
- readline_safe_prompt,
66
- get_multiline_input,
67
- setup_readline,
68
- execute_command,
69
- render_markdown,
70
- render_code_block,
71
- orange, # For colored prompt
72
- )
73
- from .npc_compiler import (
74
- NPCCompiler,
75
- load_tools_from_directory,
76
- NPC,
77
- initialize_npc_project,
78
- )
79
-
80
- import argparse
81
- from .serve import (
82
- start_flask_server,
83
- )
84
- import importlib.metadata # Python 3.8+
85
-
86
- # Fetch the version from the package metadata
87
- try:
88
- VERSION = importlib.metadata.version(
89
- "npcsh"
90
- ) # Replace "npcsh" with your package name
91
- except importlib.metadata.PackageNotFoundError:
92
- VERSION = "unknown" # Fallback if the package is not installed
93
-
94
-
95
- def main() -> None:
96
- """
97
- Main function for the npcsh shell and server.
98
- Starts either the Flask server or the interactive shell based on the argument provided.
99
- """
100
- # Set up argument parsing to handle 'serve' and regular commands
101
-
102
- check_old_par_name = os.environ.get("NPCSH_MODEL", None)
103
- if check_old_par_name is not None:
104
- # raise a deprecation warning
105
- print(
106
- """Deprecation Warning: NPCSH_MODEL and NPCSH_PROVIDER were deprecated in v0.3.5 in favor of NPCSH_CHAT_MODEL and NPCSH_CHAT_PROVIDER instead.\
107
- Please update your environment variables to use the new names.
108
- """
109
- )
110
-
111
- parser = argparse.ArgumentParser(description="npcsh CLI")
112
- parser.add_argument(
113
- "-v",
114
- "--version",
115
- action="version",
116
- version=f"npcsh version {VERSION}", # Use the dynamically fetched version
117
- )
118
- args = parser.parse_args()
119
-
120
- setup_npcsh_config()
121
- if "NPCSH_DB_PATH" in os.environ:
122
- db_path = os.path.expanduser(os.environ["NPCSH_DB_PATH"])
123
- else:
124
- db_path = os.path.expanduser("~/npcsh_history.db")
125
-
126
- command_history = CommandHistory(db_path)
127
- valid_commands = [
128
- "/compile",
129
- "/com",
130
- "/whisper",
131
- "/notes",
132
- "/data",
133
- "/cmd",
134
- "/command",
135
- "/set",
136
- "/sample",
137
- "/spool",
138
- "/sp",
139
- "/help",
140
- "/exit",
141
- "/quit",
142
- ]
143
-
144
- readline.set_completer_delims(" \t\n")
145
- readline.set_completer(complete)
146
- if sys.platform == "darwin":
147
- readline.parse_and_bind("bind ^I rl_complete")
148
- else:
149
- readline.parse_and_bind("tab: complete")
150
-
151
- # check if ./npc_team exists
152
- if os.path.exists("./npc_team"):
153
-
154
- npc_directory = os.path.abspath("./npc_team/")
155
- else:
156
- npc_directory = os.path.expanduser("~/.npcsh/npc_team/")
157
-
158
- npc_compiler = NPCCompiler(npc_directory, db_path)
159
-
160
- os.makedirs(npc_directory, exist_ok=True)
161
-
162
- # Compile all NPCs in the user's npc_team directory
163
- for filename in os.listdir(npc_directory):
164
- if filename.endswith(".npc"):
165
- npc_file_path = os.path.join(npc_directory, filename)
166
- npc_compiler.compile(npc_file_path)
167
-
168
- # Compile NPCs from project-specific npc_team directory
169
- if os.path.exists(npc_directory):
170
- for filename in os.listdir(npc_directory):
171
- if filename.endswith(".npc"):
172
- npc_file_path = os.path.join(npc_directory, filename)
173
- npc_compiler.compile(npc_file_path)
174
-
175
- if not is_npcsh_initialized():
176
- print("Initializing NPCSH...")
177
- initialize_base_npcs_if_needed(db_path)
178
- print(
179
- "NPCSH initialization complete. Please restart your terminal or run 'source ~/.npcshrc' for the changes to take effect."
180
- )
181
-
182
- history_file = setup_readline()
183
- atexit.register(readline.write_history_file, history_file)
184
- atexit.register(command_history.close)
185
- # make npcsh into ascii art
186
- from colorama import init
187
-
188
- init() # Initialize colorama for ANSI code support
189
- if sys.stdin.isatty():
190
-
191
- print(
192
- """
193
- Welcome to \033[1;94mnpc\033[0m\033[1;38;5;202msh\033[0m!
194
- \033[1;94m \033[0m\033[1;38;5;202m \\\\
195
- \033[1;94m _ __ _ __ ___ \033[0m\033[1;38;5;202m ___ | |___ \\\\
196
- \033[1;94m| '_ \ | '_ \ / __|\033[0m\033[1;38;5;202m/ __/ | |_ _| \\\\
197
- \033[1;94m| | | || |_) |( |__ \033[0m\033[1;38;5;202m\_ \ | | | | //
198
- \033[1;94m|_| |_|| .__/ \___|\033[0m\033[1;38;5;202m|___/ |_| |_| //
199
- \033[1;94m| | \033[0m\033[1;38;5;202m //
200
- \033[1;94m| |
201
- \033[1;94m|_|
202
-
203
- Begin by asking a question, issuing a bash command, or typing '/help' for more information.
204
- """
205
- )
206
-
207
- current_npc = None
208
- messages = None
209
- current_conversation_id = start_new_conversation()
210
-
211
- # --- Minimal Piped Input Handling ---
212
- if not sys.stdin.isatty():
213
- for line in sys.stdin:
214
- user_input = line.strip()
215
- if not user_input:
216
- continue # Skip empty lines
217
- if user_input.lower() in ["exit", "quit"]:
218
- print("Goodbye!")
219
- sys.exit(0)
220
- result = execute_command(
221
- user_input,
222
- db_path,
223
- npc_compiler,
224
- current_npc,
225
- model=NPCSH_CHAT_MODEL,
226
- provider=NPCSH_CHAT_PROVIDER,
227
- messages=messages,
228
- conversation_id=current_conversation_id,
229
- stream=NPCSH_STREAM_OUTPUT,
230
- api_url=NPCSH_API_URL,
231
- )
232
- messages = result.get("messages", messages)
233
- if "current_npc" in result:
234
- current_npc = result["current_npc"]
235
- output = result.get("output")
236
- conversation_id = result.get("conversation_id")
237
- model = result.get("model")
238
- provider = result.get("provider")
239
- npc = result.get("npc")
240
- messages = result.get("messages")
241
- current_path = result.get("current_path")
242
- attachments = result.get("attachments")
243
- npc_name = (
244
- npc.name
245
- if isinstance(npc, NPC)
246
- else npc if isinstance(npc, str) else None
247
- )
248
-
249
- save_conversation_message(
250
- command_history,
251
- conversation_id,
252
- "user",
253
- user_input,
254
- wd=current_path,
255
- model=model,
256
- provider=provider,
257
- npc=npc_name,
258
- attachments=attachments,
259
- )
260
- if NPCSH_STREAM_OUTPUT and (
261
- isgenerator(output)
262
- or (hasattr(output, "__iter__") and hasattr(output, "__next__"))
263
- ):
264
- str_output = ""
265
- in_code = False
266
- code_buffer = ""
267
- text_buffer = ""
268
-
269
- for chunk in output:
270
- # Get chunk content based on provider
271
- if provider == "anthropic":
272
- chunk_content = (
273
- chunk.delta.text
274
- if chunk.type == "content_block_delta"
275
- else None
276
- )
277
- elif provider in ["openai", "deepseek", "openai-like"]:
278
- chunk_content = "".join(
279
- c.delta.content for c in chunk.choices if c.delta.content
280
- )
281
- elif provider == "ollama":
282
- chunk_content = chunk["message"]["content"]
283
- else:
284
- continue
285
-
286
- if not chunk_content:
287
- continue
288
-
289
- str_output += chunk_content
290
-
291
- # Process chunk
292
- if "```" in chunk_content:
293
- parts = chunk_content.split("```")
294
-
295
- for i, part in enumerate(parts):
296
- if i == 0: # First part (before any backticks)
297
- if in_code:
298
- code_buffer += part
299
- else:
300
- print(part, end="")
301
- elif i % 2 == 1: # Inside a code block
302
- if not in_code: # Starting a new code block
303
- in_code = True
304
- code_buffer = part
305
- else: # Shouldn't happen but handle anyway
306
- code_buffer += part
307
- else: # Outside a code block
308
- if in_code: # Just finished a code block
309
- in_code = False
310
- # Render the code block
311
- render_code_block(code_buffer)
312
- code_buffer = ""
313
- print(part, end="")
314
- else:
315
- if in_code:
316
- code_buffer += chunk_content
317
- else:
318
- print(chunk_content, end="")
319
-
320
- # Handle any remaining code buffer
321
- if in_code and code_buffer:
322
- render_code_block(code_buffer)
323
-
324
- if str_output:
325
- output = str_output
326
- save_conversation_message(
327
- command_history,
328
- conversation_id,
329
- "assistant",
330
- output,
331
- wd=current_path,
332
- model=model,
333
- provider=provider,
334
- npc=npc_name,
335
- )
336
- sys.exit(0)
337
-
338
- while True:
339
- try:
340
- if current_npc:
341
- prompt = f"{colored(os.getcwd(), 'blue')}:{orange(current_npc.name)}> "
342
- else:
343
- prompt = f"{colored(os.getcwd(), 'blue')}:\033[1;94mnpc\033[0m\033[1;38;5;202msh\033[0m!> "
344
-
345
- prompt = readline_safe_prompt(prompt)
346
- user_input = get_multiline_input(prompt).strip()
347
-
348
- if user_input.lower() in ["exit", "quit"]:
349
- if current_npc:
350
- print(f"Exiting {current_npc.name} mode.")
351
- current_npc = None
352
- continue
353
- else:
354
- print("Goodbye!")
355
- break
356
- # print(current_npc, "current npc fore command execution")
357
- # Execute the command and capture the result
358
- result = execute_command(
359
- user_input,
360
- db_path,
361
- npc_compiler,
362
- current_npc=current_npc,
363
- model=NPCSH_CHAT_MODEL,
364
- provider=NPCSH_CHAT_PROVIDER,
365
- messages=messages,
366
- conversation_id=current_conversation_id,
367
- stream=NPCSH_STREAM_OUTPUT,
368
- api_url=NPCSH_API_URL,
369
- )
370
-
371
- messages = result.get("messages", messages)
372
-
373
- # need to adjust the output for the messages to all have
374
- # model, provider, npc, timestamp, role, content
375
- # also messages
376
-
377
- if "current_npc" in result:
378
-
379
- current_npc = result["current_npc"]
380
- output = result.get("output")
381
-
382
- conversation_id = result.get("conversation_id")
383
- model = result.get("model")
384
- provider = result.get("provider")
385
-
386
- messages = result.get("messages")
387
- current_path = result.get("current_path")
388
- attachments = result.get("attachments")
389
-
390
- if current_npc is not None:
391
- if isinstance(current_npc, NPC):
392
- npc_name = current_npc.name
393
- elif isinstance(current_npc, str):
394
- npc_name = current_npc
395
- else:
396
- npc_name = None
397
- message_id = save_conversation_message(
398
- command_history,
399
- conversation_id,
400
- "user",
401
- user_input,
402
- wd=current_path,
403
- model=model,
404
- provider=provider,
405
- npc=npc_name,
406
- attachments=attachments,
407
- )
408
-
409
- str_output = ""
410
- try:
411
- if NPCSH_STREAM_OUTPUT and hasattr(output, "__iter__"):
412
-
413
- buffer = ""
414
- in_code = False
415
- code_buffer = ""
416
-
417
- for chunk in output:
418
-
419
- if provider == "anthropic":
420
- chunk_content = (
421
- chunk.delta.text
422
- if chunk.type == "content_block_delta"
423
- else None
424
- )
425
- elif provider in ["openai", "deepseek", "openai-like"]:
426
- chunk_content = "".join(
427
- c.delta.content
428
- for c in chunk.choices
429
- if c.delta.content
430
- )
431
- elif provider == "ollama":
432
- chunk_content = chunk["message"]["content"]
433
- else:
434
- continue
435
-
436
- if not chunk_content:
437
- continue
438
-
439
- str_output += chunk_content
440
- # print(str_output, "str_output")
441
- # Process the content character by character
442
- for char in chunk_content:
443
- buffer += char
444
-
445
- # Check for triple backticks
446
- if buffer.endswith("```"):
447
- if not in_code:
448
- # Start of code block
449
- in_code = True
450
- # Print everything before the backticks
451
- print(buffer[:-3], end="")
452
- buffer = ""
453
- code_buffer = ""
454
- else:
455
- # End of code block
456
- in_code = False
457
- # Remove the backticks from the end of the buffer
458
- buffer = buffer[:-3]
459
- # Add buffer to code content and render
460
- code_buffer += buffer
461
-
462
- # Check for and strip language tag
463
- if (
464
- "\n" in code_buffer
465
- and code_buffer.index("\n") < 15
466
- ):
467
- first_line, rest = code_buffer.split("\n", 1)
468
- if (
469
- first_line.strip()
470
- and not "```" in first_line
471
- ):
472
- code_buffer = rest
473
-
474
- # Render the code block
475
- render_code_block(code_buffer)
476
-
477
- # Reset buffers
478
- buffer = ""
479
- code_buffer = ""
480
- elif in_code:
481
- # Just add to code buffer
482
- code_buffer += char
483
- if len(buffer) >= 3: # Keep buffer small while in code
484
- buffer = buffer[-3:]
485
- else:
486
- # Regular text - print if buffer gets too large
487
- if len(buffer) > 100:
488
- print(buffer[:-3], end="")
489
- buffer = buffer[
490
- -3:
491
- ] # Keep last 3 chars to check for backticks
492
-
493
- # Handle any remaining content
494
- if in_code:
495
- render_code_block(code_buffer)
496
- else:
497
- print(buffer, end="")
498
-
499
- if str_output:
500
- output = str_output
501
- except:
502
- output = None
503
-
504
- print("\n")
505
-
506
- if isinstance(output, str):
507
- save_conversation_message(
508
- command_history,
509
- conversation_id,
510
- "assistant",
511
- output,
512
- wd=current_path,
513
- model=model,
514
- provider=provider,
515
- npc=npc_name,
516
- )
517
-
518
- # if there are attachments in most recent user sent message, save them
519
- # save_attachment_to_message(command_history, message_id, # file_path, attachment_name, attachment_type)
520
-
521
- if (
522
- result["output"] is not None
523
- and not user_input.startswith("/")
524
- and not isinstance(result, dict)
525
- ):
526
- print("final", result)
527
-
528
- except (KeyboardInterrupt, EOFError):
529
- if current_npc:
530
- print(f"\nExiting {current_npc.name} mode.")
531
- current_npc = None
532
- else:
533
- print("\nGoodbye!")
534
- break
535
-
536
-
537
- if __name__ == "__main__":
538
- main()