npcsh 1.1.4__py3-none-any.whl → 1.1.6__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 +470 -367
- npcsh/npc_team/corca_example.png +0 -0
- npcsh/npc_team/jinxs/{python_executor.jinx → code/python.jinx} +1 -1
- npcsh/npc_team/jinxs/{bash_executer.jinx → code/sh.jinx} +1 -2
- npcsh/npc_team/jinxs/code/sql.jinx +16 -0
- npcsh/npc_team/jinxs/modes/alicanto.jinx +88 -0
- npcsh/npc_team/jinxs/modes/corca.jinx +28 -0
- npcsh/npc_team/jinxs/modes/guac.jinx +46 -0
- npcsh/npc_team/jinxs/modes/plonk.jinx +57 -0
- npcsh/npc_team/jinxs/modes/pti.jinx +28 -0
- npcsh/npc_team/jinxs/modes/spool.jinx +40 -0
- npcsh/npc_team/jinxs/modes/wander.jinx +81 -0
- npcsh/npc_team/jinxs/modes/yap.jinx +25 -0
- npcsh/npc_team/jinxs/utils/breathe.jinx +20 -0
- npcsh/npc_team/jinxs/utils/core/build.jinx +65 -0
- npcsh/npc_team/jinxs/utils/core/compile.jinx +50 -0
- npcsh/npc_team/jinxs/utils/core/help.jinx +52 -0
- npcsh/npc_team/jinxs/utils/core/init.jinx +41 -0
- npcsh/npc_team/jinxs/utils/core/jinxs.jinx +32 -0
- npcsh/npc_team/jinxs/utils/core/set.jinx +40 -0
- npcsh/npc_team/jinxs/{edit_file.jinx → utils/edit_file.jinx} +1 -1
- npcsh/npc_team/jinxs/utils/flush.jinx +39 -0
- npcsh/npc_team/jinxs/utils/npc-studio.jinx +77 -0
- npcsh/npc_team/jinxs/utils/ots.jinx +61 -0
- npcsh/npc_team/jinxs/utils/plan.jinx +33 -0
- npcsh/npc_team/jinxs/utils/roll.jinx +66 -0
- npcsh/npc_team/jinxs/utils/sample.jinx +56 -0
- npcsh/npc_team/jinxs/utils/search.jinx +130 -0
- npcsh/npc_team/jinxs/utils/serve.jinx +29 -0
- npcsh/npc_team/jinxs/utils/sleep.jinx +116 -0
- npcsh/npc_team/jinxs/utils/trigger.jinx +36 -0
- npcsh/npc_team/jinxs/utils/vixynt.jinx +117 -0
- npcsh/npcsh.py +13 -11
- npcsh/routes.py +97 -1419
- npcsh-1.1.6.data/data/npcsh/npc_team/alicanto.jinx +88 -0
- npcsh-1.1.6.data/data/npcsh/npc_team/breathe.jinx +20 -0
- npcsh-1.1.6.data/data/npcsh/npc_team/build.jinx +65 -0
- npcsh-1.1.6.data/data/npcsh/npc_team/compile.jinx +50 -0
- npcsh-1.1.6.data/data/npcsh/npc_team/corca.jinx +28 -0
- npcsh-1.1.6.data/data/npcsh/npc_team/corca_example.png +0 -0
- {npcsh-1.1.4.data → npcsh-1.1.6.data}/data/npcsh/npc_team/edit_file.jinx +1 -1
- npcsh-1.1.6.data/data/npcsh/npc_team/flush.jinx +39 -0
- npcsh-1.1.6.data/data/npcsh/npc_team/guac.jinx +46 -0
- npcsh-1.1.6.data/data/npcsh/npc_team/help.jinx +52 -0
- npcsh-1.1.6.data/data/npcsh/npc_team/init.jinx +41 -0
- npcsh-1.1.6.data/data/npcsh/npc_team/jinxs.jinx +32 -0
- npcsh-1.1.6.data/data/npcsh/npc_team/npc-studio.jinx +77 -0
- npcsh-1.1.6.data/data/npcsh/npc_team/ots.jinx +61 -0
- npcsh-1.1.6.data/data/npcsh/npc_team/plan.jinx +33 -0
- npcsh-1.1.6.data/data/npcsh/npc_team/plonk.jinx +57 -0
- npcsh-1.1.6.data/data/npcsh/npc_team/pti.jinx +28 -0
- npcsh-1.1.4.data/data/npcsh/npc_team/python_executor.jinx → npcsh-1.1.6.data/data/npcsh/npc_team/python.jinx +1 -1
- npcsh-1.1.6.data/data/npcsh/npc_team/roll.jinx +66 -0
- npcsh-1.1.6.data/data/npcsh/npc_team/sample.jinx +56 -0
- npcsh-1.1.6.data/data/npcsh/npc_team/search.jinx +130 -0
- npcsh-1.1.6.data/data/npcsh/npc_team/serve.jinx +29 -0
- npcsh-1.1.6.data/data/npcsh/npc_team/set.jinx +40 -0
- npcsh-1.1.4.data/data/npcsh/npc_team/bash_executer.jinx → npcsh-1.1.6.data/data/npcsh/npc_team/sh.jinx +1 -2
- npcsh-1.1.6.data/data/npcsh/npc_team/sleep.jinx +116 -0
- npcsh-1.1.6.data/data/npcsh/npc_team/spool.jinx +40 -0
- npcsh-1.1.6.data/data/npcsh/npc_team/sql.jinx +16 -0
- npcsh-1.1.6.data/data/npcsh/npc_team/trigger.jinx +36 -0
- npcsh-1.1.6.data/data/npcsh/npc_team/vixynt.jinx +117 -0
- npcsh-1.1.6.data/data/npcsh/npc_team/wander.jinx +81 -0
- npcsh-1.1.6.data/data/npcsh/npc_team/yap.jinx +25 -0
- {npcsh-1.1.4.dist-info → npcsh-1.1.6.dist-info}/METADATA +1 -10
- npcsh-1.1.6.dist-info/RECORD +124 -0
- npcsh/npc_team/jinxs/image_generation.jinx +0 -29
- npcsh/npc_team/jinxs/internet_search.jinx +0 -31
- npcsh/npc_team/jinxs/kg_search.jinx +0 -43
- npcsh/npc_team/jinxs/memory_search.jinx +0 -36
- npcsh/npc_team/jinxs/screen_cap.jinx +0 -25
- npcsh-1.1.4.data/data/npcsh/npc_team/image_generation.jinx +0 -29
- npcsh-1.1.4.data/data/npcsh/npc_team/internet_search.jinx +0 -31
- npcsh-1.1.4.data/data/npcsh/npc_team/kg_search.jinx +0 -43
- npcsh-1.1.4.data/data/npcsh/npc_team/memory_search.jinx +0 -36
- npcsh-1.1.4.data/data/npcsh/npc_team/screen_cap.jinx +0 -25
- npcsh-1.1.4.dist-info/RECORD +0 -78
- {npcsh-1.1.4.data → npcsh-1.1.6.data}/data/npcsh/npc_team/alicanto.npc +0 -0
- {npcsh-1.1.4.data → npcsh-1.1.6.data}/data/npcsh/npc_team/alicanto.png +0 -0
- {npcsh-1.1.4.data → npcsh-1.1.6.data}/data/npcsh/npc_team/corca.npc +0 -0
- {npcsh-1.1.4.data → npcsh-1.1.6.data}/data/npcsh/npc_team/corca.png +0 -0
- {npcsh-1.1.4.data → npcsh-1.1.6.data}/data/npcsh/npc_team/foreman.npc +0 -0
- {npcsh-1.1.4.data → npcsh-1.1.6.data}/data/npcsh/npc_team/frederic.npc +0 -0
- {npcsh-1.1.4.data → npcsh-1.1.6.data}/data/npcsh/npc_team/frederic4.png +0 -0
- {npcsh-1.1.4.data → npcsh-1.1.6.data}/data/npcsh/npc_team/guac.png +0 -0
- {npcsh-1.1.4.data → npcsh-1.1.6.data}/data/npcsh/npc_team/kadiefa.npc +0 -0
- {npcsh-1.1.4.data → npcsh-1.1.6.data}/data/npcsh/npc_team/kadiefa.png +0 -0
- {npcsh-1.1.4.data → npcsh-1.1.6.data}/data/npcsh/npc_team/npcsh.ctx +0 -0
- {npcsh-1.1.4.data → npcsh-1.1.6.data}/data/npcsh/npc_team/npcsh_sibiji.png +0 -0
- {npcsh-1.1.4.data → npcsh-1.1.6.data}/data/npcsh/npc_team/plonk.npc +0 -0
- {npcsh-1.1.4.data → npcsh-1.1.6.data}/data/npcsh/npc_team/plonk.png +0 -0
- {npcsh-1.1.4.data → npcsh-1.1.6.data}/data/npcsh/npc_team/plonkjr.npc +0 -0
- {npcsh-1.1.4.data → npcsh-1.1.6.data}/data/npcsh/npc_team/plonkjr.png +0 -0
- {npcsh-1.1.4.data → npcsh-1.1.6.data}/data/npcsh/npc_team/sibiji.npc +0 -0
- {npcsh-1.1.4.data → npcsh-1.1.6.data}/data/npcsh/npc_team/sibiji.png +0 -0
- {npcsh-1.1.4.data → npcsh-1.1.6.data}/data/npcsh/npc_team/spool.png +0 -0
- {npcsh-1.1.4.data → npcsh-1.1.6.data}/data/npcsh/npc_team/yap.png +0 -0
- {npcsh-1.1.4.dist-info → npcsh-1.1.6.dist-info}/WHEEL +0 -0
- {npcsh-1.1.4.dist-info → npcsh-1.1.6.dist-info}/entry_points.txt +0 -0
- {npcsh-1.1.4.dist-info → npcsh-1.1.6.dist-info}/licenses/LICENSE +0 -0
- {npcsh-1.1.4.dist-info → npcsh-1.1.6.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
jinx_name: "plonk"
|
|
2
|
+
description: "Use vision model to interact with GUI. Usage: /plonk <task description>"
|
|
3
|
+
inputs:
|
|
4
|
+
- task_description: "" # Required task description for GUI interaction.
|
|
5
|
+
- vmodel: "" # Vision model to use. Defaults to NPCSH_VISION_MODEL or NPC's model.
|
|
6
|
+
- vprovider: "" # Vision model provider. Defaults to NPCSH_VISION_PROVIDER or NPC's provider.
|
|
7
|
+
steps:
|
|
8
|
+
- name: "execute_plonk"
|
|
9
|
+
engine: "python"
|
|
10
|
+
code: |
|
|
11
|
+
import traceback
|
|
12
|
+
from npcsh.plonk import execute_plonk_command, format_plonk_summary
|
|
13
|
+
# Assuming NPCSH_VISION_MODEL and NPCSH_VISION_PROVIDER are accessible
|
|
14
|
+
|
|
15
|
+
task_description = context.get('task_description')
|
|
16
|
+
vision_model = context.get('vmodel')
|
|
17
|
+
vision_provider = context.get('vprovider')
|
|
18
|
+
plonk_context = context.get('plonk_context') # Passed from original context
|
|
19
|
+
current_npc = context.get('npc')
|
|
20
|
+
output_messages = context.get('messages', [])
|
|
21
|
+
|
|
22
|
+
if not task_description or not task_description.strip():
|
|
23
|
+
context['output'] = "Usage: /plonk <task_description> [--vmodel model_name] [--vprovider provider_name]"
|
|
24
|
+
context['messages'] = output_messages
|
|
25
|
+
exit()
|
|
26
|
+
|
|
27
|
+
# Fallback for model/provider if not explicitly set in Jinx inputs
|
|
28
|
+
if not vision_model and current_npc and current_npc.model:
|
|
29
|
+
vision_model = current_npc.model
|
|
30
|
+
if not vision_provider and current_npc and current_npc.provider:
|
|
31
|
+
vision_provider = current_npc.provider
|
|
32
|
+
|
|
33
|
+
# Final fallbacks (these would ideally come from npcsh._state config)
|
|
34
|
+
if not vision_model: vision_model = "gemini-1.5-pro-vision" # Example default
|
|
35
|
+
if not vision_provider: vision_provider = "gemini" # Example default
|
|
36
|
+
|
|
37
|
+
try:
|
|
38
|
+
summary_data = execute_plonk_command(
|
|
39
|
+
request=task_description,
|
|
40
|
+
model=vision_model,
|
|
41
|
+
provider=vision_provider,
|
|
42
|
+
npc=current_npc,
|
|
43
|
+
plonk_context=plonk_context,
|
|
44
|
+
debug=True # Assuming debug is often desired for plonk
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
if summary_data and isinstance(summary_data, list):
|
|
48
|
+
output_report = format_plonk_summary(summary_data)
|
|
49
|
+
context['output'] = output_report
|
|
50
|
+
else:
|
|
51
|
+
context['output'] = "Plonk command did not complete within the maximum number of iterations."
|
|
52
|
+
|
|
53
|
+
except Exception as e:
|
|
54
|
+
traceback.print_exc()
|
|
55
|
+
context['output'] = f"Error executing plonk command: {e}"
|
|
56
|
+
|
|
57
|
+
context['messages'] = output_messages
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
jinx_name: "pti"
|
|
2
|
+
description: "Enter Pardon-The-Interruption mode for human-in-the-loop reasoning."
|
|
3
|
+
inputs:
|
|
4
|
+
- command_args: "" # The full command string or specific arguments for PTI mode.
|
|
5
|
+
steps:
|
|
6
|
+
- name: "enter_pti"
|
|
7
|
+
engine: "python"
|
|
8
|
+
code: |
|
|
9
|
+
import traceback
|
|
10
|
+
from npcsh.pti import enter_pti_mode
|
|
11
|
+
|
|
12
|
+
command_args = context.get('command_args', '') # The full command string from router
|
|
13
|
+
output_messages = context.get('messages', [])
|
|
14
|
+
|
|
15
|
+
try:
|
|
16
|
+
# enter_pti_mode likely expects the full command string for its own parsing
|
|
17
|
+
result = enter_pti_mode(command=command_args, **context)
|
|
18
|
+
|
|
19
|
+
if isinstance(result, dict):
|
|
20
|
+
context['output'] = result.get('output', 'Entered PTI mode.')
|
|
21
|
+
context['messages'] = result.get('messages', output_messages)
|
|
22
|
+
else:
|
|
23
|
+
context['output'] = str(result)
|
|
24
|
+
context['messages'] = output_messages
|
|
25
|
+
except Exception as e:
|
|
26
|
+
traceback.print_exc()
|
|
27
|
+
context['output'] = f"Error entering pti mode: {e}"
|
|
28
|
+
context['messages'] = output_messages
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
jinx_name: "roll"
|
|
2
|
+
description: "Generate a video from a text prompt."
|
|
3
|
+
inputs:
|
|
4
|
+
- prompt: "" # Required text prompt for video generation.
|
|
5
|
+
- num_frames: 125 # Number of frames for the video.
|
|
6
|
+
- width: 256 # Width of the video.
|
|
7
|
+
- height: 256 # Height of the video.
|
|
8
|
+
- output_path: "output.mp4" # Output file path for the video.
|
|
9
|
+
- vgmodel: "" # Video generation model to use. Defaults to NPCSH_VIDEO_GEN_MODEL or NPC's model.
|
|
10
|
+
- vgprovider: "" # Video generation provider to use. Defaults to NPCSH_VIDEO_GEN_PROVIDER or NPC's provider.
|
|
11
|
+
steps:
|
|
12
|
+
- name: "generate_video"
|
|
13
|
+
engine: "python"
|
|
14
|
+
code: |
|
|
15
|
+
import traceback
|
|
16
|
+
from npcpy.llm_funcs import gen_video
|
|
17
|
+
# Assuming NPCSH_VIDEO_GEN_MODEL and NPCSH_VIDEO_GEN_PROVIDER are accessible
|
|
18
|
+
|
|
19
|
+
prompt = context.get('prompt')
|
|
20
|
+
num_frames = int(context.get('num_frames', 125)) # Ensure int type
|
|
21
|
+
width = int(context.get('width', 256)) # Ensure int type
|
|
22
|
+
height = int(context.get('height', 256)) # Ensure int type
|
|
23
|
+
output_path = context.get('output_path')
|
|
24
|
+
video_gen_model = context.get('vgmodel')
|
|
25
|
+
video_gen_provider = context.get('vgprovider')
|
|
26
|
+
output_messages = context.get('messages', [])
|
|
27
|
+
current_npc = context.get('npc')
|
|
28
|
+
|
|
29
|
+
if not prompt or not prompt.strip():
|
|
30
|
+
context['output'] = "Usage: /roll <your prompt>"
|
|
31
|
+
context['messages'] = output_messages
|
|
32
|
+
exit()
|
|
33
|
+
|
|
34
|
+
# Fallback for model/provider if not explicitly set in Jinx inputs
|
|
35
|
+
if not video_gen_model and current_npc and current_npc.model:
|
|
36
|
+
video_gen_model = current_npc.model
|
|
37
|
+
if not video_gen_provider and current_npc and current_npc.provider:
|
|
38
|
+
video_gen_provider = current_npc.provider
|
|
39
|
+
|
|
40
|
+
# Final fallbacks (these would ideally come from npcsh._state config)
|
|
41
|
+
if not video_gen_model: video_gen_model = "stable-video-diffusion" # Example default
|
|
42
|
+
if not video_gen_provider: video_gen_provider = "diffusers" # Example default
|
|
43
|
+
|
|
44
|
+
try:
|
|
45
|
+
result = gen_video(
|
|
46
|
+
prompt=prompt,
|
|
47
|
+
model=video_gen_model,
|
|
48
|
+
provider=video_gen_provider,
|
|
49
|
+
npc=current_npc,
|
|
50
|
+
num_frames=num_frames,
|
|
51
|
+
width=width,
|
|
52
|
+
height=height,
|
|
53
|
+
output_path=output_path,
|
|
54
|
+
**context.get('api_kwargs', {}) # Assuming api_kwargs might be passed
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
if isinstance(result, dict):
|
|
58
|
+
context['output'] = result.get('output', 'Video generated.')
|
|
59
|
+
context['messages'] = result.get('messages', output_messages)
|
|
60
|
+
else:
|
|
61
|
+
context['output'] = str(result)
|
|
62
|
+
context['messages'] = output_messages
|
|
63
|
+
except Exception as e:
|
|
64
|
+
traceback.print_exc()
|
|
65
|
+
context['output'] = f"Error generating video: {e}"
|
|
66
|
+
context['messages'] = output_messages
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
jinx_name: "sample"
|
|
2
|
+
description: "Send a prompt directly to the LLM."
|
|
3
|
+
inputs:
|
|
4
|
+
- prompt: "" # Required text prompt to send to the LLM.
|
|
5
|
+
- model: "" # LLM model to use. Defaults to NPC's model.
|
|
6
|
+
- provider: "" # LLM provider to use. Defaults to NPC's provider.
|
|
7
|
+
steps:
|
|
8
|
+
- name: "send_prompt_to_llm"
|
|
9
|
+
engine: "python"
|
|
10
|
+
code: |
|
|
11
|
+
import traceback
|
|
12
|
+
from npcpy.llm_funcs import get_llm_response
|
|
13
|
+
|
|
14
|
+
prompt = context.get('prompt')
|
|
15
|
+
llm_model = context.get('model')
|
|
16
|
+
llm_provider = context.get('provider')
|
|
17
|
+
output_messages = context.get('messages', [])
|
|
18
|
+
current_npc = context.get('npc')
|
|
19
|
+
|
|
20
|
+
if not prompt or not prompt.strip():
|
|
21
|
+
context['output'] = "Usage: /sample <your prompt> [-m --model] model [-p --provider] provider"
|
|
22
|
+
context['messages'] = output_messages
|
|
23
|
+
exit()
|
|
24
|
+
|
|
25
|
+
# Fallback for model/provider if not explicitly set in Jinx inputs
|
|
26
|
+
if not llm_model and current_npc and current_npc.model:
|
|
27
|
+
llm_model = current_npc.model
|
|
28
|
+
if not llm_provider and current_npc and current_npc.provider:
|
|
29
|
+
llm_provider = current_npc.provider
|
|
30
|
+
|
|
31
|
+
# Final fallbacks (these would ideally come from npcsh._state config)
|
|
32
|
+
if not llm_model: llm_model = "gemini-1.5-pro" # Example default
|
|
33
|
+
if not llm_provider: llm_provider = "gemini" # Example default
|
|
34
|
+
|
|
35
|
+
try:
|
|
36
|
+
result = get_llm_response(
|
|
37
|
+
prompt=prompt,
|
|
38
|
+
model=llm_model,
|
|
39
|
+
provider=llm_provider,
|
|
40
|
+
npc=current_npc,
|
|
41
|
+
**{k:v for k,v in context.items() if k not in ['messages', 'prompt', 'model', 'provider']} # Pass other context
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
if isinstance(result, dict):
|
|
45
|
+
context['output'] = result.get('response')
|
|
46
|
+
context['messages'] = result.get('messages', output_messages)
|
|
47
|
+
context['model'] = llm_model
|
|
48
|
+
context['provider'] = llm_provider
|
|
49
|
+
else:
|
|
50
|
+
context['output'] = str(result)
|
|
51
|
+
context['messages'] = output_messages
|
|
52
|
+
|
|
53
|
+
except Exception as e:
|
|
54
|
+
traceback.print_exc()
|
|
55
|
+
context['output'] = f"Error sampling LLM: {e}"
|
|
56
|
+
context['messages'] = output_messages
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
jinx_name: "search"
|
|
2
|
+
description: >
|
|
3
|
+
Executes a search across various sources.
|
|
4
|
+
Usage:
|
|
5
|
+
/search <query> (Default: Web Search)
|
|
6
|
+
/search --memory <query> (Search approved memories)
|
|
7
|
+
/search --kg <query> (Search the knowledge graph)
|
|
8
|
+
/search --rag [-f <paths>] <query> (Execute a RAG search)
|
|
9
|
+
/search --brainblast <query> (Advanced history search)
|
|
10
|
+
inputs:
|
|
11
|
+
- query: ""
|
|
12
|
+
- memory: false
|
|
13
|
+
- kg: false
|
|
14
|
+
- rag: false
|
|
15
|
+
- brainblast: false
|
|
16
|
+
- file_paths: ""
|
|
17
|
+
- history_db_path: "~/npcsh_history.db"
|
|
18
|
+
- vector_db_path: "~/npcsh_chroma.db"
|
|
19
|
+
- sprovider: ""
|
|
20
|
+
- emodel: ""
|
|
21
|
+
- eprovider: ""
|
|
22
|
+
steps:
|
|
23
|
+
- name: "execute_unified_search"
|
|
24
|
+
engine: "python"
|
|
25
|
+
code: |
|
|
26
|
+
import os
|
|
27
|
+
import traceback
|
|
28
|
+
|
|
29
|
+
# Access query from context
|
|
30
|
+
query = context.get('query')
|
|
31
|
+
if not query or not query.strip():
|
|
32
|
+
context['output'] = "Usage: /search [--memory|--kg|--rag|--brainblast] <query>"
|
|
33
|
+
else:
|
|
34
|
+
# state is available as a GLOBAL variable (from extra_globals)
|
|
35
|
+
# Access it directly, not from context
|
|
36
|
+
try:
|
|
37
|
+
current_state = state # This should work now
|
|
38
|
+
except NameError:
|
|
39
|
+
context['output'] = "Error: Shell state not available in jinx context"
|
|
40
|
+
raise
|
|
41
|
+
|
|
42
|
+
current_npc = current_state.npc
|
|
43
|
+
current_team = current_state.team
|
|
44
|
+
|
|
45
|
+
npc_name = getattr(current_npc, 'name', '__none__') if current_npc else '__none__'
|
|
46
|
+
team_name = getattr(current_team, 'name', '__none__') if current_team else '__none__'
|
|
47
|
+
current_path = os.getcwd()
|
|
48
|
+
db_path = os.path.expanduser(context.get("history_db_path"))
|
|
49
|
+
|
|
50
|
+
try:
|
|
51
|
+
cmd_history = CommandHistory(db_path)
|
|
52
|
+
|
|
53
|
+
if context.get('memory'):
|
|
54
|
+
memories = get_relevant_memories(
|
|
55
|
+
command_history=cmd_history,
|
|
56
|
+
npc_name=npc_name,
|
|
57
|
+
team_name=team_name,
|
|
58
|
+
path=current_path,
|
|
59
|
+
query=query,
|
|
60
|
+
max_memories=10,
|
|
61
|
+
state=current_state # Pass the state object
|
|
62
|
+
)
|
|
63
|
+
print(memories)
|
|
64
|
+
|
|
65
|
+
if not memories:
|
|
66
|
+
output = f"No memories found for query: '{query}'"
|
|
67
|
+
else:
|
|
68
|
+
output = f"Found {len(memories)} memories:\n\n" + "\n".join(
|
|
69
|
+
f"{i}. [{mem.get('timestamp', 'unknown')}] {mem.get('final_memory') or mem.get('initial_memory')}"
|
|
70
|
+
for i, mem in enumerate(memories, 1)
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
elif context.get('kg'):
|
|
74
|
+
facts = search_kg_facts(
|
|
75
|
+
cmd_history,
|
|
76
|
+
npc_name,
|
|
77
|
+
team_name,
|
|
78
|
+
current_path,
|
|
79
|
+
query
|
|
80
|
+
)
|
|
81
|
+
print(facts)
|
|
82
|
+
|
|
83
|
+
if not facts:
|
|
84
|
+
output = f"No KG facts found for query: '{query}'"
|
|
85
|
+
else:
|
|
86
|
+
output = f"Found {len(facts)} KG facts:\n\n" + "\n".join(
|
|
87
|
+
f"{i}. {fact.get('statement')}" for i, fact in enumerate(facts, 1)
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
elif context.get('rag'):
|
|
91
|
+
file_paths_str = context.get('file_paths', '')
|
|
92
|
+
file_paths = [os.path.abspath(os.path.expanduser(p.strip())) for p in file_paths_str.split(',') if p.strip()]
|
|
93
|
+
emodel = context.get('emodel') or current_state.embedding_model
|
|
94
|
+
eprovider = context.get('eprovider') or current_state.embedding_provider
|
|
95
|
+
|
|
96
|
+
file_contents = []
|
|
97
|
+
for path in file_paths:
|
|
98
|
+
chunks = load_file_contents(path)
|
|
99
|
+
basename = os.path.basename(path)
|
|
100
|
+
file_contents.extend([f"{basename}: {chunk}" for chunk in chunks])
|
|
101
|
+
|
|
102
|
+
result = execute_rag_command(
|
|
103
|
+
command=query,
|
|
104
|
+
vector_db_path=os.path.expanduser(context.get('vector_db_path')),
|
|
105
|
+
embedding_model=emodel,
|
|
106
|
+
embedding_provider=eprovider,
|
|
107
|
+
file_contents=file_contents or None
|
|
108
|
+
)
|
|
109
|
+
print(result)
|
|
110
|
+
output = result.get('response', 'No response from RAG.')
|
|
111
|
+
|
|
112
|
+
elif context.get('brainblast'):
|
|
113
|
+
result = execute_brainblast_command(
|
|
114
|
+
command=query,
|
|
115
|
+
command_history=cmd_history,
|
|
116
|
+
**context
|
|
117
|
+
)
|
|
118
|
+
print(result)
|
|
119
|
+
output = result.get('output', 'Brainblast search executed.')
|
|
120
|
+
|
|
121
|
+
else:
|
|
122
|
+
# Default to web search
|
|
123
|
+
provider = context.get('sprovider') or current_state.search_provider
|
|
124
|
+
results = search_web(query, provider=provider)
|
|
125
|
+
output = "\n".join([f"- {res}" for res in results]) if results else "No web results found."
|
|
126
|
+
|
|
127
|
+
except Exception as e:
|
|
128
|
+
output = f"An error occurred in the search jinx: {e}\n{traceback.format_exc()}"
|
|
129
|
+
|
|
130
|
+
context['output'] = output
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
jinx_name: "serve"
|
|
2
|
+
description: "Serve an NPC Team"
|
|
3
|
+
inputs:
|
|
4
|
+
- port: 5337 # The port to run the Flask server on.
|
|
5
|
+
- cors: "" # Comma-separated CORS origins.
|
|
6
|
+
steps:
|
|
7
|
+
- name: "start_flask_server"
|
|
8
|
+
engine: "python"
|
|
9
|
+
code: |
|
|
10
|
+
from npcpy.serve import start_flask_server
|
|
11
|
+
|
|
12
|
+
port = context.get('port')
|
|
13
|
+
cors_str = context.get('cors')
|
|
14
|
+
output_messages = context.get('messages', [])
|
|
15
|
+
|
|
16
|
+
cors_origins = None
|
|
17
|
+
if cors_str and cors_str.strip():
|
|
18
|
+
cors_origins = [origin.strip() for origin in cors_str.split(",")]
|
|
19
|
+
|
|
20
|
+
# start_flask_server blocks, so this will hold the Jinx until the server is stopped.
|
|
21
|
+
# In a real-world scenario, you might want to run this in a separate process
|
|
22
|
+
# or have a non-blocking server start.
|
|
23
|
+
start_flask_server(
|
|
24
|
+
port=int(port), # Ensure port is an integer
|
|
25
|
+
cors_origins=cors_origins,
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
context['output'] = "NPC Team server started. Execution of this jinx will pause until the server is stopped."
|
|
29
|
+
context['messages'] = output_messages
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
jinx_name: "set"
|
|
2
|
+
description: "Set configuration values"
|
|
3
|
+
inputs:
|
|
4
|
+
- key: "" # The configuration key to set.
|
|
5
|
+
- value: "" # The value to set for the configuration key.
|
|
6
|
+
steps:
|
|
7
|
+
- name: "set_config_value"
|
|
8
|
+
engine: "python"
|
|
9
|
+
code: |
|
|
10
|
+
import traceback
|
|
11
|
+
# Assuming set_npcsh_config_value is accessible
|
|
12
|
+
try:
|
|
13
|
+
from npcsh._state import set_npcsh_config_value
|
|
14
|
+
except ImportError:
|
|
15
|
+
def set_npcsh_config_value(key, value):
|
|
16
|
+
print(f"Mock: Setting config '{key}' to '{value}'")
|
|
17
|
+
# In a real scenario, this might write to a config file or global state
|
|
18
|
+
pass
|
|
19
|
+
|
|
20
|
+
key = context.get('key')
|
|
21
|
+
value = context.get('value')
|
|
22
|
+
output_messages = context.get('messages', [])
|
|
23
|
+
|
|
24
|
+
output_result = ""
|
|
25
|
+
if not key or not value:
|
|
26
|
+
context['output'] = "Usage: /set <key>=<value>"
|
|
27
|
+
context['messages'] = output_messages
|
|
28
|
+
exit()
|
|
29
|
+
|
|
30
|
+
try:
|
|
31
|
+
set_npcsh_config_value(key, value)
|
|
32
|
+
output_result = f"Configuration value '{key}' set."
|
|
33
|
+
except NameError:
|
|
34
|
+
output_result = "Set function (set_npcsh_config_value) not available."
|
|
35
|
+
except Exception as e:
|
|
36
|
+
traceback.print_exc()
|
|
37
|
+
output_result = f"Error setting configuration '{key}': {e}"
|
|
38
|
+
|
|
39
|
+
context['output'] = output_result
|
|
40
|
+
context['messages'] = output_messages
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
jinx_name:
|
|
1
|
+
jinx_name: sh
|
|
2
2
|
description: Execute bash queries. Should be used to grep for file contents, list directories, explore information to answer user questions more practically.
|
|
3
3
|
inputs:
|
|
4
4
|
- bash_command
|
|
5
|
-
- user_request
|
|
6
5
|
steps:
|
|
7
6
|
- engine: python
|
|
8
7
|
code: |
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
jinx_name: "sleep"
|
|
2
|
+
description: "Evolve knowledge graph. Use --dream to also run creative synthesis."
|
|
3
|
+
inputs:
|
|
4
|
+
- dream: False # Boolean flag to also run creative synthesis (dream process).
|
|
5
|
+
- ops: "" # Comma-separated list of operations to configure KG sleep process.
|
|
6
|
+
- model: "" # LLM model to use for KG evolution. Defaults to NPC's model.
|
|
7
|
+
- provider: "" # LLM provider to use for KG evolution. Defaults to NPC's provider.
|
|
8
|
+
steps:
|
|
9
|
+
- name: "evolve_knowledge_graph"
|
|
10
|
+
engine: "python"
|
|
11
|
+
code: |
|
|
12
|
+
import os
|
|
13
|
+
import traceback
|
|
14
|
+
from npcpy.memory.command_history import CommandHistory, load_kg_from_db, save_kg_to_db
|
|
15
|
+
from npcpy.memory.knowledge_graph import kg_sleep_process, kg_dream_process
|
|
16
|
+
# Assuming render_markdown is available if needed for logging progress
|
|
17
|
+
|
|
18
|
+
is_dreaming = context.get('dream')
|
|
19
|
+
operations_str = context.get('ops')
|
|
20
|
+
llm_model = context.get('model')
|
|
21
|
+
llm_provider = context.get('provider')
|
|
22
|
+
output_messages = context.get('messages', [])
|
|
23
|
+
current_npc = context.get('npc')
|
|
24
|
+
current_team = context.get('team')
|
|
25
|
+
|
|
26
|
+
operations_config = None
|
|
27
|
+
if operations_str and isinstance(operations_str, str):
|
|
28
|
+
operations_config = [op.strip() for op in operations_str.split(',')]
|
|
29
|
+
|
|
30
|
+
# Fallback for model/provider if not explicitly set in Jinx inputs
|
|
31
|
+
if not llm_model and current_npc and current_npc.model:
|
|
32
|
+
llm_model = current_npc.model
|
|
33
|
+
if not llm_provider and current_npc and current_npc.provider:
|
|
34
|
+
llm_provider = current_npc.provider
|
|
35
|
+
|
|
36
|
+
# Final fallbacks (these would ideally come from npcsh._state config)
|
|
37
|
+
if not llm_model: llm_model = "gemini-1.5-pro" # Example default
|
|
38
|
+
if not llm_provider: llm_provider = "gemini" # Example default
|
|
39
|
+
|
|
40
|
+
team_name = current_team.name if current_team else "__none__"
|
|
41
|
+
npc_name = current_npc.name if isinstance(current_npc, type(None).__class__) else "__none__"
|
|
42
|
+
current_path = os.getcwd()
|
|
43
|
+
scope_str = f"Team: '{team_name}', NPC: '{npc_name}', Path: '{current_path}'"
|
|
44
|
+
|
|
45
|
+
# Assume render_markdown exists
|
|
46
|
+
# render_markdown(f"- Checking knowledge graph for scope: {scope_str}")
|
|
47
|
+
|
|
48
|
+
command_history = None
|
|
49
|
+
try:
|
|
50
|
+
db_path = os.getenv("NPCSH_DB_PATH", os.path.expanduser("~/npcsh_history.db"))
|
|
51
|
+
command_history = CommandHistory(db_path)
|
|
52
|
+
engine = command_history.engine
|
|
53
|
+
except Exception as e:
|
|
54
|
+
context['output'] = f"Error connecting to history database for KG access: {e}"
|
|
55
|
+
context['messages'] = output_messages
|
|
56
|
+
exit()
|
|
57
|
+
|
|
58
|
+
output_result = ""
|
|
59
|
+
try:
|
|
60
|
+
current_kg = load_kg_from_db(engine, team_name, npc_name, current_path)
|
|
61
|
+
|
|
62
|
+
if not current_kg or not current_kg.get('facts'):
|
|
63
|
+
output_msg = f"Knowledge graph for the current scope is empty. Nothing to process.\n"
|
|
64
|
+
output_msg += f" - Scope Checked: {scope_str}\n\n"
|
|
65
|
+
output_msg += "**Hint:** Have a conversation or run some commands first to build up knowledge in this specific context. The KG is unique to each combination of Team, NPC, and directory."
|
|
66
|
+
context['output'] = output_msg
|
|
67
|
+
context['messages'] = output_messages
|
|
68
|
+
exit()
|
|
69
|
+
|
|
70
|
+
original_facts = len(current_kg.get('facts', []))
|
|
71
|
+
original_concepts = len(current_kg.get('concepts', []))
|
|
72
|
+
|
|
73
|
+
process_type = "Sleep"
|
|
74
|
+
ops_display = f"with operations: {operations_config}" if operations_config else "with random operations"
|
|
75
|
+
# render_markdown(f"- Initiating sleep process {ops_display}")
|
|
76
|
+
|
|
77
|
+
evolved_kg, _ = kg_sleep_process(
|
|
78
|
+
existing_kg=current_kg,
|
|
79
|
+
model=llm_model,
|
|
80
|
+
provider=llm_provider,
|
|
81
|
+
npc=current_npc,
|
|
82
|
+
operations_config=operations_config
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
if is_dreaming:
|
|
86
|
+
process_type += " & Dream"
|
|
87
|
+
# render_markdown(f"- Initiating dream process on the evolved KG...")
|
|
88
|
+
evolved_kg, _ = kg_dream_process(
|
|
89
|
+
existing_kg=evolved_kg,
|
|
90
|
+
model=llm_model,
|
|
91
|
+
provider=llm_provider,
|
|
92
|
+
npc=current_npc
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
save_kg_to_db(engine, evolved_kg, team_name, npc_name, current_path) # Changed conn to engine
|
|
96
|
+
|
|
97
|
+
new_facts = len(evolved_kg.get('facts', []))
|
|
98
|
+
new_concepts = len(evolved_kg.get('concepts', []))
|
|
99
|
+
|
|
100
|
+
output_result = f"{process_type} process complete.\n"
|
|
101
|
+
output_result += f"- Facts: {original_facts} -> {new_facts} ({new_facts - original_facts:+})\n"
|
|
102
|
+
output_result += f"- Concepts: {original_concepts} -> {new_concepts} ({new_concepts - original_concepts:+})"
|
|
103
|
+
|
|
104
|
+
print('Evolved facts:', evolved_kg.get('facts'))
|
|
105
|
+
print('Evolved concepts:', evolved_kg.get('concepts'))
|
|
106
|
+
|
|
107
|
+
context['output'] = output_result
|
|
108
|
+
context['messages'] = output_messages
|
|
109
|
+
|
|
110
|
+
except Exception as e:
|
|
111
|
+
traceback.print_exc()
|
|
112
|
+
context['output'] = f"Error during KG evolution process: {e}"
|
|
113
|
+
context['messages'] = output_messages
|
|
114
|
+
finally:
|
|
115
|
+
if command_history: # Check if it was successfully initialized
|
|
116
|
+
command_history.close()
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
jinx_name: "spool"
|
|
2
|
+
description: "Enter interactive chat (spool) mode"
|
|
3
|
+
inputs: [] # Spool mode typically takes its parameters directly from the environment/kwargs
|
|
4
|
+
steps:
|
|
5
|
+
- name: "enter_spool"
|
|
6
|
+
engine: "python"
|
|
7
|
+
code: |
|
|
8
|
+
import traceback
|
|
9
|
+
from npcpy.npc_compiler import NPC, Team
|
|
10
|
+
from npcsh.spool import enter_spool_mode
|
|
11
|
+
|
|
12
|
+
output_messages = context.get('messages', [])
|
|
13
|
+
current_npc = context.get('npc')
|
|
14
|
+
current_team = context.get('team')
|
|
15
|
+
|
|
16
|
+
try:
|
|
17
|
+
# Handle potential string NPC name if passed from CLI
|
|
18
|
+
if isinstance(current_npc, str) and current_team:
|
|
19
|
+
npc_name = current_npc
|
|
20
|
+
if npc_name in current_team.npcs:
|
|
21
|
+
current_npc = current_team.npcs[npc_name]
|
|
22
|
+
else:
|
|
23
|
+
context['output'] = f"Error: NPC '{npc_name}' not found in team. Available NPCs: {', '.join(current_team.npcs.keys())}"
|
|
24
|
+
context['messages'] = output_messages
|
|
25
|
+
exit()
|
|
26
|
+
context['npc'] = current_npc # Ensure the NPC object is updated in context
|
|
27
|
+
|
|
28
|
+
result = enter_spool_mode(**context) # Pass all context as kwargs
|
|
29
|
+
|
|
30
|
+
if isinstance(result, dict):
|
|
31
|
+
context['output'] = result.get('output', 'Exited Spool Mode.')
|
|
32
|
+
context['messages'] = result.get('messages', output_messages)
|
|
33
|
+
else:
|
|
34
|
+
context['output'] = str(result)
|
|
35
|
+
context['messages'] = output_messages
|
|
36
|
+
|
|
37
|
+
except Exception as e:
|
|
38
|
+
traceback.print_exc()
|
|
39
|
+
context['output'] = f"Error entering spool mode: {e}"
|
|
40
|
+
context['messages'] = output_messages
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
jinx_name: sql_executor
|
|
2
|
+
description: Execute queries on the ~/npcsh_history.db to pull data. The database
|
|
3
|
+
contains only information about conversations and other user-provided data. It does
|
|
4
|
+
not store any information about individual files. Avoid using percent signs unless absolutely necessary.
|
|
5
|
+
inputs:
|
|
6
|
+
- sql_query
|
|
7
|
+
steps:
|
|
8
|
+
- engine: python
|
|
9
|
+
code: |
|
|
10
|
+
import pandas as pd
|
|
11
|
+
query = "{{ sql_query }}"
|
|
12
|
+
try:
|
|
13
|
+
df = pd.read_sql_query(query, npc.db_conn)
|
|
14
|
+
except Exception as e:
|
|
15
|
+
df = pd.DataFrame({'Error': [str(e)]})
|
|
16
|
+
output = df.to_string()
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
jinx_name: "trigger"
|
|
2
|
+
description: "Execute a trigger command"
|
|
3
|
+
inputs:
|
|
4
|
+
- trigger_description: "" # Required description of the trigger to execute.
|
|
5
|
+
steps:
|
|
6
|
+
- name: "execute_trigger"
|
|
7
|
+
engine: "python"
|
|
8
|
+
code: |
|
|
9
|
+
import traceback
|
|
10
|
+
from npcpy.work.trigger import execute_trigger_command
|
|
11
|
+
|
|
12
|
+
trigger_description = context.get('trigger_description')
|
|
13
|
+
output_messages = context.get('messages', [])
|
|
14
|
+
|
|
15
|
+
if not trigger_description or not trigger_description.strip():
|
|
16
|
+
context['output'] = "Usage: /trigger <trigger_description>"
|
|
17
|
+
context['messages'] = output_messages
|
|
18
|
+
exit()
|
|
19
|
+
|
|
20
|
+
try:
|
|
21
|
+
# Pass all current context as kwargs to execute_trigger_command
|
|
22
|
+
result = execute_trigger_command(command=trigger_description, **context)
|
|
23
|
+
|
|
24
|
+
if isinstance(result, dict):
|
|
25
|
+
context['output'] = result.get('output', 'Trigger executed.')
|
|
26
|
+
context['messages'] = result.get('messages', output_messages)
|
|
27
|
+
else:
|
|
28
|
+
context['output'] = str(result)
|
|
29
|
+
context['messages'] = output_messages
|
|
30
|
+
except NameError:
|
|
31
|
+
context['output'] = "Trigger function (execute_trigger_command) not available."
|
|
32
|
+
context['messages'] = output_messages
|
|
33
|
+
except Exception as e:
|
|
34
|
+
traceback.print_exc()
|
|
35
|
+
context['output'] = f"Error executing trigger: {e}"
|
|
36
|
+
context['messages'] = output_messages
|