agent-nuvira 3.3.12 → 3.3.13
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/dist/agents/agents/reasoner.d.ts.map +1 -1
- package/dist/agents/agents/reasoner.js +13 -0
- package/dist/agents/agents/reasoner.js.map +1 -1
- package/dist/agents/orchestrator.d.ts.map +1 -1
- package/dist/agents/orchestrator.js +29 -9
- package/dist/agents/orchestrator.js.map +1 -1
- package/dist/cli/chat.d.ts.map +1 -1
- package/dist/cli/chat.js +34 -7
- package/dist/cli/chat.js.map +1 -1
- package/dist/cli/cli-program.d.ts.map +1 -1
- package/dist/cli/cli-program.js +8 -0
- package/dist/cli/cli-program.js.map +1 -1
- package/dist/cli/config.d.ts.map +1 -1
- package/dist/cli/config.js +21 -3
- package/dist/cli/config.js.map +1 -1
- package/dist/cli/execute.d.ts.map +1 -1
- package/dist/cli/execute.js +6 -0
- package/dist/cli/execute.js.map +1 -1
- package/dist/cli/knowledge.d.ts +23 -0
- package/dist/cli/knowledge.d.ts.map +1 -0
- package/dist/cli/knowledge.js +132 -0
- package/dist/cli/knowledge.js.map +1 -0
- package/dist/cli/loop-executor.d.ts.map +1 -1
- package/dist/cli/loop-executor.js +45 -6
- package/dist/cli/loop-executor.js.map +1 -1
- package/dist/cli/omniroute-control.d.ts +88 -0
- package/dist/cli/omniroute-control.d.ts.map +1 -0
- package/dist/cli/omniroute-control.js +179 -0
- package/dist/cli/omniroute-control.js.map +1 -0
- package/dist/cli/omniroute.d.ts +21 -0
- package/dist/cli/omniroute.d.ts.map +1 -0
- package/dist/cli/omniroute.js +67 -0
- package/dist/cli/omniroute.js.map +1 -0
- package/dist/config/types.d.ts +8 -0
- package/dist/config/types.d.ts.map +1 -1
- package/dist/context/history.d.ts +21 -0
- package/dist/context/history.d.ts.map +1 -1
- package/dist/context/history.js +50 -0
- package/dist/context/history.js.map +1 -1
- package/dist/gateway/hook-contract.d.ts +173 -0
- package/dist/gateway/hook-contract.d.ts.map +1 -0
- package/dist/gateway/hook-contract.js +352 -0
- package/dist/gateway/hook-contract.js.map +1 -0
- package/dist/gateway/hooks.d.ts.map +1 -1
- package/dist/gateway/hooks.js +14 -0
- package/dist/gateway/hooks.js.map +1 -1
- package/dist/inference/interface.d.ts +17 -0
- package/dist/inference/interface.d.ts.map +1 -1
- package/dist/inference/model-id-validation.d.ts +57 -0
- package/dist/inference/model-id-validation.d.ts.map +1 -0
- package/dist/inference/model-id-validation.js +127 -0
- package/dist/inference/model-id-validation.js.map +1 -0
- package/dist/inference/openai-compat-adapter.d.ts.map +1 -1
- package/dist/inference/openai-compat-adapter.js +12 -1
- package/dist/inference/openai-compat-adapter.js.map +1 -1
- package/dist/inference/provider-catalog.d.ts +11 -0
- package/dist/inference/provider-catalog.d.ts.map +1 -1
- package/dist/inference/provider-catalog.js +80 -0
- package/dist/inference/provider-catalog.js.map +1 -1
- package/dist/inference/route-resolver.d.ts +2 -8
- package/dist/inference/route-resolver.d.ts.map +1 -1
- package/dist/inference/route-resolver.js +17 -0
- package/dist/inference/route-resolver.js.map +1 -1
- package/dist/inference/tool-call-utils.d.ts.map +1 -1
- package/dist/inference/tool-call-utils.js +10 -8
- package/dist/inference/tool-call-utils.js.map +1 -1
- package/dist/inference/tools.d.ts +1 -0
- package/dist/inference/tools.d.ts.map +1 -1
- package/dist/inference/tools.js +20 -3
- package/dist/inference/tools.js.map +1 -1
- package/dist/learning/auto-router.d.ts +53 -0
- package/dist/learning/auto-router.d.ts.map +1 -1
- package/dist/learning/auto-router.js +73 -0
- package/dist/learning/auto-router.js.map +1 -1
- package/dist/learning/error-repair.d.ts +23 -1
- package/dist/learning/error-repair.d.ts.map +1 -1
- package/dist/learning/error-repair.js +58 -0
- package/dist/learning/error-repair.js.map +1 -1
- package/dist/learning/knowledge-base.d.ts +124 -0
- package/dist/learning/knowledge-base.d.ts.map +1 -0
- package/dist/learning/knowledge-base.js +337 -0
- package/dist/learning/knowledge-base.js.map +1 -0
- package/dist/learning/model-selection.d.ts +2 -1
- package/dist/learning/model-selection.d.ts.map +1 -1
- package/dist/learning/model-selection.js +35 -2
- package/dist/learning/model-selection.js.map +1 -1
- package/dist/learning/project-docs.d.ts +83 -0
- package/dist/learning/project-docs.d.ts.map +1 -0
- package/dist/learning/project-docs.js +132 -0
- package/dist/learning/project-docs.js.map +1 -0
- package/dist/learning/quota-ledger.d.ts +13 -0
- package/dist/learning/quota-ledger.d.ts.map +1 -1
- package/dist/learning/quota-ledger.js +28 -0
- package/dist/learning/quota-ledger.js.map +1 -1
- package/dist/learning/seeded-benchmark.d.ts +14 -0
- package/dist/learning/seeded-benchmark.d.ts.map +1 -1
- package/dist/learning/seeded-benchmark.js +43 -4
- package/dist/learning/seeded-benchmark.js.map +1 -1
- package/dist/security/secret-scan.d.ts +156 -0
- package/dist/security/secret-scan.d.ts.map +1 -0
- package/dist/security/secret-scan.js +525 -0
- package/dist/security/secret-scan.js.map +1 -0
- package/dist/tools/plan-store.d.ts +24 -2
- package/dist/tools/plan-store.d.ts.map +1 -1
- package/dist/tools/plan-store.js +42 -2
- package/dist/tools/plan-store.js.map +1 -1
- package/dist/tools/registry.d.ts.map +1 -1
- package/dist/tools/registry.js +149 -1
- package/dist/tools/registry.js.map +1 -1
- package/dist/tools/remediation-ladder.d.ts +91 -0
- package/dist/tools/remediation-ladder.d.ts.map +1 -0
- package/dist/tools/remediation-ladder.js +308 -0
- package/dist/tools/remediation-ladder.js.map +1 -0
- package/dist/tools/run-terminal.d.ts.map +1 -1
- package/dist/tools/run-terminal.js +26 -2
- package/dist/tools/run-terminal.js.map +1 -1
- package/dist/tools/skills-hub.d.ts +7 -0
- package/dist/tools/skills-hub.d.ts.map +1 -1
- package/dist/tools/skills-hub.js +11 -2
- package/dist/tools/skills-hub.js.map +1 -1
- package/dist/tools/step-artifact.d.ts +35 -0
- package/dist/tools/step-artifact.d.ts.map +1 -0
- package/dist/tools/step-artifact.js +154 -0
- package/dist/tools/step-artifact.js.map +1 -0
- package/dist/tools/tool-loop.d.ts +6 -0
- package/dist/tools/tool-loop.d.ts.map +1 -1
- package/dist/tools/tool-loop.js +27 -3
- package/dist/tools/tool-loop.js.map +1 -1
- package/dist/tools/toolsets.js +4 -4
- package/dist/tools/toolsets.js.map +1 -1
- package/dist/tools/worktree.d.ts +11 -2
- package/dist/tools/worktree.d.ts.map +1 -1
- package/dist/tools/worktree.js +11 -2
- package/dist/tools/worktree.js.map +1 -1
- package/dist/web-dashboard/server.d.ts +29 -0
- package/dist/web-dashboard/server.d.ts.map +1 -1
- package/dist/web-dashboard/server.js +372 -5
- package/dist/web-dashboard/server.js.map +1 -1
- package/dist/web-dashboard/src/types.d.ts +66 -0
- package/dist/web-dashboard/src/types.d.ts.map +1 -1
- package/dist/web-dashboard/workspace-guard.d.ts +7 -0
- package/dist/web-dashboard/workspace-guard.d.ts.map +1 -1
- package/dist/web-dashboard/workspace-guard.js +70 -0
- package/dist/web-dashboard/workspace-guard.js.map +1 -1
- package/package.json +1 -1
- package/src/web-dashboard/public/assets/index-DhiuR4S2.js +210 -0
- package/src/web-dashboard/public/assets/index-DhiuR4S2.js.map +1 -0
- package/src/web-dashboard/public/assets/index-tK8Y2qHB.css +1 -0
- package/src/web-dashboard/public/index.html +2 -2
- package/src/web-dashboard/public/assets/index-BrZcYhy6.js +0 -207
- package/src/web-dashboard/public/assets/index-BrZcYhy6.js.map +0 -1
- package/src/web-dashboard/public/assets/index-DsWczTa6.css +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/web-dashboard/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,YAAY,EAAmC,MAAM,WAAW,CAAC;AAe1E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/web-dashboard/server.ts"],"names":[],"mappings":"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"}
|
|
@@ -25,6 +25,7 @@ import { loadEnv } from '../utils/env.js';
|
|
|
25
25
|
import { ConfigManager } from '../config/manager.js';
|
|
26
26
|
import { runAllChecks } from '../cli/doctor.js';
|
|
27
27
|
import { getAutoRouter } from '../learning/auto-router.js';
|
|
28
|
+
import { withStrictModel } from '../inference/route-resolver.js';
|
|
28
29
|
import { readRecallHits } from '../context/session-recall.js';
|
|
29
30
|
import { getRouterPromotion } from '../learning/router-promotion.js';
|
|
30
31
|
import { AUTH_CLEAR_THRESHOLD } from '../learning/key-hygiene.js';
|
|
@@ -2642,6 +2643,7 @@ function summarizeProvider(type, configManager) {
|
|
|
2642
2643
|
: maskKey(key),
|
|
2643
2644
|
model: c?.model,
|
|
2644
2645
|
baseUrl: c?.baseUrl,
|
|
2646
|
+
enabled: c?.enabled !== false,
|
|
2645
2647
|
};
|
|
2646
2648
|
}
|
|
2647
2649
|
/**
|
|
@@ -2868,6 +2870,26 @@ export function setGatewayShutdownForTest(action) {
|
|
|
2868
2870
|
function runDashboardShutdown() {
|
|
2869
2871
|
dashboardShutdownAction();
|
|
2870
2872
|
}
|
|
2873
|
+
/**
|
|
2874
|
+
* The OmniRoute lifecycle actions behind /api/admin/omniroute. `null` (default)
|
|
2875
|
+
* → the REAL probe/spawn/stop. Swappable for the same reason as the gateway-stop
|
|
2876
|
+
* action: the real probe hits the network and the real start/stop spawns or
|
|
2877
|
+
* signals a machine-wide process, so a ROUTE test must not do either.
|
|
2878
|
+
*/
|
|
2879
|
+
let omniRouteActions = null;
|
|
2880
|
+
/** Test hook: stub the OmniRoute lifecycle actions (null restores the real ones). */
|
|
2881
|
+
export function setOmniRouteActionsForTest(actions) {
|
|
2882
|
+
omniRouteActions = actions;
|
|
2883
|
+
}
|
|
2884
|
+
/** The real actions, lazily imported so dashboard boot does not pull the CLI in. */
|
|
2885
|
+
async function realOmniRouteActions() {
|
|
2886
|
+
const mod = await import('../cli/omniroute-control.js');
|
|
2887
|
+
return {
|
|
2888
|
+
status: () => mod.omnirouteStatus(),
|
|
2889
|
+
start: () => mod.startOmniRoute(),
|
|
2890
|
+
stop: () => mod.stopOmniRoute(),
|
|
2891
|
+
};
|
|
2892
|
+
}
|
|
2871
2893
|
/**
|
|
2872
2894
|
* Test hook: swap the pairing manager (e.g. for a fake-bridge manager) so
|
|
2873
2895
|
* /api/whatsapp integration tests never open a real WhatsApp connection.
|
|
@@ -3040,6 +3062,102 @@ function handleRequest(req, res) {
|
|
|
3040
3062
|
res.end(JSON.stringify(readHistoryData()));
|
|
3041
3063
|
return;
|
|
3042
3064
|
}
|
|
3065
|
+
// POST /api/history/clear — delete stored conversations. Body:
|
|
3066
|
+
// { target: 'session', id } — delete ONE session (the History tab
|
|
3067
|
+
// used to be read-only: only clear-all or an age band existed)
|
|
3068
|
+
// { target: 'older', olderThanMs } — time-based bulk sweep
|
|
3069
|
+
// { target: 'all' } — clear everything
|
|
3070
|
+
// Same gate as the continuity store: this is local memory, so an authenticated
|
|
3071
|
+
// admin/operator may change it. Reads (/api/history) stay open as before.
|
|
3072
|
+
if (pathname === '/api/history/clear' && req.method === 'POST') {
|
|
3073
|
+
const session = adminSessions.validate(bearerToken(req));
|
|
3074
|
+
if (!session) {
|
|
3075
|
+
writeJson(res, 401, { ok: false, error: 'Not authenticated — log in first.' });
|
|
3076
|
+
return;
|
|
3077
|
+
}
|
|
3078
|
+
if (!roleCan(session.role, 'routing.operate')) {
|
|
3079
|
+
writeJson(res, 403, { ok: false, error: `Access denied — role '${session.role}' cannot change conversation history.` });
|
|
3080
|
+
return;
|
|
3081
|
+
}
|
|
3082
|
+
void (async () => {
|
|
3083
|
+
const body = await readJsonBody(req);
|
|
3084
|
+
const target = typeof body?.target === 'string' ? body.target : '';
|
|
3085
|
+
const id = typeof body?.id === 'string' ? body.id : undefined;
|
|
3086
|
+
const olderThanMs = typeof body?.olderThanMs === 'number' && body.olderThanMs > 0 ? body.olderThanMs : 0;
|
|
3087
|
+
const { getChatHistory } = await import('../context/history.js');
|
|
3088
|
+
const history = getChatHistory();
|
|
3089
|
+
let removed = 0;
|
|
3090
|
+
if (target === 'session' && id) {
|
|
3091
|
+
if (await history.deleteSession(id))
|
|
3092
|
+
removed = 1;
|
|
3093
|
+
}
|
|
3094
|
+
else if (target === 'older' && olderThanMs > 0) {
|
|
3095
|
+
removed = history.pruneOlderThan(olderThanMs);
|
|
3096
|
+
}
|
|
3097
|
+
else if (target === 'all') {
|
|
3098
|
+
removed = history.count();
|
|
3099
|
+
history.clear();
|
|
3100
|
+
}
|
|
3101
|
+
else {
|
|
3102
|
+
writeJson(res, 400, { ok: false, error: "Expected { target: 'session', id } | { target: 'older', olderThanMs } | { target: 'all' }." });
|
|
3103
|
+
return;
|
|
3104
|
+
}
|
|
3105
|
+
writeJson(res, 200, { ok: true, removed });
|
|
3106
|
+
})();
|
|
3107
|
+
return;
|
|
3108
|
+
}
|
|
3109
|
+
// ── Hook contract (declarative lifecycle rules) ──────────────────────────
|
|
3110
|
+
// GET /api/hooks — the declared hooks plus the contract vocabulary the page
|
|
3111
|
+
// needs to render an editor (events, action kinds and their descriptions).
|
|
3112
|
+
// Reads are open like /api/history.
|
|
3113
|
+
// PUT /api/hooks — replace the whole set. Gated on routing.operate (admin or
|
|
3114
|
+
// operator), the same capability every other config write uses. The server
|
|
3115
|
+
// VALIDATES before persisting, so a bad declaration is a 400 and the
|
|
3116
|
+
// previously-saved set stays in force.
|
|
3117
|
+
if (pathname === '/api/hooks' && req.method === 'GET') {
|
|
3118
|
+
void (async () => {
|
|
3119
|
+
const m = await import('../gateway/hook-contract.js');
|
|
3120
|
+
writeJson(res, 200, {
|
|
3121
|
+
ok: true,
|
|
3122
|
+
file: m.hookDeclarationsFile(),
|
|
3123
|
+
hooks: m.getHookDeclarations(),
|
|
3124
|
+
events: m.HOOK_EVENTS,
|
|
3125
|
+
eventDescriptions: m.HOOK_EVENT_DESCRIPTIONS,
|
|
3126
|
+
actionKinds: m.HOOK_ACTION_KINDS,
|
|
3127
|
+
actionDescriptions: m.HOOK_ACTION_DESCRIPTIONS,
|
|
3128
|
+
});
|
|
3129
|
+
})();
|
|
3130
|
+
return;
|
|
3131
|
+
}
|
|
3132
|
+
if (pathname === '/api/hooks' && req.method === 'PUT') {
|
|
3133
|
+
void (async () => {
|
|
3134
|
+
const session = adminSessions.validate(bearerToken(req));
|
|
3135
|
+
if (!session) {
|
|
3136
|
+
writeJson(res, 401, { ok: false, error: 'Not authenticated — log in first.' });
|
|
3137
|
+
return;
|
|
3138
|
+
}
|
|
3139
|
+
if (!roleCan(session.role, 'routing.operate')) {
|
|
3140
|
+
writeJson(res, 403, {
|
|
3141
|
+
ok: false,
|
|
3142
|
+
error: `Access denied — role '${session.role}' cannot change hooks (requires admin or operator).`,
|
|
3143
|
+
});
|
|
3144
|
+
return;
|
|
3145
|
+
}
|
|
3146
|
+
const body = await readJsonBody(req);
|
|
3147
|
+
if (!body || !Array.isArray(body.hooks)) {
|
|
3148
|
+
writeJson(res, 400, { ok: false, error: 'Invalid JSON body — expected { hooks: [...] }.' });
|
|
3149
|
+
return;
|
|
3150
|
+
}
|
|
3151
|
+
const m = await import('../gateway/hook-contract.js');
|
|
3152
|
+
const saved = m.setHookDeclarations(body.hooks);
|
|
3153
|
+
if (!saved.ok) {
|
|
3154
|
+
writeJson(res, 400, { ok: false, error: saved.error });
|
|
3155
|
+
return;
|
|
3156
|
+
}
|
|
3157
|
+
writeJson(res, 200, { ok: true, hooks: saved.declarations });
|
|
3158
|
+
})();
|
|
3159
|
+
return;
|
|
3160
|
+
}
|
|
3043
3161
|
if (pathname === '/api/benchmarks') {
|
|
3044
3162
|
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
3045
3163
|
res.end(JSON.stringify(readBenchmarkData()));
|
|
@@ -3212,6 +3330,10 @@ function handleRequest(req, res) {
|
|
|
3212
3330
|
icon: entry?.icon,
|
|
3213
3331
|
envVar: entry?.envVar || null,
|
|
3214
3332
|
keyless: entry?.keyless === true,
|
|
3333
|
+
// What it is / how to set it up — the dashboard renders these beside
|
|
3334
|
+
// the key fields. Optional: most providers need no explanation.
|
|
3335
|
+
...(entry?.description ? { description: entry.description } : {}),
|
|
3336
|
+
...(entry?.setup ? { setup: entry.setup } : {}),
|
|
3215
3337
|
};
|
|
3216
3338
|
});
|
|
3217
3339
|
writeJson(res, 200, { providers });
|
|
@@ -3325,6 +3447,67 @@ function handleRequest(req, res) {
|
|
|
3325
3447
|
})();
|
|
3326
3448
|
return;
|
|
3327
3449
|
}
|
|
3450
|
+
// ── OmniRoute gateway lifecycle (the EXTERNAL AI gateway on port 20128) ──
|
|
3451
|
+
// OmniRoute is a separate long-lived process nuvira does not embed; the Admin
|
|
3452
|
+
// page could configure it as a provider but not start/stop it or say whether
|
|
3453
|
+
// it was up. GET reports reachability (a real HTTP probe — a 401 counts as UP),
|
|
3454
|
+
// POST { action: 'start' | 'stop' } drives it. Reads need a session; start/stop
|
|
3455
|
+
// need gateway.manage (the same gate as `nuvira omniroute start|stop` and
|
|
3456
|
+
// `nuvira gateway stop`).
|
|
3457
|
+
if (pathname === '/api/admin/omniroute' && (req.method === 'GET' || req.method === 'POST')) {
|
|
3458
|
+
void (async () => {
|
|
3459
|
+
const session = adminSessions.validate(bearerToken(req));
|
|
3460
|
+
if (!session) {
|
|
3461
|
+
writeJson(res, 401, { ok: false, error: 'Not authenticated — log in first.' });
|
|
3462
|
+
return;
|
|
3463
|
+
}
|
|
3464
|
+
const actions = omniRouteActions ?? (await realOmniRouteActions());
|
|
3465
|
+
try {
|
|
3466
|
+
if (req.method === 'GET') {
|
|
3467
|
+
const status = await actions.status();
|
|
3468
|
+
writeJson(res, 200, { ok: true, status });
|
|
3469
|
+
return;
|
|
3470
|
+
}
|
|
3471
|
+
if (!roleCan(session.role, 'gateway.manage')) {
|
|
3472
|
+
writeJson(res, 403, {
|
|
3473
|
+
ok: false,
|
|
3474
|
+
error: `Access denied — role '${session.role}' cannot start or stop the OmniRoute gateway (requires admin or operator).`,
|
|
3475
|
+
});
|
|
3476
|
+
return;
|
|
3477
|
+
}
|
|
3478
|
+
const body = await readJsonBody(req);
|
|
3479
|
+
const action = body?.action;
|
|
3480
|
+
if (action === 'start') {
|
|
3481
|
+
const result = await actions.start();
|
|
3482
|
+
writeJson(res, 200, {
|
|
3483
|
+
ok: result.ok,
|
|
3484
|
+
action,
|
|
3485
|
+
started: result.started,
|
|
3486
|
+
detail: result.detail,
|
|
3487
|
+
status: result.status,
|
|
3488
|
+
});
|
|
3489
|
+
return;
|
|
3490
|
+
}
|
|
3491
|
+
if (action === 'stop') {
|
|
3492
|
+
const result = await actions.stop();
|
|
3493
|
+
writeJson(res, 200, {
|
|
3494
|
+
ok: result.stopped,
|
|
3495
|
+
action,
|
|
3496
|
+
stopped: result.stopped,
|
|
3497
|
+
reason: result.reason,
|
|
3498
|
+
pid: result.pid,
|
|
3499
|
+
status: await actions.status(),
|
|
3500
|
+
});
|
|
3501
|
+
return;
|
|
3502
|
+
}
|
|
3503
|
+
writeJson(res, 400, { ok: false, error: 'Invalid action — expected "start" or "stop".' });
|
|
3504
|
+
}
|
|
3505
|
+
catch (err) {
|
|
3506
|
+
writeJson(res, 500, { ok: false, error: err instanceof Error ? err.message : String(err) });
|
|
3507
|
+
}
|
|
3508
|
+
})();
|
|
3509
|
+
return;
|
|
3510
|
+
}
|
|
3328
3511
|
// ── Agent Hub toggles (I5) — admin-gated writes honored by the I1 runtime
|
|
3329
3512
|
// gate (tool-loop schema + execution gating), so the dashboard toggle is
|
|
3330
3513
|
// NEVER cosmetic. Same config the CLI writes (`nuvira tools toolsets`);
|
|
@@ -3623,6 +3806,121 @@ function handleRequest(req, res) {
|
|
|
3623
3806
|
})();
|
|
3624
3807
|
return;
|
|
3625
3808
|
}
|
|
3809
|
+
// ── Knowledge base (tag-scoped retrieval over the operator's own documents) ──
|
|
3810
|
+
// Thin endpoints over learning/knowledge-base.ts: list tags, ingest a file or
|
|
3811
|
+
// folder under a tag, query a tag, and forget a tag. Documents are extracted,
|
|
3812
|
+
// chunked and embedded ONCE on ingest, so a query only embeds the question.
|
|
3813
|
+
// Reads list a tag's metadata; writes (ingest/forget) need routing.operate.
|
|
3814
|
+
if (pathname === '/api/knowledge' && req.method === 'GET') {
|
|
3815
|
+
void (async () => {
|
|
3816
|
+
const session = adminSessions.validate(bearerToken(req));
|
|
3817
|
+
if (!session) {
|
|
3818
|
+
writeJson(res, 401, { ok: false, error: 'Not authenticated — log in first.' });
|
|
3819
|
+
return;
|
|
3820
|
+
}
|
|
3821
|
+
try {
|
|
3822
|
+
const { listKnowledgeTags } = await import('../learning/knowledge-base.js');
|
|
3823
|
+
writeJson(res, 200, { ok: true, tags: listKnowledgeTags() });
|
|
3824
|
+
}
|
|
3825
|
+
catch (err) {
|
|
3826
|
+
writeJson(res, 500, { ok: false, error: err instanceof Error ? err.message : String(err) });
|
|
3827
|
+
}
|
|
3828
|
+
})();
|
|
3829
|
+
return;
|
|
3830
|
+
}
|
|
3831
|
+
if (pathname === '/api/knowledge/ingest' && req.method === 'POST') {
|
|
3832
|
+
void (async () => {
|
|
3833
|
+
const session = adminSessions.validate(bearerToken(req));
|
|
3834
|
+
if (!session) {
|
|
3835
|
+
writeJson(res, 401, { ok: false, error: 'Not authenticated — log in first.' });
|
|
3836
|
+
return;
|
|
3837
|
+
}
|
|
3838
|
+
if (!roleCan(session.role, 'routing.operate')) {
|
|
3839
|
+
writeJson(res, 403, {
|
|
3840
|
+
ok: false,
|
|
3841
|
+
error: `Access denied — role '${session.role}' cannot ingest documents (requires admin or operator).`,
|
|
3842
|
+
});
|
|
3843
|
+
return;
|
|
3844
|
+
}
|
|
3845
|
+
const body = await readJsonBody(req);
|
|
3846
|
+
const tag = typeof body?.tag === 'string' ? body.tag.trim() : '';
|
|
3847
|
+
const paths = Array.isArray(body?.paths) ? body.paths.filter((p) => typeof p === 'string' && p.trim().length > 0) : [];
|
|
3848
|
+
if (!tag) {
|
|
3849
|
+
writeJson(res, 400, { ok: false, error: 'A tag is required.' });
|
|
3850
|
+
return;
|
|
3851
|
+
}
|
|
3852
|
+
if (paths.length === 0) {
|
|
3853
|
+
writeJson(res, 400, { ok: false, error: 'At least one file or folder path is required.' });
|
|
3854
|
+
return;
|
|
3855
|
+
}
|
|
3856
|
+
try {
|
|
3857
|
+
const { ingestKnowledge } = await import('../learning/knowledge-base.js');
|
|
3858
|
+
const result = await ingestKnowledge(tag, paths);
|
|
3859
|
+
writeJson(res, 200, { ok: true, ...result });
|
|
3860
|
+
}
|
|
3861
|
+
catch (err) {
|
|
3862
|
+
writeJson(res, 400, { ok: false, error: err instanceof Error ? err.message : String(err) });
|
|
3863
|
+
}
|
|
3864
|
+
})();
|
|
3865
|
+
return;
|
|
3866
|
+
}
|
|
3867
|
+
if (pathname === '/api/knowledge/query' && req.method === 'POST') {
|
|
3868
|
+
void (async () => {
|
|
3869
|
+
const session = adminSessions.validate(bearerToken(req));
|
|
3870
|
+
if (!session) {
|
|
3871
|
+
writeJson(res, 401, { ok: false, error: 'Not authenticated — log in first.' });
|
|
3872
|
+
return;
|
|
3873
|
+
}
|
|
3874
|
+
const body = await readJsonBody(req);
|
|
3875
|
+
const tag = typeof body?.tag === 'string' ? body.tag.trim() : '';
|
|
3876
|
+
const question = typeof body?.question === 'string' ? body.question.trim() : '';
|
|
3877
|
+
const topK = typeof body?.topK === 'number' ? body.topK : undefined;
|
|
3878
|
+
if (!tag || !question) {
|
|
3879
|
+
writeJson(res, 400, { ok: false, error: 'A tag and a question are required.' });
|
|
3880
|
+
return;
|
|
3881
|
+
}
|
|
3882
|
+
try {
|
|
3883
|
+
const { queryKnowledge } = await import('../learning/knowledge-base.js');
|
|
3884
|
+
const hits = await queryKnowledge(tag, question, { topK });
|
|
3885
|
+
writeJson(res, 200, { ok: true, tag, hits });
|
|
3886
|
+
}
|
|
3887
|
+
catch (err) {
|
|
3888
|
+
writeJson(res, 500, { ok: false, error: err instanceof Error ? err.message : String(err) });
|
|
3889
|
+
}
|
|
3890
|
+
})();
|
|
3891
|
+
return;
|
|
3892
|
+
}
|
|
3893
|
+
if (pathname === '/api/knowledge/forget' && req.method === 'POST') {
|
|
3894
|
+
void (async () => {
|
|
3895
|
+
const session = adminSessions.validate(bearerToken(req));
|
|
3896
|
+
if (!session) {
|
|
3897
|
+
writeJson(res, 401, { ok: false, error: 'Not authenticated — log in first.' });
|
|
3898
|
+
return;
|
|
3899
|
+
}
|
|
3900
|
+
if (!roleCan(session.role, 'routing.operate')) {
|
|
3901
|
+
writeJson(res, 403, {
|
|
3902
|
+
ok: false,
|
|
3903
|
+
error: `Access denied — role '${session.role}' cannot remove knowledge tags (requires admin or operator).`,
|
|
3904
|
+
});
|
|
3905
|
+
return;
|
|
3906
|
+
}
|
|
3907
|
+
const body = await readJsonBody(req);
|
|
3908
|
+
const tag = typeof body?.tag === 'string' ? body.tag.trim() : '';
|
|
3909
|
+
if (!tag) {
|
|
3910
|
+
writeJson(res, 400, { ok: false, error: 'A tag is required.' });
|
|
3911
|
+
return;
|
|
3912
|
+
}
|
|
3913
|
+
try {
|
|
3914
|
+
const { forgetKnowledgeTag } = await import('../learning/knowledge-base.js');
|
|
3915
|
+
const removed = await forgetKnowledgeTag(tag);
|
|
3916
|
+
writeJson(res, 200, { ok: true, removed });
|
|
3917
|
+
}
|
|
3918
|
+
catch (err) {
|
|
3919
|
+
writeJson(res, 500, { ok: false, error: err instanceof Error ? err.message : String(err) });
|
|
3920
|
+
}
|
|
3921
|
+
})();
|
|
3922
|
+
return;
|
|
3923
|
+
}
|
|
3626
3924
|
// ── PA4 — save skill env vars to ~/.nuvira/.env (dashboard secret capture) ──
|
|
3627
3925
|
if (pathname === '/api/skills/secrets' && req.method === 'POST') {
|
|
3628
3926
|
void (async () => {
|
|
@@ -4569,6 +4867,26 @@ function handleRequest(req, res) {
|
|
|
4569
4867
|
}
|
|
4570
4868
|
if (typeof body.runner === 'string' && body.runner.trim().length > 0)
|
|
4571
4869
|
updates.runner = body.runner.trim();
|
|
4870
|
+
// The On/Off switch. `false` removes the provider from the auto-routing
|
|
4871
|
+
// pool WITHOUT deleting its credentials; `true` re-admits it.
|
|
4872
|
+
if (typeof body.enabled === 'boolean')
|
|
4873
|
+
updates.enabled = body.enabled;
|
|
4874
|
+
// A3 — a model id is validated against the provider's LIVE list before
|
|
4875
|
+
// it is written, so a typo cannot become a silent substitution at run
|
|
4876
|
+
// time. An unreachable provider is saved unverified (never blocked); a
|
|
4877
|
+
// reachable one that does not serve the id is refused with suggestions.
|
|
4878
|
+
if (typeof updates.model === 'string' && updates.model) {
|
|
4879
|
+
const { validateModelIdForProvider } = await import('../inference/model-id-validation.js');
|
|
4880
|
+
const verdict = await validateModelIdForProvider(type, updates.model, configManager);
|
|
4881
|
+
if (!verdict.ok) {
|
|
4882
|
+
writeJson(res, 400, {
|
|
4883
|
+
ok: false,
|
|
4884
|
+
error: verdict.message,
|
|
4885
|
+
suggestions: verdict.suggestions ?? [],
|
|
4886
|
+
});
|
|
4887
|
+
return;
|
|
4888
|
+
}
|
|
4889
|
+
}
|
|
4572
4890
|
// Raw config (vault refs INTACT) — never save a resolved key back to
|
|
4573
4891
|
// plaintext (the documented resolveVaultRefs footgun).
|
|
4574
4892
|
const raw = configManager.getAll().providers[type] || {};
|
|
@@ -4584,7 +4902,7 @@ function handleRequest(req, res) {
|
|
|
4584
4902
|
// explicit undefineds, so the fields vanish from the file.
|
|
4585
4903
|
if (req.method === 'DELETE') {
|
|
4586
4904
|
const cleared = configManager.clearProviderApiKey(type);
|
|
4587
|
-
configManager.save({ providers: { [type]: { apiKey: undefined, baseUrl: undefined, model: undefined, runner: undefined } } });
|
|
4905
|
+
configManager.save({ providers: { [type]: { apiKey: undefined, baseUrl: undefined, model: undefined, runner: undefined, enabled: undefined } } });
|
|
4588
4906
|
clearModelListCache();
|
|
4589
4907
|
// An ENV-sourced key cannot be removed from the file (env re-injects on
|
|
4590
4908
|
// every load) — surface that so the UI warns instead of hiding the row.
|
|
@@ -6277,6 +6595,11 @@ function handleRequest(req, res) {
|
|
|
6277
6595
|
// POST /api/continuity/clear — forget stored continuity data. Body:
|
|
6278
6596
|
// { target: 'sessions' | 'recall' } — clear all of one kind
|
|
6279
6597
|
// { target: 'session' | 'recall-entry', id } — clear one entry
|
|
6598
|
+
// { target: 'sessions' | 'recall', olderThanMs } — TIME-BASED bulk: clear
|
|
6599
|
+
// only entries older than now − olderThanMs. Per-entry forgetting is fine
|
|
6600
|
+
// for a handful of records but tedious for a store that grows on every
|
|
6601
|
+
// run, so "forget anything older than a week" is one request instead of
|
|
6602
|
+
// N. Absent/<=0 → the existing clear-all behaviour, unchanged.
|
|
6280
6603
|
if (pathname === '/api/continuity/clear' && req.method === 'POST') {
|
|
6281
6604
|
const session = adminSessions.validate(bearerToken(req));
|
|
6282
6605
|
if (!session) {
|
|
@@ -6291,8 +6614,23 @@ function handleRequest(req, res) {
|
|
|
6291
6614
|
const body = await readJsonBody(req);
|
|
6292
6615
|
const target = typeof body?.target === 'string' ? body.target : '';
|
|
6293
6616
|
const id = typeof body?.id === 'string' ? body.id : undefined;
|
|
6617
|
+
const olderThanMs = typeof body?.olderThanMs === 'number' && body.olderThanMs > 0 ? body.olderThanMs : 0;
|
|
6618
|
+
const cutoff = olderThanMs > 0 ? Date.now() - olderThanMs : 0;
|
|
6294
6619
|
let removed = 0;
|
|
6295
|
-
if (target === 'sessions') {
|
|
6620
|
+
if (target === 'sessions' && cutoff > 0) {
|
|
6621
|
+
// Time-based bulk: only snapshots saved before the cutoff.
|
|
6622
|
+
const { listSessionSnapshots, clearSession } = await import('../learning/session-store.js');
|
|
6623
|
+
for (const s of listSessionSnapshots())
|
|
6624
|
+
if (s.savedAt < cutoff && clearSession(s.id))
|
|
6625
|
+
removed += 1;
|
|
6626
|
+
}
|
|
6627
|
+
else if (target === 'recall' && cutoff > 0) {
|
|
6628
|
+
const { listRecallEntries, removeRecallEntry } = await import('../learning/session-recall.js');
|
|
6629
|
+
for (const e of listRecallEntries())
|
|
6630
|
+
if (e.savedAt < cutoff && removeRecallEntry(e.id))
|
|
6631
|
+
removed += 1;
|
|
6632
|
+
}
|
|
6633
|
+
else if (target === 'sessions') {
|
|
6296
6634
|
const { listSessionSnapshots, clearSession } = await import('../learning/session-store.js');
|
|
6297
6635
|
for (const s of listSessionSnapshots())
|
|
6298
6636
|
if (clearSession(s.id))
|
|
@@ -6314,7 +6652,7 @@ function handleRequest(req, res) {
|
|
|
6314
6652
|
removed = 1;
|
|
6315
6653
|
}
|
|
6316
6654
|
else {
|
|
6317
|
-
writeJson(res, 400, { ok: false, error: "Expected { target: 'sessions'|'recall'|'session'|'recall-entry', id? }." });
|
|
6655
|
+
writeJson(res, 400, { ok: false, error: "Expected { target: 'sessions'|'recall'|'session'|'recall-entry', id?, olderThanMs? }." });
|
|
6318
6656
|
return;
|
|
6319
6657
|
}
|
|
6320
6658
|
writeJson(res, 200, { ok: true, removed });
|
|
@@ -6408,6 +6746,11 @@ function handleRequest(req, res) {
|
|
|
6408
6746
|
: newChatSessionId();
|
|
6409
6747
|
const provider = typeof body?.provider === 'string' ? body.provider : undefined;
|
|
6410
6748
|
const model = typeof body?.model === 'string' ? body.model : undefined;
|
|
6749
|
+
// Strict-model pin for THIS turn (the dashboard chat's "pin this model
|
|
6750
|
+
// only" switch). Scoped to the turn with AsyncLocalStorage rather than a
|
|
6751
|
+
// process env write, because two sessions can run concurrently and a
|
|
6752
|
+
// global mutation would leak one user's pin into the other's turn.
|
|
6753
|
+
const strict = body?.strict === true;
|
|
6411
6754
|
// WS5 (#27) — per-turn isolation and resume, from the GUI.
|
|
6412
6755
|
//
|
|
6413
6756
|
// Read as a strict TRI-state, because the three cases are genuinely
|
|
@@ -6516,7 +6859,7 @@ function handleRequest(req, res) {
|
|
|
6516
6859
|
// Mark the failover log BEFORE the turn so a failure can report which
|
|
6517
6860
|
// models were actually tried (same contract as the gateway).
|
|
6518
6861
|
const attemptMark = markFailoverAttempts();
|
|
6519
|
-
const result = await chatConsole.answer(sessionId, message, {
|
|
6862
|
+
const result = await withStrictModel(strict, () => chatConsole.answer(sessionId, message, {
|
|
6520
6863
|
provider,
|
|
6521
6864
|
model,
|
|
6522
6865
|
projectContext,
|
|
@@ -6525,7 +6868,7 @@ function handleRequest(req, res) {
|
|
|
6525
6868
|
...(worktree === undefined ? {} : { worktree }),
|
|
6526
6869
|
...(keepWorktree === undefined ? {} : { keepWorktree }),
|
|
6527
6870
|
...(resume === undefined ? {} : { resume }),
|
|
6528
|
-
});
|
|
6871
|
+
}));
|
|
6529
6872
|
if (!result.ok) {
|
|
6530
6873
|
writeJson(res, 400, {
|
|
6531
6874
|
ok: false,
|
|
@@ -6538,6 +6881,29 @@ function handleRequest(req, res) {
|
|
|
6538
6881
|
// enforced (see ChatRetryBroker). Without this the console was a dead end
|
|
6539
6882
|
// — the reader had to wait and re-send the message themselves.
|
|
6540
6883
|
let content = result.content ?? '';
|
|
6884
|
+
// When a model was pinned WITHOUT strict mode, say plainly what happened
|
|
6885
|
+
// to the pin: a turn that ran on another provider was auto-routed, and a
|
|
6886
|
+
// pinned model that failed may be handed off on the next attempt. Either
|
|
6887
|
+
// way the reader is told how to force the pinned model — enable strict
|
|
6888
|
+
// mode — instead of discovering the switch later.
|
|
6889
|
+
let routingNotice;
|
|
6890
|
+
if (provider) {
|
|
6891
|
+
const requested = `${provider}${model ? `/${model}` : ''}`;
|
|
6892
|
+
const served = result.provider ? `${result.provider}${result.model ? `/${result.model}` : ''}` : '';
|
|
6893
|
+
const substituted = Boolean(served) && result.provider !== provider;
|
|
6894
|
+
if (strict) {
|
|
6895
|
+
if (result.generationFailed === true) {
|
|
6896
|
+
routingNotice =
|
|
6897
|
+
'Strict model mode is on, so the turn stopped rather than falling back to another model.';
|
|
6898
|
+
}
|
|
6899
|
+
}
|
|
6900
|
+
else if (substituted) {
|
|
6901
|
+
routingNotice = `Auto routing took over: this turn ran on ${served} because your pinned ${requested} was not available. To work with ${requested} only, enable strict model mode.`;
|
|
6902
|
+
}
|
|
6903
|
+
else if (result.generationFailed === true) {
|
|
6904
|
+
routingNotice = `Your pinned ${requested} could not complete this turn, so auto routing may hand the work to another model. To stay on this model only, enable strict model mode.`;
|
|
6905
|
+
}
|
|
6906
|
+
}
|
|
6541
6907
|
// Did the offer we are about to send get a mechanism behind it? The client
|
|
6542
6908
|
// uses this to stop offering "↻ Retry" for a turn the server is already
|
|
6543
6909
|
// retrying on its own — a manual re-send on top of the queued one would
|
|
@@ -6569,6 +6935,7 @@ function handleRequest(req, res) {
|
|
|
6569
6935
|
followups: result.followups ?? [],
|
|
6570
6936
|
provider: result.provider ?? null,
|
|
6571
6937
|
model: result.model ?? null,
|
|
6938
|
+
...(routingNotice ? { routingNotice } : {}),
|
|
6572
6939
|
// WS1 — the findings this turn recorded, with the gate's verdicts, so
|
|
6573
6940
|
// a dashboard client reads the same wire form the CLI, the gateway and
|
|
6574
6941
|
// the subagent report (the GUI card is a rendering decision; the FACT
|