@miller-tech/uap 1.0.0 → 1.2.0
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/benchmarks/benchmark.d.ts +8 -8
- package/dist/benchmarks/improved-benchmark.d.ts.map +1 -1
- package/dist/benchmarks/improved-benchmark.js +10 -23
- package/dist/benchmarks/improved-benchmark.js.map +1 -1
- package/dist/benchmarks/model-integration.d.ts.map +1 -1
- package/dist/benchmarks/model-integration.js +22 -23
- package/dist/benchmarks/model-integration.js.map +1 -1
- package/dist/bin/policy.js +67 -11
- package/dist/bin/policy.js.map +1 -1
- package/dist/cli/dashboard.d.ts +2 -1
- package/dist/cli/dashboard.d.ts.map +1 -1
- package/dist/cli/dashboard.js +399 -10
- package/dist/cli/dashboard.js.map +1 -1
- package/dist/cli/model.js +12 -12
- package/dist/cli/model.js.map +1 -1
- package/dist/cli/setup-wizard.d.ts.map +1 -1
- package/dist/cli/setup-wizard.js +24 -0
- package/dist/cli/setup-wizard.js.map +1 -1
- package/dist/coordination/deploy-batcher.d.ts +1 -0
- package/dist/coordination/deploy-batcher.d.ts.map +1 -1
- package/dist/coordination/deploy-batcher.js +24 -25
- package/dist/coordination/deploy-batcher.js.map +1 -1
- package/dist/dashboard/data-service.d.ts +94 -0
- package/dist/dashboard/data-service.d.ts.map +1 -0
- package/dist/dashboard/data-service.js +286 -0
- package/dist/dashboard/data-service.js.map +1 -0
- package/dist/dashboard/index.d.ts +5 -0
- package/dist/dashboard/index.d.ts.map +1 -0
- package/dist/dashboard/index.js +3 -0
- package/dist/dashboard/index.js.map +1 -0
- package/dist/dashboard/server.d.ts +15 -0
- package/dist/dashboard/server.d.ts.map +1 -0
- package/dist/dashboard/server.js +158 -0
- package/dist/dashboard/server.js.map +1 -0
- package/dist/mcp-router/session-stats.d.ts +9 -0
- package/dist/mcp-router/session-stats.d.ts.map +1 -1
- package/dist/mcp-router/session-stats.js +19 -3
- package/dist/mcp-router/session-stats.js.map +1 -1
- package/dist/memory/adaptive-context.d.ts +1 -0
- package/dist/memory/adaptive-context.d.ts.map +1 -1
- package/dist/memory/adaptive-context.js +4 -0
- package/dist/memory/adaptive-context.js.map +1 -1
- package/dist/memory/embeddings.d.ts.map +1 -1
- package/dist/memory/embeddings.js +4 -4
- package/dist/memory/embeddings.js.map +1 -1
- package/dist/memory/model-router.d.ts +1 -1
- package/dist/memory/model-router.d.ts.map +1 -1
- package/dist/memory/model-router.js +52 -1
- package/dist/memory/model-router.js.map +1 -1
- package/dist/memory/predictive-memory.d.ts.map +1 -1
- package/dist/memory/predictive-memory.js +4 -3
- package/dist/memory/predictive-memory.js.map +1 -1
- package/dist/models/analytics.d.ts +93 -0
- package/dist/models/analytics.d.ts.map +1 -0
- package/dist/models/analytics.js +205 -0
- package/dist/models/analytics.js.map +1 -0
- package/dist/models/execution-profiles.d.ts +6 -0
- package/dist/models/execution-profiles.d.ts.map +1 -1
- package/dist/models/execution-profiles.js +15 -0
- package/dist/models/execution-profiles.js.map +1 -1
- package/dist/models/executor.d.ts.map +1 -1
- package/dist/models/executor.js +51 -17
- package/dist/models/executor.js.map +1 -1
- package/dist/models/index.d.ts +2 -0
- package/dist/models/index.d.ts.map +1 -1
- package/dist/models/index.js +2 -0
- package/dist/models/index.js.map +1 -1
- package/dist/models/router.d.ts +8 -0
- package/dist/models/router.d.ts.map +1 -1
- package/dist/models/router.js +39 -18
- package/dist/models/router.js.map +1 -1
- package/dist/models/types.d.ts +26 -0
- package/dist/models/types.d.ts.map +1 -1
- package/dist/models/types.js +39 -0
- package/dist/models/types.js.map +1 -1
- package/dist/models/unified-router.d.ts.map +1 -1
- package/dist/models/unified-router.js +4 -0
- package/dist/models/unified-router.js.map +1 -1
- package/dist/policies/database-manager.d.ts +1 -0
- package/dist/policies/database-manager.d.ts.map +1 -1
- package/dist/policies/database-manager.js +14 -2
- package/dist/policies/database-manager.js.map +1 -1
- package/dist/policies/policy-gate.d.ts +2 -2
- package/dist/policies/policy-gate.d.ts.map +1 -1
- package/dist/policies/policy-gate.js +6 -4
- package/dist/policies/policy-gate.js.map +1 -1
- package/dist/policies/policy-memory.d.ts +3 -0
- package/dist/policies/policy-memory.d.ts.map +1 -1
- package/dist/policies/policy-memory.js +11 -0
- package/dist/policies/policy-memory.js.map +1 -1
- package/dist/policies/schemas/policy.d.ts +3 -0
- package/dist/policies/schemas/policy.d.ts.map +1 -1
- package/dist/policies/schemas/policy.js +1 -0
- package/dist/policies/schemas/policy.js.map +1 -1
- package/dist/tasks/coordination.d.ts +18 -0
- package/dist/tasks/coordination.d.ts.map +1 -1
- package/dist/tasks/coordination.js +59 -1
- package/dist/tasks/coordination.js.map +1 -1
- package/dist/tasks/event-bus.d.ts +91 -0
- package/dist/tasks/event-bus.d.ts.map +1 -0
- package/dist/tasks/event-bus.js +123 -0
- package/dist/tasks/event-bus.js.map +1 -0
- package/dist/tasks/service.d.ts +5 -0
- package/dist/tasks/service.d.ts.map +1 -1
- package/dist/tasks/service.js +59 -0
- package/dist/tasks/service.js.map +1 -1
- package/dist/telemetry/session-telemetry.d.ts.map +1 -1
- package/dist/telemetry/session-telemetry.js +3 -0
- package/dist/telemetry/session-telemetry.js.map +1 -1
- package/dist/utils/concurrency-pool.d.ts +51 -0
- package/dist/utils/concurrency-pool.d.ts.map +1 -0
- package/dist/utils/concurrency-pool.js +80 -0
- package/dist/utils/concurrency-pool.js.map +1 -0
- package/dist/utils/system-resources.d.ts +47 -0
- package/dist/utils/system-resources.d.ts.map +1 -0
- package/dist/utils/system-resources.js +92 -0
- package/dist/utils/system-resources.js.map +1 -0
- package/docs/BENCHMARK_GAPS_AND_PLAN.md +146 -0
- package/docs/PARALLELISM_GAPS_AND_OPTIONS.md +422 -0
- package/docs/UAP_OPTIMIZATION_PLAN.md +638 -0
- package/package.json +4 -1
- package/templates/hooks/session-start.sh +8 -1
package/dist/cli/dashboard.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
type DashboardAction = 'overview' | 'tasks' | 'agents' | 'memory' | 'progress' | 'stats' | 'session' | 'benchmark';
|
|
1
|
+
type DashboardAction = 'overview' | 'tasks' | 'agents' | 'memory' | 'progress' | 'stats' | 'session' | 'benchmark' | 'policies' | 'models' | 'serve' | 'export' | 'history';
|
|
2
2
|
interface DashboardOptions {
|
|
3
3
|
verbose?: boolean;
|
|
4
4
|
compact?: boolean;
|
|
5
|
+
taskId?: string;
|
|
5
6
|
}
|
|
6
7
|
export declare function dashboardCommand(action: DashboardAction, options?: DashboardOptions): Promise<void>;
|
|
7
8
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dashboard.d.ts","sourceRoot":"","sources":["../../src/cli/dashboard.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"dashboard.d.ts","sourceRoot":"","sources":["../../src/cli/dashboard.ts"],"names":[],"mappings":"AAqCA,KAAK,eAAe,GAChB,UAAU,GACV,OAAO,GACP,QAAQ,GACR,QAAQ,GACR,UAAU,GACV,OAAO,GACP,SAAS,GACT,WAAW,GACX,UAAU,GACV,QAAQ,GACR,OAAO,GACP,QAAQ,GACR,SAAS,CAAC;AAEd,UAAU,gBAAgB;IACxB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,eAAe,EACvB,OAAO,GAAE,gBAAqB,GAC7B,OAAO,CAAC,IAAI,CAAC,CA0Cf;AA0qDD;;;;GAIG;AACH,wBAAgB,qBAAqB,IAAI,IAAI,CAuM5C;AAID;;;;;GAKG;AACH,wBAAgB,aAAa,IAAI,IAAI,CA0QpC"}
|
package/dist/cli/dashboard.js
CHANGED
|
@@ -10,6 +10,12 @@ import { SQLiteShortTermMemory } from '../memory/short-term/sqlite.js';
|
|
|
10
10
|
import { progressBar, stackedBar, stackedBarLegend, horizontalBarChart, table, tree, box, sectionHeader, keyValue, miniGauge, statusBadge, divider, bulletList, columns, } from './visualize.js';
|
|
11
11
|
import { STATUS_ICONS, TYPE_ICONS, PRIORITY_LABELS } from '../tasks/types.js';
|
|
12
12
|
import { globalSessionStats } from '../mcp-router/session-stats.js';
|
|
13
|
+
import { getPolicyMemoryManager } from '../policies/policy-memory.js';
|
|
14
|
+
import { getPolicyGate } from '../policies/policy-gate.js';
|
|
15
|
+
import { ModelRouter } from '../models/router.js';
|
|
16
|
+
import { ModelPresets } from '../models/types.js';
|
|
17
|
+
import { getModelAnalytics } from '../models/analytics.js';
|
|
18
|
+
import { detectExecutionProfile } from '../models/execution-profiles.js';
|
|
13
19
|
export async function dashboardCommand(action, options = {}) {
|
|
14
20
|
switch (action) {
|
|
15
21
|
case 'overview':
|
|
@@ -36,6 +42,93 @@ export async function dashboardCommand(action, options = {}) {
|
|
|
36
42
|
case 'benchmark':
|
|
37
43
|
showDashboard();
|
|
38
44
|
break;
|
|
45
|
+
case 'policies':
|
|
46
|
+
await showPoliciesDashboard(options);
|
|
47
|
+
break;
|
|
48
|
+
case 'models':
|
|
49
|
+
await showModelsDashboard(options);
|
|
50
|
+
break;
|
|
51
|
+
case 'serve':
|
|
52
|
+
await serveDashboard(options);
|
|
53
|
+
break;
|
|
54
|
+
case 'export':
|
|
55
|
+
await exportDashboard(options);
|
|
56
|
+
break;
|
|
57
|
+
case 'history':
|
|
58
|
+
await showHistory(options);
|
|
59
|
+
break;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
async function serveDashboard(_options) {
|
|
63
|
+
const { startDashboardServer } = await import('../dashboard/server.js');
|
|
64
|
+
const server = startDashboardServer({ port: 3847 });
|
|
65
|
+
// Keep alive until Ctrl+C
|
|
66
|
+
process.on('SIGINT', () => {
|
|
67
|
+
console.log('\nShutting down dashboard server...');
|
|
68
|
+
server.close();
|
|
69
|
+
process.exit(0);
|
|
70
|
+
});
|
|
71
|
+
process.on('SIGTERM', () => {
|
|
72
|
+
server.close();
|
|
73
|
+
process.exit(0);
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
async function exportDashboard(options) {
|
|
77
|
+
const { getDashboardData } = await import('../dashboard/data-service.js');
|
|
78
|
+
const data = await getDashboardData();
|
|
79
|
+
if (options.verbose) {
|
|
80
|
+
// CSV-like output for key tables
|
|
81
|
+
console.log('# Policies');
|
|
82
|
+
console.log('name,level,stage,category,active');
|
|
83
|
+
for (const p of data.policies) {
|
|
84
|
+
console.log(`${p.name},${p.level},${p.enforcementStage},${p.category},${p.isActive}`);
|
|
85
|
+
}
|
|
86
|
+
console.log('');
|
|
87
|
+
console.log('# Model Usage');
|
|
88
|
+
console.log('model,tasks,tokens_in,tokens_out,cost,success_rate');
|
|
89
|
+
for (const m of data.models.sessionUsage) {
|
|
90
|
+
console.log(`${m.modelId},${m.taskCount},${m.totalTokensIn},${m.totalTokensOut},${m.totalCost},${m.successRate}`);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
console.log(JSON.stringify(data, null, 2));
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
async function showHistory(_options) {
|
|
98
|
+
const cwd = process.cwd();
|
|
99
|
+
const snapshotDbPath = join(cwd, 'agents', 'data', 'memory', 'session_snapshots.db');
|
|
100
|
+
if (!existsSync(snapshotDbPath)) {
|
|
101
|
+
console.log(chalk.dim('No session history found. Snapshots are saved automatically.'));
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
try {
|
|
105
|
+
const db = new Database(snapshotDbPath, { readonly: true });
|
|
106
|
+
const rows = db
|
|
107
|
+
.prepare('SELECT id, timestamp, duration_ms, total_cost, tasks_completed, models_used FROM session_snapshots ORDER BY timestamp DESC LIMIT 20')
|
|
108
|
+
.all();
|
|
109
|
+
db.close();
|
|
110
|
+
if (rows.length === 0) {
|
|
111
|
+
console.log(chalk.dim('No session snapshots recorded yet.'));
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
console.log('');
|
|
115
|
+
console.log(chalk.bold.cyan(' Session History'));
|
|
116
|
+
console.log(divider(70));
|
|
117
|
+
console.log('');
|
|
118
|
+
console.log(` ${'Timestamp'.padEnd(22)} ${'Duration'.padEnd(12)} ${'Cost'.padEnd(10)} ${'Tasks'.padEnd(8)} Models`);
|
|
119
|
+
console.log(` ${'─'.repeat(22)} ${'─'.repeat(12)} ${'─'.repeat(10)} ${'─'.repeat(8)} ${'─'.repeat(16)}`);
|
|
120
|
+
for (const row of rows) {
|
|
121
|
+
const ts = row.timestamp.slice(0, 19);
|
|
122
|
+
const dur = row.duration_ms ? `${Math.round(row.duration_ms / 1000)}s` : '?';
|
|
123
|
+
const cost = row.total_cost ? `$${row.total_cost.toFixed(4)}` : '$0';
|
|
124
|
+
const tasks = String(row.tasks_completed || 0);
|
|
125
|
+
const models = row.models_used ? JSON.parse(row.models_used).join(', ') : '?';
|
|
126
|
+
console.log(` ${ts.padEnd(22)} ${dur.padEnd(12)} ${cost.padEnd(10)} ${tasks.padEnd(8)} ${models}`);
|
|
127
|
+
}
|
|
128
|
+
console.log('');
|
|
129
|
+
}
|
|
130
|
+
catch (error) {
|
|
131
|
+
console.error(chalk.red(error instanceof Error ? error.message : String(error)));
|
|
39
132
|
}
|
|
40
133
|
}
|
|
41
134
|
async function showOverview(_options) {
|
|
@@ -557,6 +650,22 @@ async function showMemoryDashboard(_options) {
|
|
|
557
650
|
for (const line of tree(layers))
|
|
558
651
|
console.log(line);
|
|
559
652
|
console.log('');
|
|
653
|
+
// Compression stats from session
|
|
654
|
+
console.log(sectionHeader('Context Compression'));
|
|
655
|
+
console.log('');
|
|
656
|
+
const sessionStats = globalSessionStats.getSummary();
|
|
657
|
+
if (sessionStats.totalCalls > 0) {
|
|
658
|
+
const rawKB = Math.round(sessionStats.totalRawBytes / 1024);
|
|
659
|
+
const ctxKB = Math.round(sessionStats.totalContextBytes / 1024);
|
|
660
|
+
console.log(` ${chalk.white('Raw bytes'.padEnd(25))} ${chalk.bold(rawKB + ' KB')}`);
|
|
661
|
+
console.log(` ${chalk.white('Context bytes'.padEnd(25))} ${chalk.bold(ctxKB + ' KB')}`);
|
|
662
|
+
console.log(` ${chalk.white('Savings'.padEnd(25))} ${chalk.green(sessionStats.savingsPercent)}`);
|
|
663
|
+
console.log(` ${chalk.white('Tool calls'.padEnd(25))} ${chalk.bold(String(sessionStats.totalCalls))}`);
|
|
664
|
+
}
|
|
665
|
+
else {
|
|
666
|
+
console.log(chalk.dim(' No compression data this session'));
|
|
667
|
+
}
|
|
668
|
+
console.log('');
|
|
560
669
|
}
|
|
561
670
|
catch (error) {
|
|
562
671
|
spinner.fail('Failed to load memory dashboard');
|
|
@@ -1081,19 +1190,30 @@ async function showSessionDashboard(options) {
|
|
|
1081
1190
|
console.log(chalk.dim(' Droids: None registered'));
|
|
1082
1191
|
}
|
|
1083
1192
|
console.log('');
|
|
1084
|
-
// Policies
|
|
1193
|
+
// Policies (DB-driven)
|
|
1085
1194
|
console.log(sectionHeader('Policies'));
|
|
1086
1195
|
console.log('');
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1196
|
+
try {
|
|
1197
|
+
const policyMgr = getPolicyMemoryManager();
|
|
1198
|
+
const allPolicies = await policyMgr.getAllPolicies();
|
|
1199
|
+
if (allPolicies.length > 0) {
|
|
1200
|
+
for (const policy of allPolicies) {
|
|
1201
|
+
const stageLabel = policy.enforcementStage || 'pre-exec';
|
|
1202
|
+
const levelColor = policy.level === 'REQUIRED'
|
|
1203
|
+
? chalk.red
|
|
1204
|
+
: policy.level === 'RECOMMENDED'
|
|
1205
|
+
? chalk.yellow
|
|
1206
|
+
: chalk.dim;
|
|
1207
|
+
console.log(` ${levelColor(policy.level.padEnd(14))} ${policy.name.slice(0, 30).padEnd(30)} ${chalk.dim(stageLabel)}`);
|
|
1208
|
+
}
|
|
1209
|
+
}
|
|
1210
|
+
else {
|
|
1211
|
+
console.log(chalk.dim(' No policies configured. Add with: uap policy add -f <file>'));
|
|
1212
|
+
}
|
|
1213
|
+
}
|
|
1214
|
+
catch {
|
|
1215
|
+
console.log(chalk.dim(' Policy DB not initialized'));
|
|
1094
1216
|
}
|
|
1095
|
-
for (const line of bulletList(policyItems))
|
|
1096
|
-
console.log(line);
|
|
1097
1217
|
console.log('');
|
|
1098
1218
|
// Open loops
|
|
1099
1219
|
if (openLoops.length > 0) {
|
|
@@ -1121,6 +1241,275 @@ async function showSessionDashboard(options) {
|
|
|
1121
1241
|
console.error(chalk.red(error instanceof Error ? error.message : String(error)));
|
|
1122
1242
|
}
|
|
1123
1243
|
}
|
|
1244
|
+
async function showPoliciesDashboard(options) {
|
|
1245
|
+
const spinner = ora('Loading policies dashboard...').start();
|
|
1246
|
+
try {
|
|
1247
|
+
const policyMgr = getPolicyMemoryManager();
|
|
1248
|
+
const gate = getPolicyGate();
|
|
1249
|
+
const allPolicies = await policyMgr.getAllPolicies();
|
|
1250
|
+
spinner.stop();
|
|
1251
|
+
console.log('');
|
|
1252
|
+
console.log(chalk.bold.cyan(' UAP Policies Dashboard'));
|
|
1253
|
+
console.log(divider(62));
|
|
1254
|
+
console.log('');
|
|
1255
|
+
// Active policies table
|
|
1256
|
+
console.log(sectionHeader(`Active Policies (${allPolicies.length})`));
|
|
1257
|
+
console.log('');
|
|
1258
|
+
if (allPolicies.length === 0) {
|
|
1259
|
+
console.log(chalk.dim(' No policies configured. Add with: uap policy add -f <file>'));
|
|
1260
|
+
}
|
|
1261
|
+
else {
|
|
1262
|
+
console.log(` ${'Name'.padEnd(28)} ${'Level'.padEnd(14)} ${'Stage'.padEnd(12)} ${'Category'.padEnd(10)} Status`);
|
|
1263
|
+
console.log(` ${'─'.repeat(28)} ${'─'.repeat(14)} ${'─'.repeat(12)} ${'─'.repeat(10)} ${'─'.repeat(6)}`);
|
|
1264
|
+
for (const policy of allPolicies) {
|
|
1265
|
+
const stage = policy.enforcementStage || 'pre-exec';
|
|
1266
|
+
const status = policy.isActive ? chalk.green('ON') : chalk.red('OFF');
|
|
1267
|
+
const levelColor = policy.level === 'REQUIRED'
|
|
1268
|
+
? chalk.red
|
|
1269
|
+
: policy.level === 'RECOMMENDED'
|
|
1270
|
+
? chalk.yellow
|
|
1271
|
+
: chalk.dim;
|
|
1272
|
+
console.log(` ${policy.name.slice(0, 28).padEnd(28)} ${levelColor(policy.level.padEnd(14))} ${stage.padEnd(12)} ${policy.category.padEnd(10)} ${status}`);
|
|
1273
|
+
}
|
|
1274
|
+
}
|
|
1275
|
+
console.log('');
|
|
1276
|
+
// Enforcement stages breakdown
|
|
1277
|
+
const stageGroups = {
|
|
1278
|
+
'pre-exec': 0,
|
|
1279
|
+
'post-exec': 0,
|
|
1280
|
+
review: 0,
|
|
1281
|
+
always: 0,
|
|
1282
|
+
};
|
|
1283
|
+
for (const p of allPolicies) {
|
|
1284
|
+
const stage = p.enforcementStage || 'pre-exec';
|
|
1285
|
+
stageGroups[stage] = (stageGroups[stage] || 0) + 1;
|
|
1286
|
+
}
|
|
1287
|
+
console.log(sectionHeader('Enforcement Stages'));
|
|
1288
|
+
console.log('');
|
|
1289
|
+
for (const [stage, count] of Object.entries(stageGroups)) {
|
|
1290
|
+
const barLen = Math.min(count * 5, 30);
|
|
1291
|
+
const bar = chalk.cyan('\u2588'.repeat(barLen)) + chalk.dim('\u2591'.repeat(30 - barLen));
|
|
1292
|
+
console.log(` ${stage.padEnd(12)} ${bar} ${count} policies`);
|
|
1293
|
+
}
|
|
1294
|
+
console.log('');
|
|
1295
|
+
// Level breakdown
|
|
1296
|
+
const levelGroups = { REQUIRED: 0, RECOMMENDED: 0, OPTIONAL: 0 };
|
|
1297
|
+
for (const p of allPolicies) {
|
|
1298
|
+
levelGroups[p.level] = (levelGroups[p.level] || 0) + 1;
|
|
1299
|
+
}
|
|
1300
|
+
console.log(sectionHeader('Enforcement Levels'));
|
|
1301
|
+
console.log('');
|
|
1302
|
+
for (const [level, count] of Object.entries(levelGroups)) {
|
|
1303
|
+
const color = level === 'REQUIRED' ? chalk.red : level === 'RECOMMENDED' ? chalk.yellow : chalk.dim;
|
|
1304
|
+
console.log(` ${color(level.padEnd(14))} ${chalk.bold(String(count))}`);
|
|
1305
|
+
}
|
|
1306
|
+
console.log('');
|
|
1307
|
+
// Audit trail
|
|
1308
|
+
const auditEntries = await gate.getAuditTrail(undefined, 10);
|
|
1309
|
+
if (auditEntries.length > 0) {
|
|
1310
|
+
console.log(sectionHeader('Recent Audit Trail'));
|
|
1311
|
+
console.log('');
|
|
1312
|
+
for (const entry of auditEntries) {
|
|
1313
|
+
const icon = entry.allowed ? chalk.green('PASS') : chalk.red('BLOCK');
|
|
1314
|
+
const time = typeof entry.executedAt === 'string' ? entry.executedAt.slice(0, 19) : '';
|
|
1315
|
+
const op = typeof entry.operation === 'string' ? entry.operation : '';
|
|
1316
|
+
const reason = typeof entry.reason === 'string' ? entry.reason.slice(0, 40) : '';
|
|
1317
|
+
console.log(` ${chalk.dim(time)} ${icon} ${op.padEnd(20)} ${chalk.dim(reason)}`);
|
|
1318
|
+
}
|
|
1319
|
+
}
|
|
1320
|
+
else {
|
|
1321
|
+
console.log(chalk.dim(' No audit trail entries yet'));
|
|
1322
|
+
}
|
|
1323
|
+
console.log('');
|
|
1324
|
+
// Per-task filtering
|
|
1325
|
+
if (options.taskId) {
|
|
1326
|
+
console.log(sectionHeader(`Policy Checks for Task: ${options.taskId}`));
|
|
1327
|
+
console.log('');
|
|
1328
|
+
const taskAudit = await gate.getAuditTrail(undefined, 50);
|
|
1329
|
+
const taskEntries = taskAudit.filter((e) => e.taskId === options.taskId);
|
|
1330
|
+
if (taskEntries.length > 0) {
|
|
1331
|
+
for (const entry of taskEntries) {
|
|
1332
|
+
const icon = entry.allowed ? chalk.green('PASS') : chalk.red('BLOCK');
|
|
1333
|
+
console.log(` ${icon} ${entry.operation} - ${entry.reason || 'OK'}`);
|
|
1334
|
+
}
|
|
1335
|
+
}
|
|
1336
|
+
else {
|
|
1337
|
+
console.log(chalk.dim(' No policy checks recorded for this task'));
|
|
1338
|
+
}
|
|
1339
|
+
console.log('');
|
|
1340
|
+
}
|
|
1341
|
+
// Help
|
|
1342
|
+
console.log(chalk.dim(' Toggle: uap policy toggle <id> --off'));
|
|
1343
|
+
console.log(chalk.dim(' Stage: uap policy stage <id> -s post-exec'));
|
|
1344
|
+
console.log(chalk.dim(' Level: uap policy level <id> -l OPTIONAL'));
|
|
1345
|
+
console.log('');
|
|
1346
|
+
}
|
|
1347
|
+
catch (error) {
|
|
1348
|
+
spinner.fail('Failed to load policies dashboard');
|
|
1349
|
+
console.error(chalk.red(error instanceof Error ? error.message : String(error)));
|
|
1350
|
+
}
|
|
1351
|
+
}
|
|
1352
|
+
async function showModelsDashboard(options) {
|
|
1353
|
+
const spinner = ora('Loading models dashboard...').start();
|
|
1354
|
+
try {
|
|
1355
|
+
// Load UAP config
|
|
1356
|
+
const configPath = join(process.cwd(), '.uap.json');
|
|
1357
|
+
let mmConfig = {
|
|
1358
|
+
enabled: true,
|
|
1359
|
+
models: ['opus-4.6', 'qwen35'],
|
|
1360
|
+
roles: { planner: 'opus-4.6', executor: 'qwen35', fallback: 'qwen35' },
|
|
1361
|
+
routingStrategy: 'balanced',
|
|
1362
|
+
};
|
|
1363
|
+
if (existsSync(configPath)) {
|
|
1364
|
+
try {
|
|
1365
|
+
const raw = JSON.parse(readFileSync(configPath, 'utf-8'));
|
|
1366
|
+
if (raw.multiModel)
|
|
1367
|
+
mmConfig = raw.multiModel;
|
|
1368
|
+
}
|
|
1369
|
+
catch {
|
|
1370
|
+
/* use defaults */
|
|
1371
|
+
}
|
|
1372
|
+
}
|
|
1373
|
+
const router = new ModelRouter(mmConfig);
|
|
1374
|
+
const analytics = getModelAnalytics();
|
|
1375
|
+
spinner.stop();
|
|
1376
|
+
console.log('');
|
|
1377
|
+
console.log(chalk.bold.cyan(' UAP Model Dashboard'));
|
|
1378
|
+
console.log(divider(62));
|
|
1379
|
+
console.log('');
|
|
1380
|
+
// Active configuration
|
|
1381
|
+
console.log(sectionHeader('Active Configuration'));
|
|
1382
|
+
console.log('');
|
|
1383
|
+
const roles = mmConfig.roles || { planner: 'opus-4.6', executor: 'qwen35', fallback: 'qwen35' };
|
|
1384
|
+
const plannerPreset = ModelPresets[roles.planner || 'opus-4.6'];
|
|
1385
|
+
const executorPreset = ModelPresets[roles.executor || 'qwen35'];
|
|
1386
|
+
const fallbackPreset = ModelPresets[roles.fallback || 'qwen35'];
|
|
1387
|
+
const roleRows = [
|
|
1388
|
+
[
|
|
1389
|
+
'Planner',
|
|
1390
|
+
roles.planner || 'opus-4.6',
|
|
1391
|
+
plannerPreset?.name || '?',
|
|
1392
|
+
`$${(plannerPreset?.costPer1MInput || 0).toFixed(2)}/$${(plannerPreset?.costPer1MOutput || 0).toFixed(2)}`,
|
|
1393
|
+
],
|
|
1394
|
+
[
|
|
1395
|
+
'Executor',
|
|
1396
|
+
roles.executor || 'qwen35',
|
|
1397
|
+
executorPreset?.name || '?',
|
|
1398
|
+
`$${(executorPreset?.costPer1MInput || 0).toFixed(2)}/$${(executorPreset?.costPer1MOutput || 0).toFixed(2)}`,
|
|
1399
|
+
],
|
|
1400
|
+
['Reviewer', roles.reviewer || roles.planner || 'opus-4.6', plannerPreset?.name || '?', ''],
|
|
1401
|
+
['Fallback', roles.fallback || 'qwen35', fallbackPreset?.name || '?', ''],
|
|
1402
|
+
];
|
|
1403
|
+
for (const [role, id, name, cost] of roleRows) {
|
|
1404
|
+
const roleColor = role === 'Planner' ? chalk.green : role === 'Executor' ? chalk.blue : chalk.dim;
|
|
1405
|
+
console.log(` ${roleColor(role.padEnd(10))} ${chalk.cyan(id.padEnd(14))} ${name.padEnd(22)} ${chalk.dim(cost)}`);
|
|
1406
|
+
}
|
|
1407
|
+
console.log(` ${'Strategy'.padEnd(10)} ${chalk.cyan(mmConfig.routingStrategy)}`);
|
|
1408
|
+
console.log('');
|
|
1409
|
+
// Routing matrix
|
|
1410
|
+
console.log(sectionHeader('Routing Matrix'));
|
|
1411
|
+
console.log('');
|
|
1412
|
+
console.log(` ${'Complexity'.padEnd(12)} ${'Model'.padEnd(16)} ${'Est. Cost'}`);
|
|
1413
|
+
console.log(` ${'─'.repeat(12)} ${'─'.repeat(16)} ${'─'.repeat(10)}`);
|
|
1414
|
+
for (const complexity of ['low', 'medium', 'high', 'critical']) {
|
|
1415
|
+
const result = router.classifyTask(`A ${complexity} complexity task`);
|
|
1416
|
+
const model = result.suggestedModel;
|
|
1417
|
+
const preset = ModelPresets[model];
|
|
1418
|
+
const cost = preset ? router.estimateCost(preset, 10000, 5000) : 0;
|
|
1419
|
+
const complexityColor = complexity === 'critical'
|
|
1420
|
+
? chalk.red
|
|
1421
|
+
: complexity === 'high'
|
|
1422
|
+
? chalk.yellow
|
|
1423
|
+
: complexity === 'medium'
|
|
1424
|
+
? chalk.blue
|
|
1425
|
+
: chalk.green;
|
|
1426
|
+
console.log(` ${complexityColor(complexity.padEnd(12))} ${chalk.cyan(model.padEnd(16))} $${cost.toFixed(4)}`);
|
|
1427
|
+
}
|
|
1428
|
+
console.log('');
|
|
1429
|
+
// Session usage from analytics
|
|
1430
|
+
const sessionUsage = analytics.getSessionUsage();
|
|
1431
|
+
if (sessionUsage.length > 0) {
|
|
1432
|
+
console.log(sectionHeader('Session Usage'));
|
|
1433
|
+
console.log('');
|
|
1434
|
+
console.log(` ${'Model'.padEnd(14)} ${'Tasks'.padEnd(7)} ${'Tokens In'.padEnd(12)} ${'Tokens Out'.padEnd(12)} ${'Cost'.padEnd(10)} ${'Success'}`);
|
|
1435
|
+
console.log(` ${'─'.repeat(14)} ${'─'.repeat(7)} ${'─'.repeat(12)} ${'─'.repeat(12)} ${'─'.repeat(10)} ${'─'.repeat(7)}`);
|
|
1436
|
+
for (const usage of sessionUsage) {
|
|
1437
|
+
const rate = (usage.successRate * 100).toFixed(1) + '%';
|
|
1438
|
+
console.log(` ${chalk.cyan(usage.modelId.padEnd(14))} ${String(usage.taskCount).padEnd(7)} ${String(usage.totalTokensIn).padEnd(12)} ${String(usage.totalTokensOut).padEnd(12)} $${usage.totalCost.toFixed(4).padEnd(9)} ${rate}`);
|
|
1439
|
+
}
|
|
1440
|
+
console.log('');
|
|
1441
|
+
const totalCost = analytics.getTotalCost();
|
|
1442
|
+
console.log(` ${chalk.bold('Total session cost:')} $${totalCost.toFixed(4)}`);
|
|
1443
|
+
console.log('');
|
|
1444
|
+
}
|
|
1445
|
+
else {
|
|
1446
|
+
console.log(chalk.dim(' No model usage recorded this session'));
|
|
1447
|
+
console.log('');
|
|
1448
|
+
}
|
|
1449
|
+
// Execution profile for executor
|
|
1450
|
+
const executorModel = roles.executor || 'qwen35';
|
|
1451
|
+
const executorApiModel = ModelPresets[executorModel]?.apiModel || executorModel;
|
|
1452
|
+
const profile = detectExecutionProfile(executorApiModel);
|
|
1453
|
+
console.log(sectionHeader(`Execution Profile: ${profile.name}`));
|
|
1454
|
+
console.log('');
|
|
1455
|
+
const profileConfig = profile.config;
|
|
1456
|
+
const flagPairs = [
|
|
1457
|
+
['domainHints', profileConfig.domainHints],
|
|
1458
|
+
['webSearch', profileConfig.webSearch],
|
|
1459
|
+
['reflectionCheckpoints', profileConfig.reflectionCheckpoints],
|
|
1460
|
+
['temperature', profileConfig.temperature],
|
|
1461
|
+
['loopEscapeThreshold', profileConfig.loopEscapeThreshold],
|
|
1462
|
+
['toolChoiceForce', profileConfig.toolChoiceForce],
|
|
1463
|
+
['softBudget', profileConfig.softBudget],
|
|
1464
|
+
['hardBudget', profileConfig.hardBudget],
|
|
1465
|
+
];
|
|
1466
|
+
const flagLines = [];
|
|
1467
|
+
for (const [key, val] of flagPairs) {
|
|
1468
|
+
const display = typeof val === 'boolean'
|
|
1469
|
+
? val
|
|
1470
|
+
? chalk.green('ON')
|
|
1471
|
+
: chalk.red('OFF')
|
|
1472
|
+
: chalk.cyan(String(val));
|
|
1473
|
+
flagLines.push(`${key}: ${display}`);
|
|
1474
|
+
}
|
|
1475
|
+
// Print 3 per line
|
|
1476
|
+
for (let i = 0; i < flagLines.length; i += 3) {
|
|
1477
|
+
const chunk = flagLines.slice(i, i + 3);
|
|
1478
|
+
console.log(` ${chunk.map((f) => f.padEnd(28)).join('')}`);
|
|
1479
|
+
}
|
|
1480
|
+
console.log('');
|
|
1481
|
+
// Per-task view
|
|
1482
|
+
if (options.taskId) {
|
|
1483
|
+
console.log(sectionHeader(`Model Usage for Task: ${options.taskId}`));
|
|
1484
|
+
console.log('');
|
|
1485
|
+
const taskOutcomes = analytics.getTaskOutcomes(options.taskId);
|
|
1486
|
+
if (taskOutcomes.length > 0) {
|
|
1487
|
+
for (const outcome of taskOutcomes) {
|
|
1488
|
+
const icon = outcome.success ? chalk.green('OK') : chalk.red('FAIL');
|
|
1489
|
+
console.log(` ${icon} ${chalk.cyan(outcome.modelId)} ${outcome.taskType} ${outcome.complexity} ${outcome.durationMs}ms $${outcome.cost.toFixed(4)}`);
|
|
1490
|
+
}
|
|
1491
|
+
}
|
|
1492
|
+
else {
|
|
1493
|
+
console.log(chalk.dim(' No outcomes recorded for this task'));
|
|
1494
|
+
}
|
|
1495
|
+
console.log('');
|
|
1496
|
+
}
|
|
1497
|
+
// Optimal routing suggestions
|
|
1498
|
+
const optimal = analytics.getOptimalRouting();
|
|
1499
|
+
if (Object.keys(optimal).length > 0) {
|
|
1500
|
+
console.log(sectionHeader('Optimal Routing (from history)'));
|
|
1501
|
+
console.log('');
|
|
1502
|
+
for (const [taskType, modelId] of Object.entries(optimal)) {
|
|
1503
|
+
console.log(` ${taskType.padEnd(16)} -> ${chalk.cyan(modelId)}`);
|
|
1504
|
+
}
|
|
1505
|
+
console.log('');
|
|
1506
|
+
}
|
|
1507
|
+
}
|
|
1508
|
+
catch (error) {
|
|
1509
|
+
spinner.fail('Failed to load models dashboard');
|
|
1510
|
+
console.error(chalk.red(error instanceof Error ? error.message : String(error)));
|
|
1511
|
+
}
|
|
1512
|
+
}
|
|
1124
1513
|
// ==================== Compact Session Summary (for post-task / pre-compact) ====================
|
|
1125
1514
|
/**
|
|
1126
1515
|
* Renders a compact session summary panel.
|