nothumanallowed 17.0.1 → 17.0.2
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 +1 -1
- package/src/constants.mjs +1 -1
- package/src/legion/legion-x.mjs +69 -16
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nothumanallowed",
|
|
3
|
-
"version": "17.0.
|
|
3
|
+
"version": "17.0.2",
|
|
4
4
|
"description": "Local AI assistant: 80 tools (Gmail, Calendar, Drive, GitHub, Slack, browser, code, files), 38 agents, multi-agent deliberation that runs entirely on your machine (Legion X), visual workflows (Studio, AWF, WebCraft). Install with `npm i -g nothumanallowed`, run with `nha ui`. Bring your own LLM: an API key or a local model (Ollama, any OpenAI-compatible endpoint). Your data stays on your PC — OAuth tokens local, no cloud. Open-source MIT.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
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 = '17.0.
|
|
8
|
+
export const VERSION = '17.0.2';
|
|
9
9
|
export const BASE_URL = 'https://nothumanallowed.com/cli';
|
|
10
10
|
export const API_BASE = 'https://nothumanallowed.com/api/v1';
|
|
11
11
|
|
package/src/legion/legion-x.mjs
CHANGED
|
@@ -6061,9 +6061,30 @@ var GETH_DOMAIN_AFFINITY = {
|
|
|
6061
6061
|
* A replacement comes from the preferred categories, then the allowed ones,
|
|
6062
6062
|
* and is never an agent already in the list. With no replacement left the
|
|
6063
6063
|
* original stays: too few agents is worse than one out of place.
|
|
6064
|
-
*
|
|
6065
|
-
*
|
|
6064
|
+
* The domain-agnostic agents always pass. A general or uncertain domain
|
|
6065
|
+
* (confidence below 0.3) changes nothing.
|
|
6066
6066
|
*/
|
|
6067
|
+
// Their work applies to any subject, whatever category the catalog files them
|
|
6068
|
+
// under: LOGOS checks the reasoning, VERITAS checks the claims.
|
|
6069
|
+
var GETH_DOMAIN_AGNOSTIC_AGENTS = ['LOGOS', 'VERITAS'];
|
|
6070
|
+
|
|
6071
|
+
var GETH_DOMAIN_TIER_PROHIBITED = 3;
|
|
6072
|
+
|
|
6073
|
+
/**
|
|
6074
|
+
* How well an agent fits the question's domain: 0 preferred category,
|
|
6075
|
+
* 1 allowed, 2 neither listed, 3 prohibited. A general or uncertain domain
|
|
6076
|
+
* (confidence below 0.3) ranks every agent the same, and the domain-agnostic
|
|
6077
|
+
* agents are never prohibited.
|
|
6078
|
+
*/
|
|
6079
|
+
function gethDomainTier(agentName, category, domain) {
|
|
6080
|
+
if (!domain || domain.family === 'general' || domain.confidence < 0.3) return 0;
|
|
6081
|
+
var affinity = GETH_DOMAIN_AFFINITY[domain.family] || GETH_DOMAIN_AFFINITY.general;
|
|
6082
|
+
if (affinity.preferred.indexOf(category) !== -1) return 0;
|
|
6083
|
+
if (affinity.allowed.indexOf(category) !== -1) return 1;
|
|
6084
|
+
if (affinity.prohibited.indexOf(category) === -1) return 2;
|
|
6085
|
+
return GETH_DOMAIN_AGNOSTIC_AGENTS.indexOf(String(agentName).toUpperCase()) !== -1 ? 1 : GETH_DOMAIN_TIER_PROHIBITED;
|
|
6086
|
+
}
|
|
6087
|
+
|
|
6067
6088
|
function gethValidateAgentDomainAffinity(agents, domain, available) {
|
|
6068
6089
|
var unchanged = agents.map(function(a) { return { name: a.name, category: a.category }; });
|
|
6069
6090
|
if (domain.family === 'general' || domain.confidence < 0.3) return unchanged;
|
|
@@ -6085,7 +6106,7 @@ function gethValidateAgentDomainAffinity(agents, domain, available) {
|
|
|
6085
6106
|
}
|
|
6086
6107
|
|
|
6087
6108
|
return agents.map(function(agent) {
|
|
6088
|
-
if (agent.name.toUpperCase()
|
|
6109
|
+
if (GETH_DOMAIN_AGNOSTIC_AGENTS.indexOf(agent.name.toUpperCase()) !== -1 || affinity.prohibited.indexOf(agent.category) === -1) {
|
|
6089
6110
|
return { name: agent.name, category: agent.category };
|
|
6090
6111
|
}
|
|
6091
6112
|
var replacement = findReplacement();
|
|
@@ -7300,21 +7321,32 @@ class LocalGethOrchestrator {
|
|
|
7300
7321
|
/**
|
|
7301
7322
|
* One orchestrator call with provider fallback. Tries the preferred provider,
|
|
7302
7323
|
* then the others in order; throws the last error when all of them fail.
|
|
7324
|
+
*
|
|
7325
|
+
* `usable(text)` is optional: when it returns false the answer cannot be
|
|
7326
|
+
* read (a model that chats instead of following the format), and the next
|
|
7327
|
+
* configured provider is asked. If none does better, the first unreadable
|
|
7328
|
+
* answer is returned and the caller decides what to make of it.
|
|
7303
7329
|
*/
|
|
7304
|
-
async orchestratorChat(session, systemPrompt, userMessage, maxTokens, agentTag) {
|
|
7330
|
+
async orchestratorChat(session, systemPrompt, userMessage, maxTokens, agentTag, usable) {
|
|
7305
7331
|
var preferred = this.pickOrchestratorProvider(session);
|
|
7306
7332
|
var order = [preferred].concat(session.providers.filter(function(p) { return p !== preferred; }));
|
|
7307
7333
|
var lastErr = null;
|
|
7334
|
+
var unreadable = null;
|
|
7308
7335
|
for (var i = 0; i < order.length; i++) {
|
|
7309
7336
|
try {
|
|
7310
7337
|
var text = await this.llm.chatWithProvider(order[i], systemPrompt, userMessage, {
|
|
7311
7338
|
maxTokens: maxTokens, agentTag: agentTag,
|
|
7312
7339
|
});
|
|
7340
|
+
if (usable && !usable(text)) {
|
|
7341
|
+
if (!unreadable) unreadable = { text: text, provider: order[i] };
|
|
7342
|
+
continue;
|
|
7343
|
+
}
|
|
7313
7344
|
return { text: text, provider: order[i] };
|
|
7314
7345
|
} catch (err) {
|
|
7315
7346
|
lastErr = err;
|
|
7316
7347
|
}
|
|
7317
7348
|
}
|
|
7349
|
+
if (unreadable) return unreadable;
|
|
7318
7350
|
throw lastErr || new Error('No provider available for the orchestrator');
|
|
7319
7351
|
}
|
|
7320
7352
|
|
|
@@ -7882,11 +7914,22 @@ class LocalGethOrchestrator {
|
|
|
7882
7914
|
assignments.forEach(function(a) { assigned[a.agentName] = true; });
|
|
7883
7915
|
var categoriesInUse = {};
|
|
7884
7916
|
assignments.forEach(function(a) { categoriesInUse[a.category] = true; });
|
|
7917
|
+
// The agents added here answer the same question as the ones PROMETHEUS
|
|
7918
|
+
// chose, so the same domain rule applies: an agent the guardrail just
|
|
7919
|
+
// removed, or one of a category prohibited for the domain, is not
|
|
7920
|
+
// brought back in by the top-up. Fitting categories come first.
|
|
7921
|
+
var topUpDomain = session.domain || gethClassifyDomain(session.prompt);
|
|
7922
|
+
var removedByGuardrail = {};
|
|
7923
|
+
(session.domainReplacements || []).forEach(function(r) { removedByGuardrail[String(r.from).toUpperCase()] = true; });
|
|
7885
7924
|
var candidates = this.getCatalog()
|
|
7886
|
-
.filter(function(a) { return !assigned[a.agentName] && PARLIAMENT_AGENT_NAMES.indexOf(a.agentName) === -1; })
|
|
7925
|
+
.filter(function(a) { return !assigned[a.agentName] && PARLIAMENT_AGENT_NAMES.indexOf(a.agentName) === -1; })
|
|
7926
|
+
.filter(function(a) { return !removedByGuardrail[a.agentName.toUpperCase()]; })
|
|
7927
|
+
.map(function(a) { return { agent: a, tier: gethDomainTier(a.agentName, a.category, topUpDomain) }; })
|
|
7928
|
+
.filter(function(c) { return c.tier < GETH_DOMAIN_TIER_PROHIBITED; });
|
|
7887
7929
|
candidates = gethShuffle(candidates).sort(function(x, y) {
|
|
7888
|
-
|
|
7889
|
-
|
|
7930
|
+
if (x.tier !== y.tier) return x.tier - y.tier;
|
|
7931
|
+
return (categoriesInUse[x.agent.category] ? 1 : 0) - (categoriesInUse[y.agent.category] ? 1 : 0);
|
|
7932
|
+
}).map(function(c) { return c.agent; });
|
|
7890
7933
|
for (var ci = 0; ci < candidates.length && assignments.length < providerFloor; ci++) {
|
|
7891
7934
|
assignments.push({
|
|
7892
7935
|
agentName: candidates[ci].agentName,
|
|
@@ -8465,16 +8508,23 @@ class LocalGethOrchestrator {
|
|
|
8465
8508
|
'At most 12 claims, the most consequential first. If nothing deserves a warning, return an empty list.\n\n' +
|
|
8466
8509
|
'Respond ONLY with JSON: {"claims":[{"claim":"the claim, quoted or closely paraphrased","agents":["AGENT"],"status":"contradicted|doubtful|unsupported","note":"why, in one sentence"}]}';
|
|
8467
8510
|
|
|
8511
|
+
// A list of claims, even an empty one, or null when the answer is not one.
|
|
8512
|
+
function readClaims(text) {
|
|
8513
|
+
var json = extractJSON(text);
|
|
8514
|
+
if (json && Array.isArray(json.claims)) return json;
|
|
8515
|
+
// Cut off by the token limit: the claims already written still count.
|
|
8516
|
+
var salvagedClaims = gethSalvageArrayObjects(text, 'claims');
|
|
8517
|
+
return salvagedClaims.length > 0 ? { claims: salvagedClaims } : null;
|
|
8518
|
+
}
|
|
8519
|
+
|
|
8468
8520
|
try {
|
|
8521
|
+
// Any of the user's providers can do this: one that cannot answer in
|
|
8522
|
+
// the format is followed by the next.
|
|
8469
8523
|
var result = await this.orchestratorChat(session, systemPrompt,
|
|
8470
|
-
'Question: ' + session.prompt + '\n\nAgents\' final positions:\n\n' + body, 4096, '_fact_check'
|
|
8471
|
-
|
|
8472
|
-
|
|
8473
|
-
|
|
8474
|
-
var salvagedClaims = gethSalvageArrayObjects(result.text, 'claims');
|
|
8475
|
-
if (salvagedClaims.length === 0) return null;
|
|
8476
|
-
parsed = { claims: salvagedClaims };
|
|
8477
|
-
}
|
|
8524
|
+
'Question: ' + session.prompt + '\n\nAgents\' final positions:\n\n' + body, 4096, '_fact_check',
|
|
8525
|
+
function(text) { return readClaims(text) !== null; });
|
|
8526
|
+
var parsed = readClaims(result.text);
|
|
8527
|
+
if (!parsed) return null;
|
|
8478
8528
|
var allowed = ['contradicted', 'doubtful', 'unsupported'];
|
|
8479
8529
|
var claims = [];
|
|
8480
8530
|
for (var i = 0; i < parsed.claims.length && claims.length < 12; i++) {
|
|
@@ -8792,7 +8842,10 @@ class LocalGethOrchestrator {
|
|
|
8792
8842
|
|
|
8793
8843
|
try {
|
|
8794
8844
|
// 1024 tokens cut the list of omissions short on real deliberations.
|
|
8795
|
-
var result = await this.orchestratorChat(session, systemPrompt, userMessage, 4096, 'ATHENA')
|
|
8845
|
+
var result = await this.orchestratorChat(session, systemPrompt, userMessage, 4096, 'ATHENA', function(text) {
|
|
8846
|
+
var json = extractJSON(text);
|
|
8847
|
+
return !!(json && (json.verdict === 'PASS' || json.verdict === 'FLAG')) || gethSalvageAthenaVerdict(text) !== null;
|
|
8848
|
+
});
|
|
8796
8849
|
var parsed = extractJSON(result.text);
|
|
8797
8850
|
var truncated = false;
|
|
8798
8851
|
if (!parsed || (parsed.verdict !== 'PASS' && parsed.verdict !== 'FLAG')) {
|