npcsh 1.1.20__py3-none-any.whl → 1.1.22__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 +15 -76
- npcsh/benchmark/npcsh_agent.py +22 -14
- npcsh/benchmark/templates/install-npcsh.sh.j2 +2 -2
- npcsh/diff_viewer.py +3 -3
- npcsh/mcp_server.py +9 -1
- npcsh/npc_team/alicanto.npc +12 -6
- npcsh/npc_team/corca.npc +0 -1
- npcsh/npc_team/frederic.npc +2 -3
- npcsh/npc_team/jinxs/lib/core/compress.jinx +373 -85
- npcsh/npc_team/jinxs/lib/core/edit_file.jinx +83 -61
- npcsh/npc_team/jinxs/lib/core/search/db_search.jinx +17 -6
- npcsh/npc_team/jinxs/lib/core/search/file_search.jinx +17 -6
- npcsh/npc_team/jinxs/lib/core/search/web_search.jinx +52 -14
- npcsh/npc_team/jinxs/{bin → lib/utils}/benchmark.jinx +2 -2
- npcsh/npc_team/jinxs/{bin → lib/utils}/jinxs.jinx +12 -12
- npcsh/npc_team/jinxs/{bin → lib/utils}/models.jinx +7 -7
- npcsh/npc_team/jinxs/{bin → lib/utils}/setup.jinx +6 -6
- npcsh/npc_team/jinxs/modes/alicanto.jinx +1633 -295
- npcsh/npc_team/jinxs/modes/arxiv.jinx +5 -5
- npcsh/npc_team/jinxs/modes/build.jinx +378 -0
- npcsh/npc_team/jinxs/modes/config_tui.jinx +300 -0
- npcsh/npc_team/jinxs/modes/convene.jinx +597 -0
- npcsh/npc_team/jinxs/modes/corca.jinx +777 -387
- npcsh/npc_team/jinxs/modes/git.jinx +795 -0
- {npcsh-1.1.20.data/data/npcsh/npc_team → npcsh/npc_team/jinxs/modes}/kg.jinx +82 -15
- npcsh/npc_team/jinxs/modes/memories.jinx +414 -0
- npcsh/npc_team/jinxs/{bin → modes}/nql.jinx +10 -21
- npcsh/npc_team/jinxs/modes/papers.jinx +578 -0
- npcsh/npc_team/jinxs/modes/plonk.jinx +503 -308
- npcsh/npc_team/jinxs/modes/reattach.jinx +3 -3
- npcsh/npc_team/jinxs/modes/spool.jinx +3 -3
- npcsh/npc_team/jinxs/{bin → modes}/team.jinx +12 -12
- npcsh/npc_team/jinxs/modes/vixynt.jinx +388 -0
- npcsh/npc_team/jinxs/modes/wander.jinx +454 -181
- npcsh/npc_team/jinxs/modes/yap.jinx +630 -182
- npcsh/npc_team/kadiefa.npc +2 -1
- npcsh/npc_team/sibiji.npc +3 -3
- npcsh/npcsh.py +112 -47
- npcsh/routes.py +4 -1
- npcsh/salmon_simulation.py +0 -0
- npcsh-1.1.22.data/data/npcsh/npc_team/alicanto.jinx +1694 -0
- {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/alicanto.npc +12 -6
- {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/arxiv.jinx +5 -5
- {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/benchmark.jinx +2 -2
- npcsh-1.1.22.data/data/npcsh/npc_team/build.jinx +378 -0
- npcsh-1.1.22.data/data/npcsh/npc_team/compress.jinx +428 -0
- npcsh-1.1.22.data/data/npcsh/npc_team/config_tui.jinx +300 -0
- npcsh-1.1.22.data/data/npcsh/npc_team/corca.jinx +820 -0
- {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/corca.npc +0 -1
- {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/db_search.jinx +17 -6
- npcsh-1.1.22.data/data/npcsh/npc_team/edit_file.jinx +119 -0
- {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/file_search.jinx +17 -6
- {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/frederic.npc +2 -3
- npcsh-1.1.22.data/data/npcsh/npc_team/git.jinx +795 -0
- {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/jinxs.jinx +12 -12
- {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/kadiefa.npc +2 -1
- {npcsh/npc_team/jinxs/bin → npcsh-1.1.22.data/data/npcsh/npc_team}/kg.jinx +82 -15
- npcsh-1.1.22.data/data/npcsh/npc_team/memories.jinx +414 -0
- {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/models.jinx +7 -7
- {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/nql.jinx +10 -21
- npcsh-1.1.22.data/data/npcsh/npc_team/papers.jinx +578 -0
- npcsh-1.1.22.data/data/npcsh/npc_team/plonk.jinx +574 -0
- {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/reattach.jinx +3 -3
- {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/setup.jinx +6 -6
- {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/sibiji.npc +3 -3
- {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/spool.jinx +3 -3
- {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/team.jinx +12 -12
- npcsh-1.1.22.data/data/npcsh/npc_team/vixynt.jinx +388 -0
- npcsh-1.1.22.data/data/npcsh/npc_team/wander.jinx +728 -0
- {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/web_search.jinx +52 -14
- npcsh-1.1.22.data/data/npcsh/npc_team/yap.jinx +716 -0
- {npcsh-1.1.20.dist-info → npcsh-1.1.22.dist-info}/METADATA +246 -281
- npcsh-1.1.22.dist-info/RECORD +240 -0
- npcsh-1.1.22.dist-info/entry_points.txt +11 -0
- npcsh/npc_team/jinxs/bin/config_tui.jinx +0 -300
- npcsh/npc_team/jinxs/bin/memories.jinx +0 -317
- npcsh/npc_team/jinxs/bin/vixynt.jinx +0 -122
- npcsh/npc_team/jinxs/lib/core/search/kg_search.jinx +0 -418
- npcsh/npc_team/jinxs/lib/core/search/mem_review.jinx +0 -73
- npcsh/npc_team/jinxs/lib/core/search/mem_search.jinx +0 -388
- npcsh/npc_team/jinxs/lib/core/search.jinx +0 -54
- npcsh/npc_team/jinxs/lib/research/paper_search.jinx +0 -412
- npcsh/npc_team/jinxs/lib/research/semantic_scholar.jinx +0 -386
- npcsh/npc_team/jinxs/lib/utils/build.jinx +0 -65
- npcsh/npc_team/plonkjr.npc +0 -23
- npcsh-1.1.20.data/data/npcsh/npc_team/alicanto.jinx +0 -356
- npcsh-1.1.20.data/data/npcsh/npc_team/build.jinx +0 -65
- npcsh-1.1.20.data/data/npcsh/npc_team/compress.jinx +0 -140
- npcsh-1.1.20.data/data/npcsh/npc_team/config_tui.jinx +0 -300
- npcsh-1.1.20.data/data/npcsh/npc_team/corca.jinx +0 -430
- npcsh-1.1.20.data/data/npcsh/npc_team/edit_file.jinx +0 -97
- npcsh-1.1.20.data/data/npcsh/npc_team/kg_search.jinx +0 -418
- npcsh-1.1.20.data/data/npcsh/npc_team/mem_review.jinx +0 -73
- npcsh-1.1.20.data/data/npcsh/npc_team/mem_search.jinx +0 -388
- npcsh-1.1.20.data/data/npcsh/npc_team/memories.jinx +0 -317
- npcsh-1.1.20.data/data/npcsh/npc_team/paper_search.jinx +0 -412
- npcsh-1.1.20.data/data/npcsh/npc_team/plonk.jinx +0 -379
- npcsh-1.1.20.data/data/npcsh/npc_team/plonkjr.npc +0 -23
- npcsh-1.1.20.data/data/npcsh/npc_team/search.jinx +0 -54
- npcsh-1.1.20.data/data/npcsh/npc_team/semantic_scholar.jinx +0 -386
- npcsh-1.1.20.data/data/npcsh/npc_team/vixynt.jinx +0 -122
- npcsh-1.1.20.data/data/npcsh/npc_team/wander.jinx +0 -455
- npcsh-1.1.20.data/data/npcsh/npc_team/yap.jinx +0 -268
- npcsh-1.1.20.dist-info/RECORD +0 -248
- npcsh-1.1.20.dist-info/entry_points.txt +0 -25
- /npcsh/npc_team/jinxs/lib/{orchestration → core}/convene.jinx +0 -0
- /npcsh/npc_team/jinxs/lib/{orchestration → core}/delegate.jinx +0 -0
- /npcsh/npc_team/jinxs/{bin → lib/core}/sample.jinx +0 -0
- /npcsh/npc_team/jinxs/lib/{core → utils}/chat.jinx +0 -0
- /npcsh/npc_team/jinxs/lib/{core → utils}/cmd.jinx +0 -0
- /npcsh/npc_team/jinxs/{bin → lib/utils}/sync.jinx +0 -0
- /npcsh/npc_team/jinxs/{bin → modes}/roll.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/add_tab.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/alicanto.png +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/browser_action.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/browser_screenshot.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/chat.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/click.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/close_browser.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/close_pane.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/close_tab.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/cmd.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/compile.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/confirm.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/convene.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/corca.png +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/corca_example.png +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/delegate.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/focus_pane.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/frederic4.png +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/guac.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/guac.npc +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/guac.png +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/help.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/incognide.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/init.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/kadiefa.png +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/key_press.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/launch_app.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/list_panes.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/load_file.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/navigate.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/notify.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/npcsh.ctx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/npcsh_sibiji.png +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/open_browser.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/open_pane.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/ots.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/paste.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/plonk.npc +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/plonk.png +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/plonkjr.png +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/pti.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/python.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/read_pane.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/roll.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/run_terminal.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/sample.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/screenshot.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/send_message.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/serve.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/set.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/sh.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/shh.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/sibiji.png +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/sleep.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/split_pane.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/spool.png +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/sql.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/switch.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/switch_npc.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/switch_tab.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/switches.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/sync.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/teamviz.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/trigger.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/type_text.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/usage.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/verbose.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/wait.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/write_file.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/yap.png +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.22.data}/data/npcsh/npc_team/zen_mode.jinx +0 -0
- {npcsh-1.1.20.dist-info → npcsh-1.1.22.dist-info}/WHEEL +0 -0
- {npcsh-1.1.20.dist-info → npcsh-1.1.22.dist-info}/licenses/LICENSE +0 -0
- {npcsh-1.1.20.dist-info → npcsh-1.1.22.dist-info}/top_level.txt +0 -0
|
@@ -1,356 +0,0 @@
|
|
|
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[7;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)
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
jinx_name: "build"
|
|
2
|
-
description: "Build deployment artifacts for NPC team"
|
|
3
|
-
inputs:
|
|
4
|
-
- target: "flask"
|
|
5
|
-
- outdir: "./build"
|
|
6
|
-
- team: "./npc_team"
|
|
7
|
-
- port: 5337
|
|
8
|
-
- cors: ""
|
|
9
|
-
steps:
|
|
10
|
-
- name: "execute_build"
|
|
11
|
-
engine: "python"
|
|
12
|
-
code: |
|
|
13
|
-
import os
|
|
14
|
-
|
|
15
|
-
# Assume these build functions are available in the execution environment
|
|
16
|
-
# from a larger project context, e.g., from npcpy.build_funcs
|
|
17
|
-
try:
|
|
18
|
-
from npcpy.build_funcs import (
|
|
19
|
-
build_flask_server,
|
|
20
|
-
build_docker_compose,
|
|
21
|
-
build_cli_executable,
|
|
22
|
-
build_static_site,
|
|
23
|
-
)
|
|
24
|
-
except ImportError:
|
|
25
|
-
# Provide mock functions for demonstration or error handling
|
|
26
|
-
def build_flask_server(config, **kwargs): return {"output": f"Mock build flask: {config}", "messages": []}
|
|
27
|
-
def build_docker_compose(config, **kwargs): return {"output": f"Mock build docker: {config}", "messages": []}
|
|
28
|
-
def build_cli_executable(config, **kwargs): return {"output": f"Mock build cli: {config}", "messages": []}
|
|
29
|
-
def build_static_site(config, **kwargs): return {"output": f"Mock build static: {config}", "messages": []}
|
|
30
|
-
|
|
31
|
-
target = context.get('target') or 'flask'
|
|
32
|
-
output_dir = context.get('outdir') or './build'
|
|
33
|
-
team_path = context.get('team') or './npc_team'
|
|
34
|
-
port = context.get('port') or 5337
|
|
35
|
-
cors_origins_str = context.get('cors') or ''
|
|
36
|
-
|
|
37
|
-
cors_origins = [origin.strip() for origin in cors_origins_str.split(',') if origin.strip()] or None
|
|
38
|
-
|
|
39
|
-
build_config = {
|
|
40
|
-
'team_path': os.path.abspath(os.path.expanduser(team_path)),
|
|
41
|
-
'output_dir': os.path.abspath(os.path.expanduser(output_dir)),
|
|
42
|
-
'target': target,
|
|
43
|
-
'port': port,
|
|
44
|
-
'cors_origins': cors_origins,
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
builders = {
|
|
48
|
-
'flask': build_flask_server,
|
|
49
|
-
'docker': build_docker_compose,
|
|
50
|
-
'cli': build_cli_executable,
|
|
51
|
-
'static': build_static_site,
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
output_messages = context.get('messages', [])
|
|
55
|
-
output_result = ""
|
|
56
|
-
|
|
57
|
-
if target not in builders:
|
|
58
|
-
output_result = f"Unknown target: {target}. Available: {list(builders.keys())}"
|
|
59
|
-
else:
|
|
60
|
-
result = builders[target](build_config, messages=output_messages)
|
|
61
|
-
output_result = result.get('output', 'Build command executed.')
|
|
62
|
-
output_messages = result.get('messages', output_messages) # Update messages from builder call
|
|
63
|
-
|
|
64
|
-
context['output'] = output_result
|
|
65
|
-
context['messages'] = output_messages
|
|
@@ -1,140 +0,0 @@
|
|
|
1
|
-
jinx_name: "compress"
|
|
2
|
-
description: "Manages conversation and knowledge context. Defaults to compacting context. Use flags for other operations."
|
|
3
|
-
inputs:
|
|
4
|
-
- flush: ""
|
|
5
|
-
- sleep: False
|
|
6
|
-
- dream: False
|
|
7
|
-
- ops: ""
|
|
8
|
-
- model: ""
|
|
9
|
-
- provider: ""
|
|
10
|
-
steps:
|
|
11
|
-
- name: "manage_context_and_memory"
|
|
12
|
-
engine: "python"
|
|
13
|
-
code: |
|
|
14
|
-
import os
|
|
15
|
-
import traceback
|
|
16
|
-
from npcpy.llm_funcs import breathe
|
|
17
|
-
from npcpy.memory.command_history import CommandHistory, load_kg_from_db, save_kg_to_db
|
|
18
|
-
from npcpy.memory.knowledge_graph import kg_sleep_process, kg_dream_process
|
|
19
|
-
|
|
20
|
-
# --- Get all inputs from context ---
|
|
21
|
-
flush_n_str = context.get('flush')
|
|
22
|
-
is_sleeping = context.get('sleep')
|
|
23
|
-
is_dreaming = context.get('dream')
|
|
24
|
-
operations_str = context.get('ops')
|
|
25
|
-
llm_model = context.get('model')
|
|
26
|
-
llm_provider = context.get('provider')
|
|
27
|
-
output_messages = context.get('messages', [])
|
|
28
|
-
|
|
29
|
-
USAGE = """Usage:
|
|
30
|
-
/compress (Compacts conversation context)
|
|
31
|
-
/compress --flush <number> (Removes the last N messages)
|
|
32
|
-
/compress --sleep [...] (Evolves the knowledge graph)
|
|
33
|
-
--dream (With --sleep: enables creative synthesis)
|
|
34
|
-
--ops "op1,op2" (With --sleep: specifies KG operations)
|
|
35
|
-
--model <name> (With --sleep: specifies LLM model)
|
|
36
|
-
--provider <name> (With --sleep: specifies LLM provider)"""
|
|
37
|
-
|
|
38
|
-
# --- Argument Validation: Ensure mutual exclusivity ---
|
|
39
|
-
is_flushing = flush_n_str is not None and flush_n_str.strip() != ''
|
|
40
|
-
if is_sleeping and is_flushing:
|
|
41
|
-
context['output'] = f"Error: --sleep and --flush are mutually exclusive.\n{USAGE}"
|
|
42
|
-
context['messages'] = output_messages
|
|
43
|
-
exit()
|
|
44
|
-
|
|
45
|
-
# --- Dispatcher: Route to the correct functionality ---
|
|
46
|
-
|
|
47
|
-
# 1. SLEEP: Evolve the Knowledge Graph
|
|
48
|
-
if is_sleeping:
|
|
49
|
-
current_npc = context.get('npc')
|
|
50
|
-
current_team = context.get('team')
|
|
51
|
-
|
|
52
|
-
# Parameter setup for KG process
|
|
53
|
-
operations_config = [op.strip() for op in operations_str.split(',')] if operations_str else None
|
|
54
|
-
if not llm_model and current_npc: llm_model = current_npc.model
|
|
55
|
-
if not llm_provider and current_npc: llm_provider = current_npc.provider
|
|
56
|
-
if not llm_model: llm_model = state.chat_model if state else "llama3.2"
|
|
57
|
-
if not llm_provider: llm_provider = state.chat_provider if state else "ollama"
|
|
58
|
-
|
|
59
|
-
team_name = current_team.name if current_team else "__none__"
|
|
60
|
-
npc_name = current_npc.name if current_npc else "__none__"
|
|
61
|
-
current_path = os.getcwd()
|
|
62
|
-
scope_str = f"Team: '{team_name}', NPC: '{npc_name}', Path: '{current_path}'"
|
|
63
|
-
|
|
64
|
-
command_history = None
|
|
65
|
-
try:
|
|
66
|
-
db_path = os.getenv("NPCSH_DB_PATH", os.path.expanduser("~/npcsh_history.db"))
|
|
67
|
-
command_history = CommandHistory(db_path)
|
|
68
|
-
engine = command_history.engine
|
|
69
|
-
current_kg = load_kg_from_db(engine, team_name, npc_name, current_path)
|
|
70
|
-
|
|
71
|
-
if not current_kg or not current_kg.get('facts'):
|
|
72
|
-
context['output'] = f"Knowledge graph for the current scope is empty. Nothing to process.\n- Scope: {scope_str}"
|
|
73
|
-
exit()
|
|
74
|
-
|
|
75
|
-
original_facts = len(current_kg.get('facts', []))
|
|
76
|
-
original_concepts = len(current_kg.get('concepts', []))
|
|
77
|
-
|
|
78
|
-
evolved_kg, _ = kg_sleep_process(existing_kg=current_kg, model=llm_model, provider=llm_provider, npc=current_npc, operations_config=operations_config)
|
|
79
|
-
process_type = "Sleep"
|
|
80
|
-
|
|
81
|
-
if is_dreaming:
|
|
82
|
-
evolved_kg, _ = kg_dream_process(existing_kg=evolved_kg, model=llm_model, provider=llm_provider, npc=current_npc)
|
|
83
|
-
process_type += " & Dream"
|
|
84
|
-
|
|
85
|
-
save_kg_to_db(engine, evolved_kg, team_name, npc_name, current_path)
|
|
86
|
-
|
|
87
|
-
new_facts = len(evolved_kg.get('facts', []))
|
|
88
|
-
new_concepts = len(evolved_kg.get('concepts', []))
|
|
89
|
-
|
|
90
|
-
context['output'] = (f"{process_type} process complete.\n"
|
|
91
|
-
f"- Facts: {original_facts} -> {new_facts} ({new_facts - original_facts:+})\n"
|
|
92
|
-
f"- Concepts: {original_concepts} -> {new_concepts} ({new_concepts - original_concepts:+})")
|
|
93
|
-
except Exception as e:
|
|
94
|
-
traceback.print_exc()
|
|
95
|
-
context['output'] = f"Error during KG evolution: {e}"
|
|
96
|
-
finally:
|
|
97
|
-
if command_history: command_history.close()
|
|
98
|
-
context['messages'] = output_messages
|
|
99
|
-
|
|
100
|
-
# 2. FLUSH: Remove messages from context
|
|
101
|
-
elif is_flushing:
|
|
102
|
-
try:
|
|
103
|
-
n = int(flush_n_str)
|
|
104
|
-
if n <= 0:
|
|
105
|
-
context['output'] = "Error: Number of messages to flush must be positive."
|
|
106
|
-
exit()
|
|
107
|
-
except ValueError:
|
|
108
|
-
context['output'] = f"Error: Invalid number '{flush_n_str}'. {USAGE}"
|
|
109
|
-
exit()
|
|
110
|
-
|
|
111
|
-
messages_list = list(output_messages)
|
|
112
|
-
original_len = len(messages_list)
|
|
113
|
-
final_messages = []
|
|
114
|
-
|
|
115
|
-
if messages_list and messages_list[0].get("role") == "system":
|
|
116
|
-
system_message = messages_list.pop(0)
|
|
117
|
-
num_to_remove = min(n, len(messages_list))
|
|
118
|
-
final_messages = [system_message] + messages_list[:-num_to_remove]
|
|
119
|
-
else:
|
|
120
|
-
num_to_remove = min(n, original_len)
|
|
121
|
-
final_messages = messages_list[:-num_to_remove]
|
|
122
|
-
|
|
123
|
-
removed_count = original_len - len(final_messages)
|
|
124
|
-
context['output'] = f"Flushed {removed_count} message(s). Context is now {len(final_messages)} messages."
|
|
125
|
-
context['messages'] = final_messages
|
|
126
|
-
|
|
127
|
-
# 3. DEFAULT: Compact conversation context
|
|
128
|
-
else:
|
|
129
|
-
try:
|
|
130
|
-
result = breathe(**context)
|
|
131
|
-
if isinstance(result, dict):
|
|
132
|
-
context['output'] = result.get('output', 'Context compressed.')
|
|
133
|
-
context['messages'] = result.get('messages', output_messages)
|
|
134
|
-
else:
|
|
135
|
-
context['output'] = "Context compression process initiated."
|
|
136
|
-
context['messages'] = output_messages
|
|
137
|
-
except Exception as e:
|
|
138
|
-
traceback.print_exc()
|
|
139
|
-
context['output'] = f"Error during context compression: {e}"
|
|
140
|
-
context['messages'] = output_messages
|