nothumanallowed 13.5.128 → 13.5.129

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.128",
3
+ "version": "13.5.129",
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": {
@@ -2111,9 +2111,33 @@ export async function cmdUI(args) {
2111
2111
  clean = clean.replace(/\[Screenshot[^\]]*\]/g, '').replace(/!\[.*?\]\(data:image[^)]+\)/g, '').slice(0, 3000);
2112
2112
  return `[${t.action} result]: ${clean.trim() || 'Done.'}`;
2113
2113
  }).join('\n\n');
2114
- const followUp = `The user asked: "${body.message}"\n\nI executed these tools and got REAL results:\n\n${toolContext}\n\nNow respond conversationally based ONLY on the REAL data above. Do NOT output any JSON blocks, base64, or image markdown — just natural text.`;
2114
+ const followUp = `The user asked: "${body.message}"\n\nI executed these tools and got REAL results:\n\n${toolContext}\n\nNow respond to the user conversationally based ONLY on the REAL data above. If the user's request has multiple steps and the first step is done, execute the next step using a JSON tool block. Do NOT embed base64 data or image markdown — just natural text.`;
2115
2115
  try {
2116
2116
  fullResponse = await callLLM(config, enrichedSystemPrompt, followUp);
2117
+
2118
+ // Round 2: execute any tool calls emitted in the synthesis response
2119
+ const { textParts: synthText2, actions: synthActions2 } = parseActions(fullResponse);
2120
+ if (synthActions2.length > 0) {
2121
+ const round2Results = [];
2122
+ for (const { action: a2, params: p2 } of synthActions2) {
2123
+ try {
2124
+ const r2 = await executeTool(a2, p2, config);
2125
+ round2Results.push({ action: a2, result: typeof r2 === 'object' ? JSON.stringify(r2) : String(r2) });
2126
+ } catch (e2) {
2127
+ round2Results.push({ action: a2, result: `Error: ${e2.message}` });
2128
+ }
2129
+ }
2130
+ const round2Context = round2Results.map(t => `[${t.action} result]: ${t.result.slice(0, 2000)}`).join('\n\n');
2131
+ try {
2132
+ const r2Summary = await callLLM(config, enrichedSystemPrompt, `The user asked: "${body.message}"\n\n${toolContext}\n\nRound 2 tool results:\n\n${round2Context}\n\nGive the user a final natural-language summary of everything. Do NOT output JSON blocks.`);
2133
+ fullResponse = synthText2.join('\n').replace(/```json[\s\S]*?```/g, '').trim() + (synthText2.join('').trim() ? '\n\n' : '') + r2Summary.trim();
2134
+ } catch {
2135
+ fullResponse = synthText2.join('\n').replace(/```json[\s\S]*?```/g, '').trim() + '\n\n' + round2Results.map(t => `${t.action}: ${t.result}`).join('\n');
2136
+ }
2137
+ } else {
2138
+ fullResponse = fullResponse.replace(/```json[\s\S]*?```/g, '').trim();
2139
+ }
2140
+
2117
2141
  // Prepend preserved markers so the UI can render canvas/screenshots
2118
2142
  if (preservedMarkers) fullResponse = preservedMarkers + fullResponse;
2119
2143
  } catch {
@@ -2615,17 +2639,50 @@ export async function cmdUI(args) {
2615
2639
  sendSSE('canvas', { markers: preservedMarkers });
2616
2640
  }
2617
2641
 
2618
- const followUp = `The user asked: "${msg}"\n\nI executed these tools and got REAL results:\n\n${toolContext}\n\nNow respond to the user conversationally based ONLY on the REAL data above. Present the results clearly. Do NOT output any JSON blocks, any base64 data, or any image markdown — just natural text. If a screenshot was taken, just mention "Screenshot captured" without embedding it.`;
2642
+ const followUp = `The user asked: "${msg}"\n\nI executed these tools and got REAL results:\n\n${toolContext}\n\nNow respond to the user conversationally based ONLY on the REAL data above. Present the results clearly. If the user's request has multiple steps and the first step is done, execute the next step using a JSON tool block. Do NOT embed base64 data or image markdown — just natural text. If a screenshot was taken, just mention "Screenshot captured" without embedding it.`;
2619
2643
  sendSSE('tool_synthesis', {});
2620
2644
  try {
2621
2645
  finalResponse = await callLLMStream(config, enrichedPrompt, followUp, (chunk) => {
2622
2646
  sendSSE('token', { content: chunk });
2623
2647
  });
2624
2648
  finalResponse = finalResponse
2625
- .replace(/```json[\s\S]*?```/g, '')
2626
2649
  .replace(/!\[.*?\]\(data:image\/[^)]+\)/g, '')
2627
2650
  .replace(/data:image\/[a-z]+;base64,[A-Za-z0-9+/=]{100,}/g, '[image]')
2628
2651
  .trim();
2652
+
2653
+ // Round 2: execute any tool calls emitted in the synthesis response
2654
+ const { textParts: synthText, actions: synthActions } = parseActions(finalResponse);
2655
+ if (synthActions.length > 0) {
2656
+ const round2Results = [];
2657
+ for (const { action: a2, params: p2 } of synthActions) {
2658
+ sendSSE('tool', { action: a2, status: 'executing' });
2659
+ try {
2660
+ const r2 = await executeTool(a2, p2, config);
2661
+ const r2str = typeof r2 === 'object' ? JSON.stringify(r2) : String(r2);
2662
+ round2Results.push({ action: a2, result: r2str });
2663
+ sendSSE('tool', { action: a2, status: 'done', result: r2str.slice(0, 200) });
2664
+ } catch (e2) {
2665
+ round2Results.push({ action: a2, result: `Error: ${e2.message}` });
2666
+ sendSSE('tool', { action: a2, status: 'error', error: e2.message });
2667
+ }
2668
+ }
2669
+ const round2Context = round2Results.map(t => `[${t.action} result]: ${t.result.slice(0, 2000)}`).join('\n\n');
2670
+ const round2Prompt = `${toolContext}\n\nRound 2 tool results:\n\n${round2Context}\n\nNow give the user a final natural-language summary of everything that was done. Do NOT output JSON blocks.`;
2671
+ sendSSE('tool_synthesis', {});
2672
+ try {
2673
+ finalResponse = synthText.join('\n').replace(/```json[\s\S]*?```/g, '').trim();
2674
+ const r2Summary = await callLLMStream(config, enrichedPrompt, `The user asked: "${msg}"\n\n${round2Prompt}`, (chunk) => {
2675
+ sendSSE('token', { content: chunk });
2676
+ });
2677
+ finalResponse = (finalResponse ? finalResponse + '\n\n' : '') + r2Summary.trim();
2678
+ } catch {
2679
+ finalResponse = synthText.join('\n').replace(/```json[\s\S]*?```/g, '').trim() + '\n\n' + round2Results.map(t => `${t.action}: ${t.result}`).join('\n');
2680
+ }
2681
+ } else {
2682
+ // No new tool calls — strip any leftover JSON blocks from display text
2683
+ finalResponse = finalResponse.replace(/```json[\s\S]*?```/g, '').trim();
2684
+ }
2685
+
2629
2686
  // Prepend preserved markers for persistence
2630
2687
  if (preservedMarkers) finalResponse = preservedMarkers + finalResponse;
2631
2688
  } catch {
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 = '13.5.128';
8
+ export const VERSION = '13.5.129';
9
9
  export const BASE_URL = 'https://nothumanallowed.com/cli';
10
10
  export const API_BASE = 'https://nothumanallowed.com/api/v1';
11
11