npcsh 1.1.17__py3-none-any.whl → 1.1.18__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 +114 -91
- npcsh/alicanto.py +2 -2
- npcsh/benchmark/__init__.py +8 -2
- npcsh/benchmark/npcsh_agent.py +46 -12
- npcsh/benchmark/runner.py +85 -43
- npcsh/benchmark/templates/install-npcsh.sh.j2 +35 -0
- npcsh/build.py +2 -4
- npcsh/completion.py +2 -6
- npcsh/config.py +1 -3
- npcsh/conversation_viewer.py +389 -0
- npcsh/corca.py +0 -1
- npcsh/execution.py +0 -1
- npcsh/guac.py +0 -1
- npcsh/mcp_helpers.py +2 -3
- npcsh/mcp_server.py +5 -10
- npcsh/npc.py +10 -11
- npcsh/npc_team/jinxs/bin/benchmark.jinx +1 -1
- npcsh/npc_team/jinxs/lib/core/search/db_search.jinx +321 -17
- npcsh/npc_team/jinxs/lib/core/search/file_search.jinx +312 -67
- npcsh/npc_team/jinxs/lib/core/search/kg_search.jinx +366 -44
- npcsh/npc_team/jinxs/lib/core/search/mem_review.jinx +73 -0
- npcsh/npc_team/jinxs/lib/core/search/mem_search.jinx +328 -20
- npcsh/npc_team/jinxs/lib/core/search/web_search.jinx +242 -10
- npcsh/npc_team/jinxs/lib/core/sleep.jinx +22 -11
- npcsh/npc_team/jinxs/lib/core/sql.jinx +10 -6
- npcsh/npc_team/jinxs/lib/research/paper_search.jinx +387 -76
- npcsh/npc_team/jinxs/lib/research/semantic_scholar.jinx +372 -55
- npcsh/npc_team/jinxs/lib/utils/jinxs.jinx +299 -144
- npcsh/npc_team/jinxs/modes/alicanto.jinx +356 -0
- npcsh/npc_team/jinxs/modes/arxiv.jinx +720 -0
- npcsh/npc_team/jinxs/modes/corca.jinx +430 -0
- npcsh/npc_team/jinxs/modes/guac.jinx +544 -0
- npcsh/npc_team/jinxs/modes/plonk.jinx +379 -0
- npcsh/npc_team/jinxs/modes/pti.jinx +357 -0
- npcsh/npc_team/jinxs/modes/reattach.jinx +291 -0
- npcsh/npc_team/jinxs/modes/spool.jinx +350 -0
- npcsh/npc_team/jinxs/modes/wander.jinx +455 -0
- npcsh/npc_team/jinxs/{bin → modes}/yap.jinx +13 -7
- npcsh/npcsh.py +7 -4
- npcsh/plonk.py +0 -1
- npcsh/pti.py +0 -1
- npcsh/routes.py +1 -3
- npcsh/spool.py +0 -1
- npcsh/ui.py +0 -1
- npcsh/wander.py +0 -1
- npcsh/yap.py +0 -1
- npcsh-1.1.18.data/data/npcsh/npc_team/alicanto.jinx +356 -0
- npcsh-1.1.18.data/data/npcsh/npc_team/arxiv.jinx +720 -0
- {npcsh-1.1.17.data → npcsh-1.1.18.data}/data/npcsh/npc_team/benchmark.jinx +1 -1
- npcsh-1.1.18.data/data/npcsh/npc_team/corca.jinx +430 -0
- npcsh-1.1.18.data/data/npcsh/npc_team/db_search.jinx +348 -0
- npcsh-1.1.18.data/data/npcsh/npc_team/file_search.jinx +339 -0
- npcsh-1.1.18.data/data/npcsh/npc_team/guac.jinx +544 -0
- npcsh-1.1.18.data/data/npcsh/npc_team/jinxs.jinx +331 -0
- npcsh-1.1.18.data/data/npcsh/npc_team/kg_search.jinx +418 -0
- npcsh-1.1.18.data/data/npcsh/npc_team/mem_review.jinx +73 -0
- npcsh-1.1.18.data/data/npcsh/npc_team/mem_search.jinx +388 -0
- npcsh-1.1.18.data/data/npcsh/npc_team/paper_search.jinx +412 -0
- npcsh-1.1.18.data/data/npcsh/npc_team/plonk.jinx +379 -0
- npcsh-1.1.18.data/data/npcsh/npc_team/pti.jinx +357 -0
- npcsh-1.1.18.data/data/npcsh/npc_team/reattach.jinx +291 -0
- npcsh-1.1.18.data/data/npcsh/npc_team/semantic_scholar.jinx +386 -0
- {npcsh-1.1.17.data → npcsh-1.1.18.data}/data/npcsh/npc_team/sleep.jinx +22 -11
- npcsh-1.1.18.data/data/npcsh/npc_team/spool.jinx +350 -0
- npcsh-1.1.18.data/data/npcsh/npc_team/sql.jinx +20 -0
- npcsh-1.1.18.data/data/npcsh/npc_team/wander.jinx +455 -0
- npcsh-1.1.18.data/data/npcsh/npc_team/web_search.jinx +283 -0
- {npcsh-1.1.17.data → npcsh-1.1.18.data}/data/npcsh/npc_team/yap.jinx +13 -7
- {npcsh-1.1.17.dist-info → npcsh-1.1.18.dist-info}/METADATA +90 -1
- npcsh-1.1.18.dist-info/RECORD +235 -0
- {npcsh-1.1.17.dist-info → npcsh-1.1.18.dist-info}/WHEEL +1 -1
- {npcsh-1.1.17.dist-info → npcsh-1.1.18.dist-info}/entry_points.txt +0 -3
- npcsh/npc_team/jinxs/bin/spool.jinx +0 -161
- npcsh/npc_team/jinxs/bin/wander.jinx +0 -242
- npcsh/npc_team/jinxs/lib/research/arxiv.jinx +0 -76
- npcsh-1.1.17.data/data/npcsh/npc_team/arxiv.jinx +0 -76
- npcsh-1.1.17.data/data/npcsh/npc_team/db_search.jinx +0 -44
- npcsh-1.1.17.data/data/npcsh/npc_team/file_search.jinx +0 -94
- npcsh-1.1.17.data/data/npcsh/npc_team/jinxs.jinx +0 -176
- npcsh-1.1.17.data/data/npcsh/npc_team/kg_search.jinx +0 -96
- npcsh-1.1.17.data/data/npcsh/npc_team/mem_search.jinx +0 -80
- npcsh-1.1.17.data/data/npcsh/npc_team/paper_search.jinx +0 -101
- npcsh-1.1.17.data/data/npcsh/npc_team/semantic_scholar.jinx +0 -69
- npcsh-1.1.17.data/data/npcsh/npc_team/spool.jinx +0 -161
- npcsh-1.1.17.data/data/npcsh/npc_team/sql.jinx +0 -16
- npcsh-1.1.17.data/data/npcsh/npc_team/wander.jinx +0 -242
- npcsh-1.1.17.data/data/npcsh/npc_team/web_search.jinx +0 -51
- npcsh-1.1.17.dist-info/RECORD +0 -219
- {npcsh-1.1.17.data → npcsh-1.1.18.data}/data/npcsh/npc_team/add_tab.jinx +0 -0
- {npcsh-1.1.17.data → npcsh-1.1.18.data}/data/npcsh/npc_team/alicanto.npc +0 -0
- {npcsh-1.1.17.data → npcsh-1.1.18.data}/data/npcsh/npc_team/alicanto.png +0 -0
- {npcsh-1.1.17.data → npcsh-1.1.18.data}/data/npcsh/npc_team/browser_action.jinx +0 -0
- {npcsh-1.1.17.data → npcsh-1.1.18.data}/data/npcsh/npc_team/browser_screenshot.jinx +0 -0
- {npcsh-1.1.17.data → npcsh-1.1.18.data}/data/npcsh/npc_team/build.jinx +0 -0
- {npcsh-1.1.17.data → npcsh-1.1.18.data}/data/npcsh/npc_team/chat.jinx +0 -0
- {npcsh-1.1.17.data → npcsh-1.1.18.data}/data/npcsh/npc_team/click.jinx +0 -0
- {npcsh-1.1.17.data → npcsh-1.1.18.data}/data/npcsh/npc_team/close_browser.jinx +0 -0
- {npcsh-1.1.17.data → npcsh-1.1.18.data}/data/npcsh/npc_team/close_pane.jinx +0 -0
- {npcsh-1.1.17.data → npcsh-1.1.18.data}/data/npcsh/npc_team/close_tab.jinx +0 -0
- {npcsh-1.1.17.data → npcsh-1.1.18.data}/data/npcsh/npc_team/cmd.jinx +0 -0
- {npcsh-1.1.17.data → npcsh-1.1.18.data}/data/npcsh/npc_team/compile.jinx +0 -0
- {npcsh-1.1.17.data → npcsh-1.1.18.data}/data/npcsh/npc_team/compress.jinx +0 -0
- {npcsh-1.1.17.data → npcsh-1.1.18.data}/data/npcsh/npc_team/confirm.jinx +0 -0
- {npcsh-1.1.17.data → npcsh-1.1.18.data}/data/npcsh/npc_team/convene.jinx +0 -0
- {npcsh-1.1.17.data → npcsh-1.1.18.data}/data/npcsh/npc_team/corca.npc +0 -0
- {npcsh-1.1.17.data → npcsh-1.1.18.data}/data/npcsh/npc_team/corca.png +0 -0
- {npcsh-1.1.17.data → npcsh-1.1.18.data}/data/npcsh/npc_team/corca_example.png +0 -0
- {npcsh-1.1.17.data → npcsh-1.1.18.data}/data/npcsh/npc_team/delegate.jinx +0 -0
- {npcsh-1.1.17.data → npcsh-1.1.18.data}/data/npcsh/npc_team/edit_file.jinx +0 -0
- {npcsh-1.1.17.data → npcsh-1.1.18.data}/data/npcsh/npc_team/focus_pane.jinx +0 -0
- {npcsh-1.1.17.data → npcsh-1.1.18.data}/data/npcsh/npc_team/frederic.npc +0 -0
- {npcsh-1.1.17.data → npcsh-1.1.18.data}/data/npcsh/npc_team/frederic4.png +0 -0
- {npcsh-1.1.17.data → npcsh-1.1.18.data}/data/npcsh/npc_team/guac.npc +0 -0
- {npcsh-1.1.17.data → npcsh-1.1.18.data}/data/npcsh/npc_team/guac.png +0 -0
- {npcsh-1.1.17.data → npcsh-1.1.18.data}/data/npcsh/npc_team/help.jinx +0 -0
- {npcsh-1.1.17.data → npcsh-1.1.18.data}/data/npcsh/npc_team/incognide.jinx +0 -0
- {npcsh-1.1.17.data → npcsh-1.1.18.data}/data/npcsh/npc_team/init.jinx +0 -0
- {npcsh-1.1.17.data → npcsh-1.1.18.data}/data/npcsh/npc_team/kadiefa.npc +0 -0
- {npcsh-1.1.17.data → npcsh-1.1.18.data}/data/npcsh/npc_team/kadiefa.png +0 -0
- {npcsh-1.1.17.data → npcsh-1.1.18.data}/data/npcsh/npc_team/key_press.jinx +0 -0
- {npcsh-1.1.17.data → npcsh-1.1.18.data}/data/npcsh/npc_team/launch_app.jinx +0 -0
- {npcsh-1.1.17.data → npcsh-1.1.18.data}/data/npcsh/npc_team/list_panes.jinx +0 -0
- {npcsh-1.1.17.data → npcsh-1.1.18.data}/data/npcsh/npc_team/load_file.jinx +0 -0
- {npcsh-1.1.17.data → npcsh-1.1.18.data}/data/npcsh/npc_team/navigate.jinx +0 -0
- {npcsh-1.1.17.data → npcsh-1.1.18.data}/data/npcsh/npc_team/notify.jinx +0 -0
- {npcsh-1.1.17.data → npcsh-1.1.18.data}/data/npcsh/npc_team/npcsh.ctx +0 -0
- {npcsh-1.1.17.data → npcsh-1.1.18.data}/data/npcsh/npc_team/npcsh_sibiji.png +0 -0
- {npcsh-1.1.17.data → npcsh-1.1.18.data}/data/npcsh/npc_team/nql.jinx +0 -0
- {npcsh-1.1.17.data → npcsh-1.1.18.data}/data/npcsh/npc_team/open_browser.jinx +0 -0
- {npcsh-1.1.17.data → npcsh-1.1.18.data}/data/npcsh/npc_team/open_pane.jinx +0 -0
- {npcsh-1.1.17.data → npcsh-1.1.18.data}/data/npcsh/npc_team/ots.jinx +0 -0
- {npcsh-1.1.17.data → npcsh-1.1.18.data}/data/npcsh/npc_team/paste.jinx +0 -0
- {npcsh-1.1.17.data → npcsh-1.1.18.data}/data/npcsh/npc_team/plonk.npc +0 -0
- {npcsh-1.1.17.data → npcsh-1.1.18.data}/data/npcsh/npc_team/plonk.png +0 -0
- {npcsh-1.1.17.data → npcsh-1.1.18.data}/data/npcsh/npc_team/plonkjr.npc +0 -0
- {npcsh-1.1.17.data → npcsh-1.1.18.data}/data/npcsh/npc_team/plonkjr.png +0 -0
- {npcsh-1.1.17.data → npcsh-1.1.18.data}/data/npcsh/npc_team/python.jinx +0 -0
- {npcsh-1.1.17.data → npcsh-1.1.18.data}/data/npcsh/npc_team/read_pane.jinx +0 -0
- {npcsh-1.1.17.data → npcsh-1.1.18.data}/data/npcsh/npc_team/roll.jinx +0 -0
- {npcsh-1.1.17.data → npcsh-1.1.18.data}/data/npcsh/npc_team/run_terminal.jinx +0 -0
- {npcsh-1.1.17.data → npcsh-1.1.18.data}/data/npcsh/npc_team/sample.jinx +0 -0
- {npcsh-1.1.17.data → npcsh-1.1.18.data}/data/npcsh/npc_team/screenshot.jinx +0 -0
- {npcsh-1.1.17.data → npcsh-1.1.18.data}/data/npcsh/npc_team/search.jinx +0 -0
- {npcsh-1.1.17.data → npcsh-1.1.18.data}/data/npcsh/npc_team/send_message.jinx +0 -0
- {npcsh-1.1.17.data → npcsh-1.1.18.data}/data/npcsh/npc_team/serve.jinx +0 -0
- {npcsh-1.1.17.data → npcsh-1.1.18.data}/data/npcsh/npc_team/set.jinx +0 -0
- {npcsh-1.1.17.data → npcsh-1.1.18.data}/data/npcsh/npc_team/sh.jinx +0 -0
- {npcsh-1.1.17.data → npcsh-1.1.18.data}/data/npcsh/npc_team/shh.jinx +0 -0
- {npcsh-1.1.17.data → npcsh-1.1.18.data}/data/npcsh/npc_team/sibiji.npc +0 -0
- {npcsh-1.1.17.data → npcsh-1.1.18.data}/data/npcsh/npc_team/sibiji.png +0 -0
- {npcsh-1.1.17.data → npcsh-1.1.18.data}/data/npcsh/npc_team/split_pane.jinx +0 -0
- {npcsh-1.1.17.data → npcsh-1.1.18.data}/data/npcsh/npc_team/spool.png +0 -0
- {npcsh-1.1.17.data → npcsh-1.1.18.data}/data/npcsh/npc_team/switch.jinx +0 -0
- {npcsh-1.1.17.data → npcsh-1.1.18.data}/data/npcsh/npc_team/switch_npc.jinx +0 -0
- {npcsh-1.1.17.data → npcsh-1.1.18.data}/data/npcsh/npc_team/switch_tab.jinx +0 -0
- {npcsh-1.1.17.data → npcsh-1.1.18.data}/data/npcsh/npc_team/switches.jinx +0 -0
- {npcsh-1.1.17.data → npcsh-1.1.18.data}/data/npcsh/npc_team/sync.jinx +0 -0
- {npcsh-1.1.17.data → npcsh-1.1.18.data}/data/npcsh/npc_team/teamviz.jinx +0 -0
- {npcsh-1.1.17.data → npcsh-1.1.18.data}/data/npcsh/npc_team/trigger.jinx +0 -0
- {npcsh-1.1.17.data → npcsh-1.1.18.data}/data/npcsh/npc_team/type_text.jinx +0 -0
- {npcsh-1.1.17.data → npcsh-1.1.18.data}/data/npcsh/npc_team/usage.jinx +0 -0
- {npcsh-1.1.17.data → npcsh-1.1.18.data}/data/npcsh/npc_team/verbose.jinx +0 -0
- {npcsh-1.1.17.data → npcsh-1.1.18.data}/data/npcsh/npc_team/vixynt.jinx +0 -0
- {npcsh-1.1.17.data → npcsh-1.1.18.data}/data/npcsh/npc_team/wait.jinx +0 -0
- {npcsh-1.1.17.data → npcsh-1.1.18.data}/data/npcsh/npc_team/write_file.jinx +0 -0
- {npcsh-1.1.17.data → npcsh-1.1.18.data}/data/npcsh/npc_team/yap.png +0 -0
- {npcsh-1.1.17.data → npcsh-1.1.18.data}/data/npcsh/npc_team/zen_mode.jinx +0 -0
- {npcsh-1.1.17.dist-info → npcsh-1.1.18.dist-info}/licenses/LICENSE +0 -0
- {npcsh-1.1.17.dist-info → npcsh-1.1.18.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,356 @@
|
|
|
1
|
+
jinx_name: alicanto
|
|
2
|
+
description: Deep research mode - multi-perspective exploration with gold insights and cliff warnings
|
|
3
|
+
npc: forenpc
|
|
4
|
+
inputs:
|
|
5
|
+
- query: null
|
|
6
|
+
- num_npcs: 5
|
|
7
|
+
- depth: 3
|
|
8
|
+
- model: null
|
|
9
|
+
- provider: null
|
|
10
|
+
- max_steps: 20
|
|
11
|
+
- skip_research: true
|
|
12
|
+
- exploration: 0.3
|
|
13
|
+
- creativity: 0.5
|
|
14
|
+
- format: report
|
|
15
|
+
- browse: false
|
|
16
|
+
|
|
17
|
+
steps:
|
|
18
|
+
- name: alicanto_research
|
|
19
|
+
engine: python
|
|
20
|
+
code: |
|
|
21
|
+
import os
|
|
22
|
+
import sys
|
|
23
|
+
import tty
|
|
24
|
+
import termios
|
|
25
|
+
from termcolor import colored
|
|
26
|
+
|
|
27
|
+
from npcpy.llm_funcs import get_llm_response
|
|
28
|
+
from npcpy.data.web import search_web
|
|
29
|
+
from npcpy.npc_compiler import NPC
|
|
30
|
+
|
|
31
|
+
npc = context.get('npc')
|
|
32
|
+
team = context.get('team')
|
|
33
|
+
messages = context.get('messages', [])
|
|
34
|
+
|
|
35
|
+
# Resolve npc if it's a string (npc name) rather than NPC object
|
|
36
|
+
if isinstance(npc, str) and team:
|
|
37
|
+
npc = team.get(npc) if hasattr(team, 'get') else None
|
|
38
|
+
elif isinstance(npc, str):
|
|
39
|
+
npc = None # Can't use string npc without team to resolve it
|
|
40
|
+
|
|
41
|
+
# ========== TUI Helper Functions ==========
|
|
42
|
+
def get_terminal_size():
|
|
43
|
+
try:
|
|
44
|
+
size = os.get_terminal_size()
|
|
45
|
+
return size.columns, size.lines
|
|
46
|
+
except:
|
|
47
|
+
return 80, 24
|
|
48
|
+
|
|
49
|
+
def research_tui_browser(result):
|
|
50
|
+
"""Interactive TUI browser for research results"""
|
|
51
|
+
perspectives = result.get('perspectives', '').split('\n')
|
|
52
|
+
insights = result.get('insights', [])
|
|
53
|
+
gold = result.get('gold', [])
|
|
54
|
+
cliffs = result.get('cliffs', [])
|
|
55
|
+
report = result.get('report', '')
|
|
56
|
+
|
|
57
|
+
# Build tabs
|
|
58
|
+
tabs = ['Gold', 'Cliffs', 'Insights', 'Report']
|
|
59
|
+
current_tab = 0
|
|
60
|
+
|
|
61
|
+
width, height = get_terminal_size()
|
|
62
|
+
selected = 0
|
|
63
|
+
scroll = 0
|
|
64
|
+
list_height = height - 5
|
|
65
|
+
|
|
66
|
+
fd = sys.stdin.fileno()
|
|
67
|
+
old_settings = termios.tcgetattr(fd)
|
|
68
|
+
|
|
69
|
+
try:
|
|
70
|
+
tty.setcbreak(fd)
|
|
71
|
+
sys.stdout.write('\033[?25l')
|
|
72
|
+
sys.stdout.write('\033[2J\033[H')
|
|
73
|
+
|
|
74
|
+
while True:
|
|
75
|
+
width, height = get_terminal_size()
|
|
76
|
+
list_height = height - 5
|
|
77
|
+
|
|
78
|
+
# Get current content
|
|
79
|
+
if current_tab == 0: # Gold
|
|
80
|
+
items = gold if gold else ['No gold insights marked']
|
|
81
|
+
elif current_tab == 1: # Cliffs
|
|
82
|
+
items = cliffs if cliffs else ['No cliff warnings marked']
|
|
83
|
+
elif current_tab == 2: # Insights
|
|
84
|
+
items = [i[:200] for i in insights] if insights else ['No insights yet']
|
|
85
|
+
else: # Report
|
|
86
|
+
items = report.split('\n') if report else ['No report generated']
|
|
87
|
+
|
|
88
|
+
if selected >= len(items):
|
|
89
|
+
selected = max(0, len(items) - 1)
|
|
90
|
+
|
|
91
|
+
if selected < scroll:
|
|
92
|
+
scroll = selected
|
|
93
|
+
elif selected >= scroll + list_height:
|
|
94
|
+
scroll = selected - list_height + 1
|
|
95
|
+
|
|
96
|
+
sys.stdout.write('\033[H')
|
|
97
|
+
|
|
98
|
+
# Tab bar
|
|
99
|
+
tab_bar = " "
|
|
100
|
+
for i, tab in enumerate(tabs):
|
|
101
|
+
if i == current_tab:
|
|
102
|
+
tab_bar += f'\033[43;30;1m {tab} \033[0m '
|
|
103
|
+
else:
|
|
104
|
+
tab_bar += f'\033[90m {tab} \033[0m '
|
|
105
|
+
sys.stdout.write(f'{tab_bar.ljust(width)}\n')
|
|
106
|
+
sys.stdout.write(f'\033[90m{"─" * width}\033[0m\n')
|
|
107
|
+
|
|
108
|
+
# Content
|
|
109
|
+
for i in range(list_height):
|
|
110
|
+
idx = scroll + i
|
|
111
|
+
sys.stdout.write(f'\033[{3+i};1H\033[K')
|
|
112
|
+
if idx >= len(items):
|
|
113
|
+
continue
|
|
114
|
+
|
|
115
|
+
line = str(items[idx])[:width-2]
|
|
116
|
+
if current_tab in [0, 1, 2] and idx == selected:
|
|
117
|
+
sys.stdout.write(f'\033[47;30;1m>{line.ljust(width-2)}\033[0m')
|
|
118
|
+
else:
|
|
119
|
+
# Color gold/cliff markers
|
|
120
|
+
if '[GOLD]' in line:
|
|
121
|
+
sys.stdout.write(f'\033[33m {line}\033[0m')
|
|
122
|
+
elif '[CLIFF]' in line:
|
|
123
|
+
sys.stdout.write(f'\033[31m {line}\033[0m')
|
|
124
|
+
else:
|
|
125
|
+
sys.stdout.write(f' {line}')
|
|
126
|
+
|
|
127
|
+
# Status bar
|
|
128
|
+
sys.stdout.write(f'\033[{height-2};1H\033[K\033[90m{"─" * width}\033[0m')
|
|
129
|
+
counts = f"Gold: {len(gold)} | Cliffs: {len(cliffs)} | Insights: {len(insights)}"
|
|
130
|
+
sys.stdout.write(f'\033[{height-1};1H\033[K {counts}'.ljust(width)[:width])
|
|
131
|
+
sys.stdout.write(f'\033[{height};1H\033[K\033[43;30m h/l:Tabs j/k:Nav Enter:View q:Quit [{selected+1}/{len(items)}] \033[0m')
|
|
132
|
+
|
|
133
|
+
sys.stdout.flush()
|
|
134
|
+
|
|
135
|
+
c = sys.stdin.read(1)
|
|
136
|
+
|
|
137
|
+
if c == '\x1b':
|
|
138
|
+
c2 = sys.stdin.read(1)
|
|
139
|
+
if c2 == '[':
|
|
140
|
+
c3 = sys.stdin.read(1)
|
|
141
|
+
if c3 == 'A' and selected > 0:
|
|
142
|
+
selected -= 1
|
|
143
|
+
elif c3 == 'B' and selected < len(items) - 1:
|
|
144
|
+
selected += 1
|
|
145
|
+
elif c3 == 'C': # Right
|
|
146
|
+
current_tab = (current_tab + 1) % len(tabs)
|
|
147
|
+
selected = 0
|
|
148
|
+
scroll = 0
|
|
149
|
+
elif c3 == 'D': # Left
|
|
150
|
+
current_tab = (current_tab - 1) % len(tabs)
|
|
151
|
+
selected = 0
|
|
152
|
+
scroll = 0
|
|
153
|
+
else:
|
|
154
|
+
return
|
|
155
|
+
continue
|
|
156
|
+
|
|
157
|
+
if c == 'q' or c == '\x03':
|
|
158
|
+
return
|
|
159
|
+
elif c == 'k' and selected > 0:
|
|
160
|
+
selected -= 1
|
|
161
|
+
elif c == 'j' and selected < len(items) - 1:
|
|
162
|
+
selected += 1
|
|
163
|
+
elif c == 'h':
|
|
164
|
+
current_tab = (current_tab - 1) % len(tabs)
|
|
165
|
+
selected = 0
|
|
166
|
+
scroll = 0
|
|
167
|
+
elif c == 'l':
|
|
168
|
+
current_tab = (current_tab + 1) % len(tabs)
|
|
169
|
+
selected = 0
|
|
170
|
+
scroll = 0
|
|
171
|
+
elif c in ('\r', '\n') and current_tab < 3:
|
|
172
|
+
# Show full item
|
|
173
|
+
item = items[selected] if selected < len(items) else ''
|
|
174
|
+
print(f'\033[2J\033[H{item}\n\nPress any key to continue...')
|
|
175
|
+
sys.stdout.flush()
|
|
176
|
+
sys.stdin.read(1)
|
|
177
|
+
sys.stdout.write('\033[2J\033[H')
|
|
178
|
+
|
|
179
|
+
finally:
|
|
180
|
+
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
|
|
181
|
+
sys.stdout.write('\033[?25h')
|
|
182
|
+
sys.stdout.write('\033[2J\033[H')
|
|
183
|
+
sys.stdout.flush()
|
|
184
|
+
|
|
185
|
+
query = context.get('query')
|
|
186
|
+
num_npcs = int(context.get('num_npcs', 5))
|
|
187
|
+
depth = int(context.get('depth', 3))
|
|
188
|
+
max_steps = int(context.get('max_steps', 20))
|
|
189
|
+
skip_research = context.get('skip_research', True)
|
|
190
|
+
exploration = float(context.get('exploration', 0.3))
|
|
191
|
+
creativity = float(context.get('creativity', 0.5))
|
|
192
|
+
output_format = context.get('format', 'report')
|
|
193
|
+
|
|
194
|
+
# Handle case where npc might be a string (npc name) or NPC object
|
|
195
|
+
model = context.get('model') or (npc.model if npc and hasattr(npc, 'model') else 'gemini-1.5-pro')
|
|
196
|
+
provider = context.get('provider') or (npc.provider if npc and hasattr(npc, 'provider') else 'gemini')
|
|
197
|
+
|
|
198
|
+
if not query:
|
|
199
|
+
context['output'] = """Usage: /alicanto <research query>
|
|
200
|
+
|
|
201
|
+
Options:
|
|
202
|
+
--num-npcs N Number of research perspectives (default: 5)
|
|
203
|
+
--depth N Research depth (default: 3)
|
|
204
|
+
--max-steps N Maximum research steps (default: 20)
|
|
205
|
+
--exploration F Exploration factor 0-1 (default: 0.3)
|
|
206
|
+
--creativity F Creativity factor 0-1 (default: 0.5)
|
|
207
|
+
--format FORMAT Output: report|summary|full (default: report)
|
|
208
|
+
|
|
209
|
+
Example: /alicanto What are the latest advances in quantum computing?"""
|
|
210
|
+
context['messages'] = messages
|
|
211
|
+
exit()
|
|
212
|
+
|
|
213
|
+
print(f"""
|
|
214
|
+
█████╗ ██╗ ██╗ ██████╗ █████╗ ███╗ ██╗████████╗ ██████╗
|
|
215
|
+
██╔══██╗██║ ██║██╔════╝██╔══██╗████╗ ██║╚══██╔══╝██╔═══██╗
|
|
216
|
+
███████║██║ ██║██║ ███████║██╔██╗ ██║ ██║ ██║ ██║
|
|
217
|
+
██╔══██║██║ ██║██║ ██╔══██║██║╚██╗██║ ██║ ██║ ██║
|
|
218
|
+
██║ ██║███████╗██║╚██████╗██║ ██║██║ ╚████║ ██║ ╚██████╔╝
|
|
219
|
+
╚═╝ ╚═╝╚══════╝╚═╝ ╚═════╝╚═╝ ╚═╝╚═╝ ╚═══╝ ╚═╝ ╚═════╝
|
|
220
|
+
|
|
221
|
+
Deep Research Mode
|
|
222
|
+
Query: {query}
|
|
223
|
+
Perspectives: {num_npcs} | Depth: {depth} | Max Steps: {max_steps}
|
|
224
|
+
""")
|
|
225
|
+
|
|
226
|
+
# Generate research perspectives
|
|
227
|
+
perspectives_prompt = f"""Generate {num_npcs} distinct research perspectives for investigating: "{query}"
|
|
228
|
+
|
|
229
|
+
For each perspective, provide:
|
|
230
|
+
1. Name (a descriptive title)
|
|
231
|
+
2. Approach (how this perspective would investigate)
|
|
232
|
+
3. Key questions to explore
|
|
233
|
+
|
|
234
|
+
Return as a numbered list."""
|
|
235
|
+
|
|
236
|
+
print(colored("Generating research perspectives...", "cyan"))
|
|
237
|
+
resp = get_llm_response(
|
|
238
|
+
perspectives_prompt,
|
|
239
|
+
model=model,
|
|
240
|
+
provider=provider,
|
|
241
|
+
npc=npc
|
|
242
|
+
)
|
|
243
|
+
perspectives = str(resp.get('response', ''))
|
|
244
|
+
print(perspectives)
|
|
245
|
+
|
|
246
|
+
# Conduct web research if not skipped
|
|
247
|
+
research_findings = ""
|
|
248
|
+
if not skip_research:
|
|
249
|
+
print(colored("\nConducting web research...", "cyan"))
|
|
250
|
+
try:
|
|
251
|
+
search_results = search_web(query, n_results=5)
|
|
252
|
+
if search_results:
|
|
253
|
+
research_findings = "\n\nWeb Research Findings:\n"
|
|
254
|
+
for i, result in enumerate(search_results[:5], 1):
|
|
255
|
+
title = result.get('title', 'No title')
|
|
256
|
+
snippet = result.get('snippet', result.get('body', ''))[:200]
|
|
257
|
+
research_findings += f"\n{i}. {title}\n {snippet}...\n"
|
|
258
|
+
print(colored(f"Found {len(search_results)} sources", "green"))
|
|
259
|
+
except Exception as e:
|
|
260
|
+
print(colored(f"Web search error: {e}", "yellow"))
|
|
261
|
+
|
|
262
|
+
# Multi-step exploration from each perspective
|
|
263
|
+
all_insights = []
|
|
264
|
+
gold_insights = [] # Key valuable findings
|
|
265
|
+
cliff_warnings = [] # Potential pitfalls or caveats
|
|
266
|
+
|
|
267
|
+
for step in range(min(depth, max_steps)):
|
|
268
|
+
print(colored(f"\n--- Research Depth {step + 1}/{depth} ---", "cyan"))
|
|
269
|
+
|
|
270
|
+
explore_prompt = f"""Research query: "{query}"
|
|
271
|
+
|
|
272
|
+
Perspectives generated:
|
|
273
|
+
{perspectives}
|
|
274
|
+
|
|
275
|
+
{research_findings}
|
|
276
|
+
|
|
277
|
+
Previous insights: {all_insights[-3:] if all_insights else 'None yet'}
|
|
278
|
+
|
|
279
|
+
For depth level {step + 1}:
|
|
280
|
+
1. Explore deeper implications from each perspective
|
|
281
|
+
2. Identify GOLD insights (valuable, non-obvious findings) - mark with [GOLD]
|
|
282
|
+
3. Identify CLIFF warnings (pitfalls, caveats, risks) - mark with [CLIFF]
|
|
283
|
+
4. Connect insights across perspectives
|
|
284
|
+
|
|
285
|
+
Exploration factor: {exploration} (higher = more diverse exploration)
|
|
286
|
+
Creativity factor: {creativity} (higher = more novel connections)"""
|
|
287
|
+
|
|
288
|
+
resp = get_llm_response(
|
|
289
|
+
explore_prompt,
|
|
290
|
+
model=model,
|
|
291
|
+
provider=provider,
|
|
292
|
+
temperature=creativity,
|
|
293
|
+
npc=npc
|
|
294
|
+
)
|
|
295
|
+
|
|
296
|
+
step_insights = str(resp.get('response', ''))
|
|
297
|
+
print(step_insights)
|
|
298
|
+
|
|
299
|
+
# Extract gold and cliff markers
|
|
300
|
+
if '[GOLD]' in step_insights:
|
|
301
|
+
gold_insights.extend([line.strip() for line in step_insights.split('\n') if '[GOLD]' in line])
|
|
302
|
+
if '[CLIFF]' in step_insights:
|
|
303
|
+
cliff_warnings.extend([line.strip() for line in step_insights.split('\n') if '[CLIFF]' in line])
|
|
304
|
+
|
|
305
|
+
all_insights.append(step_insights)
|
|
306
|
+
|
|
307
|
+
# Generate final synthesis
|
|
308
|
+
print(colored("\n--- Synthesizing Research ---", "cyan"))
|
|
309
|
+
|
|
310
|
+
synthesis_prompt = f"""Synthesize research on: "{query}"
|
|
311
|
+
|
|
312
|
+
All insights gathered:
|
|
313
|
+
{chr(10).join(all_insights)}
|
|
314
|
+
|
|
315
|
+
Gold insights identified:
|
|
316
|
+
{chr(10).join(gold_insights) if gold_insights else 'None explicitly marked'}
|
|
317
|
+
|
|
318
|
+
Cliff warnings identified:
|
|
319
|
+
{chr(10).join(cliff_warnings) if cliff_warnings else 'None explicitly marked'}
|
|
320
|
+
|
|
321
|
+
Generate a {output_format} that:
|
|
322
|
+
1. Summarizes key findings
|
|
323
|
+
2. Highlights the most valuable insights (gold)
|
|
324
|
+
3. Notes important caveats and risks (cliffs)
|
|
325
|
+
4. Provides actionable conclusions"""
|
|
326
|
+
|
|
327
|
+
resp = get_llm_response(
|
|
328
|
+
synthesis_prompt,
|
|
329
|
+
model=model,
|
|
330
|
+
provider=provider,
|
|
331
|
+
npc=npc
|
|
332
|
+
)
|
|
333
|
+
|
|
334
|
+
final_report = str(resp.get('response', ''))
|
|
335
|
+
print("\n" + "="*60)
|
|
336
|
+
print(colored("ALICANTO RESEARCH REPORT", "green", attrs=['bold']))
|
|
337
|
+
print("="*60)
|
|
338
|
+
print(final_report)
|
|
339
|
+
|
|
340
|
+
alicanto_result = {
|
|
341
|
+
'query': query,
|
|
342
|
+
'perspectives': perspectives,
|
|
343
|
+
'insights': all_insights,
|
|
344
|
+
'gold': gold_insights,
|
|
345
|
+
'cliffs': cliff_warnings,
|
|
346
|
+
'report': final_report
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
context['output'] = final_report
|
|
350
|
+
context['messages'] = messages
|
|
351
|
+
context['alicanto_result'] = alicanto_result
|
|
352
|
+
|
|
353
|
+
# Launch interactive browser automatically
|
|
354
|
+
if gold_insights or cliff_warnings or all_insights:
|
|
355
|
+
print(colored("\nLaunching results browser...", "cyan"))
|
|
356
|
+
research_tui_browser(alicanto_result)
|