nothumanallowed 13.5.91 → 13.5.93

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": "13.5.91",
3
+ "version": "13.5.93",
4
4
  "description": "NotHumanAllowed — 38 AI agents, 80 tools, Studio (visual agentic workflows). Email, calendar, browser automation, screen capture, canvas, cron/heartbeat, Alexandria E2E messaging, GitHub, Notion, Slack, voice chat, free AI (Liara), 28 languages. Zero-dependency CLI.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -3856,7 +3856,7 @@ ${completedHeadings ? `## SECTIONS ALREADY WRITTEN (headings only):\n${completed
3856
3856
  return;
3857
3857
  }
3858
3858
  try {
3859
- const result = await callLLM(config, body.system, body.user, { max_tokens: body.max_tokens || 4096 });
3859
+ const result = await callLLM(config, body.system, body.user, { max_tokens: body.max_tokens || 8192, temperature: 0.15 });
3860
3860
  sendJSON(res, 200, { text: result });
3861
3861
  } catch (e) {
3862
3862
  sendJSON(res, 500, { error: e.message });
@@ -7,14 +7,15 @@
7
7
 
8
8
  // ── Providers ──────────────────────────────────────────────────────────────
9
9
 
10
- export async function callAnthropic(apiKey, model, systemPrompt, userMessage, stream = false) {
10
+ export async function callAnthropic(apiKey, model, systemPrompt, userMessage, stream = false, opts = {}) {
11
11
  const body = {
12
12
  model: model || 'claude-sonnet-4-20250514',
13
- max_tokens: 8192,
13
+ max_tokens: opts.max_tokens || 8192,
14
14
  system: systemPrompt,
15
15
  messages: [{ role: 'user', content: userMessage }],
16
16
  stream,
17
17
  };
18
+ if (opts.temperature !== undefined) body.temperature = opts.temperature;
18
19
  const res = await fetch('https://api.anthropic.com/v1/messages', {
19
20
  method: 'POST',
20
21
  headers: {
@@ -33,16 +34,17 @@ export async function callAnthropic(apiKey, model, systemPrompt, userMessage, st
33
34
  return data.content?.[0]?.text || '';
34
35
  }
35
36
 
36
- export async function callOpenAI(apiKey, model, systemPrompt, userMessage, stream = false) {
37
+ export async function callOpenAI(apiKey, model, systemPrompt, userMessage, stream = false, opts = {}) {
37
38
  const body = {
38
39
  model: model || 'gpt-4o',
39
- max_tokens: 8192,
40
+ max_tokens: opts.max_tokens || 8192,
40
41
  messages: [
41
42
  { role: 'system', content: systemPrompt },
42
43
  { role: 'user', content: userMessage },
43
44
  ],
44
45
  stream,
45
46
  };
47
+ if (opts.temperature !== undefined) body.temperature = opts.temperature;
46
48
  const res = await fetch('https://api.openai.com/v1/chat/completions', {
47
49
  method: 'POST',
48
50
  headers: {
@@ -60,13 +62,15 @@ export async function callOpenAI(apiKey, model, systemPrompt, userMessage, strea
60
62
  return data.choices?.[0]?.message?.content || '';
61
63
  }
62
64
 
63
- export async function callGemini(apiKey, model, systemPrompt, userMessage, _stream = false) {
65
+ export async function callGemini(apiKey, model, systemPrompt, userMessage, _stream = false, opts = {}) {
64
66
  const m = model || 'gemini-2.5-pro-preview-05-06';
65
67
  const url = `https://generativelanguage.googleapis.com/v1beta/models/${m}:generateContent?key=${apiKey}`;
68
+ const generationConfig = { maxOutputTokens: opts.max_tokens || 8192 };
69
+ if (opts.temperature !== undefined) generationConfig.temperature = opts.temperature;
66
70
  const body = {
67
71
  system_instruction: { parts: [{ text: systemPrompt }] },
68
72
  contents: [{ parts: [{ text: userMessage }] }],
69
- generationConfig: { maxOutputTokens: 8192 },
73
+ generationConfig,
70
74
  };
71
75
  const res = await fetch(url, {
72
76
  method: 'POST',
@@ -81,16 +85,17 @@ export async function callGemini(apiKey, model, systemPrompt, userMessage, _stre
81
85
  return data.candidates?.[0]?.content?.parts?.[0]?.text || '';
82
86
  }
83
87
 
84
- export async function callDeepSeek(apiKey, model, systemPrompt, userMessage, stream = false) {
88
+ export async function callDeepSeek(apiKey, model, systemPrompt, userMessage, stream = false, opts = {}) {
85
89
  const body = {
86
90
  model: model || 'deepseek-chat',
87
- max_tokens: 8192,
91
+ max_tokens: opts.max_tokens || 8192,
88
92
  messages: [
89
93
  { role: 'system', content: systemPrompt },
90
94
  { role: 'user', content: userMessage },
91
95
  ],
92
96
  stream,
93
97
  };
98
+ if (opts.temperature !== undefined) body.temperature = opts.temperature;
94
99
  const res = await fetch('https://api.deepseek.com/v1/chat/completions', {
95
100
  method: 'POST',
96
101
  headers: {
@@ -108,16 +113,17 @@ export async function callDeepSeek(apiKey, model, systemPrompt, userMessage, str
108
113
  return data.choices?.[0]?.message?.content || '';
109
114
  }
110
115
 
111
- export async function callGrok(apiKey, model, systemPrompt, userMessage, stream = false) {
116
+ export async function callGrok(apiKey, model, systemPrompt, userMessage, stream = false, opts = {}) {
112
117
  const body = {
113
118
  model: model || 'grok-3-latest',
114
- max_tokens: 8192,
119
+ max_tokens: opts.max_tokens || 8192,
115
120
  messages: [
116
121
  { role: 'system', content: systemPrompt },
117
122
  { role: 'user', content: userMessage },
118
123
  ],
119
124
  stream,
120
125
  };
126
+ if (opts.temperature !== undefined) body.temperature = opts.temperature;
121
127
  const res = await fetch('https://api.x.ai/v1/chat/completions', {
122
128
  method: 'POST',
123
129
  headers: {
@@ -135,16 +141,17 @@ export async function callGrok(apiKey, model, systemPrompt, userMessage, stream
135
141
  return data.choices?.[0]?.message?.content || '';
136
142
  }
137
143
 
138
- export async function callMistral(apiKey, model, systemPrompt, userMessage, stream = false) {
144
+ export async function callMistral(apiKey, model, systemPrompt, userMessage, stream = false, opts = {}) {
139
145
  const body = {
140
146
  model: model || 'mistral-large-latest',
141
- max_tokens: 8192,
147
+ max_tokens: opts.max_tokens || 8192,
142
148
  messages: [
143
149
  { role: 'system', content: systemPrompt },
144
150
  { role: 'user', content: userMessage },
145
151
  ],
146
152
  stream,
147
153
  };
154
+ if (opts.temperature !== undefined) body.temperature = opts.temperature;
148
155
  const res = await fetch('https://api.mistral.ai/v1/chat/completions', {
149
156
  method: 'POST',
150
157
  headers: {
@@ -162,13 +169,14 @@ export async function callMistral(apiKey, model, systemPrompt, userMessage, stre
162
169
  return data.choices?.[0]?.message?.content || '';
163
170
  }
164
171
 
165
- export async function callCohere(apiKey, model, systemPrompt, userMessage, _stream = false) {
172
+ export async function callCohere(apiKey, model, systemPrompt, userMessage, _stream = false, opts = {}) {
166
173
  const body = {
167
174
  model: model || 'command-r-plus',
168
- max_tokens: 8192,
175
+ max_tokens: opts.max_tokens || 8192,
169
176
  preamble: systemPrompt,
170
177
  message: userMessage,
171
178
  };
179
+ if (opts.temperature !== undefined) body.temperature = opts.temperature;
172
180
  const res = await fetch('https://api.cohere.ai/v1/chat', {
173
181
  method: 'POST',
174
182
  headers: {
@@ -236,7 +244,7 @@ export async function streamSSE(res, format) {
236
244
  * NHA Free (Liara) — free LLM tier, no API key required.
237
245
  * Qwen3 32B on Hetzner RTX 6000 Pro 96GB. Supports thinking mode.
238
246
  */
239
- export async function callNHA(apiKey, model, systemPrompt, userMessage, stream = false) {
247
+ export async function callNHA(apiKey, model, systemPrompt, userMessage, stream = false, opts = {}) {
240
248
  // Read thinking preference from config
241
249
  let thinkingEnabled = false; // OFF by default for speed
242
250
  try {
@@ -266,7 +274,7 @@ export async function callNHA(apiKey, model, systemPrompt, userMessage, stream =
266
274
 
267
275
  const body = {
268
276
  model: model || '/opt/models/qwen3-32b',
269
- max_tokens: thinkingEnabled ? 16384 : 8192,
277
+ max_tokens: opts.max_tokens || (thinkingEnabled ? 16384 : 8192),
270
278
  messages: [
271
279
  { role: 'system', content: sanitizeForSentinel(systemPrompt) },
272
280
  { role: 'user', content: sanitizeForSentinel(userMessage) },
@@ -274,6 +282,7 @@ export async function callNHA(apiKey, model, systemPrompt, userMessage, stream =
274
282
  stream,
275
283
  chat_template_kwargs: { enable_thinking: thinkingEnabled },
276
284
  };
285
+ if (opts.temperature !== undefined) body.temperature = opts.temperature;
277
286
  // Route through NHA server proxy (SENTINEL protection) instead of direct to Hetzner
278
287
  const res = await fetch('https://nothumanallowed.com/api/v1/liara/chat', {
279
288
  method: 'POST',
@@ -338,7 +347,7 @@ export async function callLLM(config, systemPrompt, userMessage, opts = {}) {
338
347
  const callFn = getProviderCall(provider);
339
348
  if (!callFn) throw new Error(`Unknown provider: ${provider}`);
340
349
 
341
- return callFn(apiKey, model, systemPrompt, userMessage, false);
350
+ return callFn(apiKey, model, systemPrompt, userMessage, false, opts);
342
351
  }
343
352
 
344
353
  /**
@@ -7987,15 +7987,43 @@ async function wcGenerate() {
7987
7987
  _wcGenStartTime = Date.now();
7988
7988
  _wcTokIn = 0; _wcTokOut = 0; // reset global counters for this generation run
7989
7989
 
7990
- // Helper: generate one file
7990
+ // CSS files that need two-pass generation (too long for one call)
7991
+ var WC_CSS_SPLIT = {
7992
+ 'public/css/base.css': [
7993
+ 'PART 1 of 2. Generate the FIRST HALF of public/css/base.css. Include: (1) all CSS custom properties / design tokens (colors, spacing, font sizes, shadows, radii, transitions, z-index scale, dark/light mode via prefers-color-scheme data-theme), (2) CSS reset (*, box-sizing, margin, padding), (3) base typography (body, h1-h6, p, a, code, pre, blockquote), (4) utility classes (flex, grid helpers, spacing, text alignment, visibility, truncation). End the file at a natural boundary (closing brace). Do NOT generate components. Output raw CSS only.',
7994
+ 'PART 2 of 2. Continue (do NOT repeat) public/css/base.css from where part 1 ended. Generate: (5) layout helpers (.container, .grid, .col-*, .stack, .cluster, .sidebar-layout), (6) responsive breakpoint utilities (768px, 480px), (7) animation keyframes (@keyframes fadeIn, slideUp, pulse, spin), (8) scrollbar styling, (9) selection styles, (10) print styles. Output raw CSS only, starting directly from where part 1 ended — no repetition.'
7995
+ ],
7996
+ 'public/css/components.css': [
7997
+ 'PART 1 of 2. Generate the FIRST HALF of public/css/components.css using strict BEM. Include components: (1) .btn (--primary, --secondary, --danger, --ghost, --sm, --lg, disabled state, loading state with spinner), (2) .form (.form__group, .form__label, .form__input, .form__textarea, .form__select, .form__error, .form__hint, .form__input--invalid, focus states), (3) .card (.card__header, .card__body, .card__footer, .card--interactive hover/active), (4) .badge (--success, --error, --warning, --info, --neutral), (5) .alert (--success, --error, --warning, --info with icon space). Output raw CSS only.',
7998
+ 'PART 2 of 2. Continue (do NOT repeat) public/css/components.css from where part 1 ended. Include components: (6) .nav (.nav__brand, .nav__links, .nav__link, .nav__link--active, .nav__toggle mobile hamburger, .nav--sticky), (7) .modal (.modal__overlay, .modal__content, .modal__header, .modal__body, .modal__footer, open/close transition), (8) .spinner (sizes: sm/md/lg, colors), (9) .dropdown (.dropdown__menu, .dropdown__item, open state), (10) .avatar (.avatar--sm/md/lg, .avatar--initials), (11) .progress (.progress__bar, animated fill), (12) .table (.table__head, .table__row, .table__cell, striped, hover). Output raw CSS only, starting directly from where part 1 ended.'
7999
+ ]
8000
+ };
8001
+
8002
+ // Helper: strip markdown fences from LLM output
8003
+ function wcStripFences(content) {
8004
+ var _nl2 = String.fromCharCode(10);
8005
+ var _fence = String.fromCharCode(96,96,96);
8006
+ var lines = content.split(_nl2);
8007
+ if (lines.length > 0 && lines[0].indexOf(_fence) === 0) lines.shift();
8008
+ if (lines.length > 0 && lines[lines.length-1].trim() === _fence) lines.pop();
8009
+ return lines.join(_nl2).trim();
8010
+ }
8011
+
8012
+ // Helper: generate one file (with two-pass split for large CSS files)
7991
8013
  async function wcGenOneFile(fp, signal) {
7992
8014
  var _nl2 = String.fromCharCode(10);
8015
+ var splitPrompts = WC_CSS_SPLIT[fp.name];
8016
+ if (splitPrompts) {
8017
+ // Two-pass generation: call LLM twice and concatenate
8018
+ var part1 = await wcCallLLM(sysPreamble, splitPrompts[0] + _nl2 + _nl2 + 'File: ' + fp.name, signal, fp.lang, 8192);
8019
+ part1 = wcStripFences(part1);
8020
+ if (signal && signal.aborted) return part1;
8021
+ var part2 = await wcCallLLM(sysPreamble, splitPrompts[1] + _nl2 + _nl2 + 'File: ' + fp.name, signal, fp.lang, 8192);
8022
+ part2 = wcStripFences(part2);
8023
+ return part1 + _nl2 + _nl2 + part2;
8024
+ }
7993
8025
  var content = await wcCallLLM(sysPreamble, fp.prompt + _nl2 + _nl2 + 'File to generate: ' + fp.name, signal, fp.lang);
7994
- var _fence = String.fromCharCode(96,96,96);
7995
- var wcLines = content.split(_nl2);
7996
- if (wcLines.length > 0 && wcLines[0].indexOf(_fence) === 0) wcLines.shift();
7997
- if (wcLines.length > 0 && wcLines[wcLines.length-1].trim() === _fence) wcLines.pop();
7998
- return wcLines.join(_nl2).trim();
8026
+ return wcStripFences(content);
7999
8027
  }
8000
8028
 
8001
8029
  wcStartGenTimer();
@@ -8094,7 +8122,8 @@ async function wcAutoRepair(filePlan, sysPreamble) {
8094
8122
  if (filePlan) filePlan.forEach(function(fp){ planMap[fp.name] = fp; });
8095
8123
 
8096
8124
  var _nl3 = String.fromCharCode(10);
8097
- var sysBase = sysPreamble || ('You are an expert full-stack engineer. Output ONLY the complete corrected file content. No explanations, no markdown fences.');
8125
+ // Use compact system prompt for repair to avoid exceeding Liara context window
8126
+ var sysBase = 'You are an expert full-stack engineer. Output ONLY the complete corrected file content. No explanations, no markdown fences, no preamble. Raw file content only.';
8098
8127
 
8099
8128
  for (var ri = 0; ri < toFix.length; ri++) {
8100
8129
  var broken = toFix[ri];
@@ -8120,7 +8149,7 @@ async function wcAutoRepair(filePlan, sysPreamble) {
8120
8149
  (broken.content.length > 800 ? broken.content.slice(0, 400) + _nl3 + '...' + _nl3 + broken.content.slice(-400) : broken.content) + _nl3 + _nl3 +
8121
8150
  'Output the COMPLETE corrected file from the beginning.';
8122
8151
  }
8123
- var fixed = await wcCallLLM(fixSys, fixUser, null, broken.lang || plan && plan.lang);
8152
+ var fixed = await wcCallLLM(fixSys, fixUser, null, broken.lang || plan && plan.lang, 8192);
8124
8153
  var _fence3 = String.fromCharCode(96,96,96);
8125
8154
  var fixLines = fixed.split(_nl3);
8126
8155
  if (fixLines.length > 0 && fixLines[0].indexOf(_fence3) === 0) fixLines.shift();
@@ -8230,11 +8259,11 @@ function wcIsTruncated(content, lang) {
8230
8259
  return false;
8231
8260
  }
8232
8261
 
8233
- async function wcCallLLMRaw(sys, user, signal) {
8262
+ async function wcCallLLMRaw(sys, user, signal, maxTok) {
8234
8263
  var fetchOpts = {
8235
8264
  method: 'POST',
8236
8265
  headers: {'Content-Type':'application/json'},
8237
- body: JSON.stringify({system: sys, user: user, max_tokens: 8192})
8266
+ body: JSON.stringify({system: sys, user: user, max_tokens: maxTok || 16384})
8238
8267
  };
8239
8268
  if (signal) fetchOpts.signal = signal;
8240
8269
  for (var attempt = 0; attempt < 3; attempt++) {
@@ -8262,8 +8291,8 @@ async function wcCallLLMRaw(sys, user, signal) {
8262
8291
  }
8263
8292
  }
8264
8293
 
8265
- async function wcCallLLM(sys, user, signal, lang) {
8266
- var content = await wcCallLLMRaw(sys, user, signal);
8294
+ async function wcCallLLM(sys, user, signal, lang, maxTok) {
8295
+ var content = await wcCallLLMRaw(sys, user, signal, maxTok);
8267
8296
  // Continuation loop: if response is truncated, ask model to continue
8268
8297
  var maxContinuations = 2;
8269
8298
  for (var ci = 0; ci < maxContinuations; ci++) {
@@ -8272,7 +8301,7 @@ async function wcCallLLM(sys, user, signal, lang) {
8272
8301
  var continuePrompt = 'Continue generating the file EXACTLY from where you stopped. Do not repeat anything already written. Output ONLY the remaining code, starting from the next character after where you stopped.' +
8273
8302
  String.fromCharCode(10) + String.fromCharCode(10) + 'The file so far ends with:' +
8274
8303
  String.fromCharCode(10) + content.slice(-300);
8275
- var continuation = await wcCallLLMRaw(sys, continuePrompt, signal);
8304
+ var continuation = await wcCallLLMRaw(sys, continuePrompt, signal, maxTok);
8276
8305
  if (!continuation || continuation.trim().length < 5) break;
8277
8306
  content = content + String.fromCharCode(10) + continuation;
8278
8307
  }