nothumanallowed 9.3.7 → 9.3.9

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nothumanallowed",
3
- "version": "9.3.7",
3
+ "version": "9.3.9",
4
4
  "description": "NotHumanAllowed — 38 AI agents + 58 tools + browser automation + web search. Streaming chat, headless Chrome CDP, multi-conversation, export. Gmail, Calendar, Drive, GitHub, Notion, Slack. Zero-dependency CLI.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -59,7 +59,8 @@ const MAX_HISTORY = 20;
59
59
  const CHAT_PERSONA = `You are NHA Chat, a personal operations assistant inside the NotHumanAllowed CLI. ` +
60
60
  `You help the user manage their emails, calendar, tasks, GitHub issues, Notion pages, and Slack channels through natural conversation. ` +
61
61
  `Be concise, helpful, and proactive. When presenting data, format it clearly. ` +
62
- `Never output raw JSON to the user — always wrap results in natural language.`;
62
+ `Never output raw JSON to the user — always wrap results in natural language. ` +
63
+ `ALWAYS respond in the same language the user writes in. If the user writes in English, respond in English. If the user writes in Italian, respond in Italian. Match their language exactly.`;
63
64
 
64
65
  // ── System Prompt Builder ────────────────────────────────────────────────────
65
66
 
@@ -175,7 +175,8 @@ export async function cmdUI(args) {
175
175
  const UI_PERSONA = `You are NHA Chat, a personal operations assistant inside the NotHumanAllowed web UI. ` +
176
176
  `You help the user manage their emails, calendar, tasks, GitHub issues, Notion pages, and Slack channels through natural conversation. ` +
177
177
  `Be concise, helpful, and proactive. When presenting data, format it clearly. ` +
178
- `Never output raw JSON to the user.`;
178
+ `Never output raw JSON to the user. ` +
179
+ `ALWAYS respond in the same language the user writes in. If the user writes in English, respond in English. If the user writes in Italian, respond in Italian. Match their language exactly.`;
179
180
  const chatSystemPrompt = buildSystemPrompt('NHA UI', UI_PERSONA, config);
180
181
 
181
182
  // ── Route Handlers ──────────────────────────────────────────────────────
@@ -814,12 +815,25 @@ export async function cmdUI(args) {
814
815
  return;
815
816
  }
816
817
 
817
- // Build message with history (merge persisted + request history)
818
- const requestHistory = body.history || [];
818
+ // Build message with rolling context (same strategy as streaming path)
819
+ const requestHistory = (body.history || []).map(h => ({
820
+ role: h.role,
821
+ content: (h.content || '').replace(/!\[Screenshot\]\(data:image\/[^)]+\)/g, '[Screenshot taken]'),
822
+ }));
823
+ const RECENT = 6;
819
824
  const parts = [];
820
- for (const turn of requestHistory) {
821
- const prefix = turn.role === 'user' ? '[User]' : '[Assistant]';
822
- parts.push(`${prefix} ${turn.content}`);
825
+ if (requestHistory.length > RECENT) {
826
+ const older = requestHistory.slice(0, -RECENT);
827
+ const sLines = [];
828
+ for (let i = 0; i < older.length; i += 2) {
829
+ const u = older[i]?.content?.slice(0, 150)?.replace(/\n/g, ' ') || '';
830
+ const a = older[i + 1]?.content?.slice(0, 200)?.replace(/\n/g, ' ') || '';
831
+ if (u) sLines.push(`- User: "${u.trim()}${u.length >= 150 ? '...' : ''}" → ${a.trim()}${a.length >= 200 ? '...' : ''}`);
832
+ }
833
+ if (sLines.length > 0) parts.push(`[CONTEXT — ${sLines.length} earlier exchanges]\n${sLines.join('\n')}\n[END CONTEXT]`);
834
+ }
835
+ for (const turn of requestHistory.slice(-RECENT)) {
836
+ parts.push(`${turn.role === 'user' ? '[User]' : '[Assistant]'} ${turn.content.slice(0, 2000)}`);
823
837
  }
824
838
  parts.push(`[User] ${body.message}`);
825
839
  let userMessage = parts.join('\n\n');
@@ -1119,13 +1133,38 @@ export async function cmdUI(args) {
1119
1133
  let enrichedPrompt = basePrompt;
1120
1134
  try { const m = buildMemoryContext('chat', effectiveMsg); if (m) enrichedPrompt = basePrompt + m; } catch {}
1121
1135
 
1122
- // Build message with conversation history
1123
- const history = body.history || [];
1136
+ // Build message with rolling context window:
1137
+ // - Recent messages (last 6): full content up to 2000 chars
1138
+ // - Older messages: compressed to 1-line summaries preserving full context
1139
+ const rawHistory = (body.history || []).map(h => ({
1140
+ role: h.role,
1141
+ content: (h.content || '').replace(/!\[Screenshot\]\(data:image\/[^)]+\)/g, '[Screenshot taken]'),
1142
+ }));
1143
+
1144
+ const RECENT_COUNT = 6;
1124
1145
  const parts = [];
1125
- for (const turn of history) {
1146
+
1147
+ if (rawHistory.length > RECENT_COUNT) {
1148
+ // Compress older messages into a conversation summary
1149
+ const older = rawHistory.slice(0, -RECENT_COUNT);
1150
+ const summaryLines = [];
1151
+ for (let i = 0; i < older.length; i += 2) {
1152
+ const userMsg = older[i]?.content?.slice(0, 150)?.replace(/\n/g, ' ') || '';
1153
+ const assistantMsg = older[i + 1]?.content?.slice(0, 200)?.replace(/\n/g, ' ') || '';
1154
+ if (userMsg) summaryLines.push(`- User asked: "${userMsg.trim()}${userMsg.length >= 150 ? '...' : ''}" → Assistant: ${assistantMsg.trim()}${assistantMsg.length >= 200 ? '...' : ''}`);
1155
+ }
1156
+ if (summaryLines.length > 0) {
1157
+ parts.push(`[CONVERSATION CONTEXT — ${summaryLines.length} earlier exchanges]\n${summaryLines.join('\n')}\n[END CONTEXT]`);
1158
+ }
1159
+ }
1160
+
1161
+ // Recent messages in full
1162
+ const recent = rawHistory.slice(-RECENT_COUNT);
1163
+ for (const turn of recent) {
1126
1164
  const prefix = turn.role === 'user' ? '[User]' : '[Assistant]';
1127
- parts.push(`${prefix} ${turn.content}`);
1165
+ parts.push(`${prefix} ${turn.content.slice(0, 2000)}`);
1128
1166
  }
1167
+
1129
1168
  parts.push(`[User] ${effectiveMsg}`);
1130
1169
  const userMessage = parts.join('\n\n');
1131
1170
 
package/src/constants.mjs CHANGED
@@ -5,7 +5,7 @@ import { fileURLToPath } from 'url';
5
5
  const __filename = fileURLToPath(import.meta.url);
6
6
  const __dirname = path.dirname(__filename);
7
7
 
8
- export const VERSION = '9.3.7';
8
+ export const VERSION = '9.3.9';
9
9
  export const BASE_URL = 'https://nothumanallowed.com/cli';
10
10
  export const API_BASE = 'https://nothumanallowed.com/api/v1';
11
11
 
@@ -483,8 +483,8 @@ function sendChat(){
483
483
  chatHistory.push({role:'assistant',content:''});
484
484
  renderMessages();
485
485
  var streamIdx=chatHistory.length-1;
486
- var cleanHistory=chatHistory.slice(0,-1).map(function(m){return{role:m.role,content:(m.content||'').replace(/!\\[Screenshot\\]\\(data:image\\/[^)]+\\)/g,'[Screenshot was shown]').slice(0,4000)};});
487
- var payload={message:msg,history:cleanHistory,conversationId:activeConvId};
486
+ var allHistory=chatHistory.slice(0,-1).map(function(m){return{role:m.role,content:(m.content||'').replace(/!\\[Screenshot\\]\\(data:image\\/[^)]+\\)/g,'[Screenshot taken]')};});
487
+ var payload={message:msg,history:allHistory,conversationId:activeConvId};
488
488
 
489
489
  fetch(API+'/api/chat/stream',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(payload)}).then(function(response){
490
490
  if(!response.ok||!response.body){chatHistory[streamIdx].content='Error: connection failed';chatStreaming=false;renderMessages();return;}