@iris-eval/mcp-server 0.1.6 → 0.1.7
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/README.md +3 -2
- package/dist/config/defaults.js +1 -1
- package/dist/dashboard/assets/index-BwFrX6Zx.js +70 -0
- package/dist/dashboard/assets/index-C9BwWthL.css +1 -0
- package/dist/dashboard/index.html +2 -2
- package/dist/dashboard/routes/eval-stats.d.ts +3 -0
- package/dist/dashboard/routes/eval-stats.js +76 -0
- package/dist/dashboard/routes/evaluations.d.ts +3 -0
- package/dist/dashboard/routes/evaluations.js +15 -0
- package/dist/dashboard/routes/filters.d.ts +3 -0
- package/dist/dashboard/routes/filters.js +9 -0
- package/dist/dashboard/routes/health.d.ts +3 -0
- package/dist/dashboard/routes/health.js +25 -0
- package/dist/dashboard/routes/index.d.ts +6 -0
- package/dist/dashboard/routes/index.js +6 -0
- package/dist/dashboard/routes/summary.d.ts +3 -0
- package/dist/dashboard/routes/summary.js +8 -0
- package/dist/dashboard/routes/traces.d.ts +3 -0
- package/dist/dashboard/routes/traces.js +29 -0
- package/dist/dashboard/server.d.ts +10 -0
- package/dist/dashboard/server.js +65 -0
- package/dist/dashboard/validation.d.ts +75 -0
- package/dist/dashboard/validation.js +29 -0
- package/package.json +1 -1
- package/server.json +2 -2
- package/dist/dashboard/assets/index-BgJQ3xJ9.js +0 -127
- package/dist/dashboard/assets/index-zuWgVxsu.css +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
:root{--bg-primary:#0a0a0b;--bg-secondary:#141416;--bg-tertiary:#1c1c1f;--bg-hover:#252528;--text-primary:#fafafa;--text-secondary:#a1a1aa;--text-muted:#71717a;--accent-primary:#0d9488;--accent-primary-hover:#14b8a6;--accent-success:#22c55e;--accent-error:#ef4444;--accent-warning:#f59e0b;--accent-tool:#3b82f6;--accent-llm:#a855f7;--border-color:#27272a;--border-radius:8px;--border-radius-sm:4px;--border-radius-lg:12px;--font-sans:-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;--font-mono:"JetBrains Mono", "Fira Code", monospace;--font-size-xs:.75rem;--font-size-sm:.875rem;--font-size-base:1rem;--font-size-lg:1.125rem;--font-size-xl:1.25rem;--font-size-2xl:1.5rem;--font-size-3xl:2rem;--space-1:.25rem;--space-2:.5rem;--space-3:.75rem;--space-4:1rem;--space-5:1.25rem;--space-6:1.5rem;--space-8:2rem;--space-10:2.5rem;--space-12:3rem;--shadow-sm:0 1px 2px #0000004d;--shadow-md:0 4px 6px #0006;--shadow-lg:0 10px 15px #00000080;--transition-fast:.15s ease;--transition-base:.2s ease}*,:before,:after{box-sizing:border-box;margin:0;padding:0}html,body,#root{width:100%;height:100%}body{font-family:var(--font-sans);font-size:var(--font-size-base);color:var(--text-primary);background-color:var(--bg-primary);-webkit-font-smoothing:antialiased;line-height:1.5}a{color:var(--accent-primary);text-decoration:none}a:hover{color:var(--accent-primary-hover)}button{cursor:pointer;font-family:inherit}input,select{font-family:inherit;font-size:inherit}code,pre{font-family:var(--font-mono)}::-webkit-scrollbar{width:8px;height:8px}::-webkit-scrollbar-track{background:var(--bg-primary)}::-webkit-scrollbar-thumb{background:var(--border-color);border-radius:4px}::-webkit-scrollbar-thumb:hover{background:var(--text-muted)}
|
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
6
|
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
|
7
7
|
<title>Iris — Agent Eval & Observability</title>
|
|
8
|
-
<script type="module" crossorigin src="/assets/index-
|
|
9
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
8
|
+
<script type="module" crossorigin src="/assets/index-BwFrX6Zx.js"></script>
|
|
9
|
+
<link rel="stylesheet" crossorigin href="/assets/index-C9BwWthL.css">
|
|
10
10
|
</head>
|
|
11
11
|
<body>
|
|
12
12
|
<div id="root"></div>
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { evalStatsPeriodSchema, evalStatsFailuresSchema } from '../validation.js';
|
|
2
|
+
export function registerEvalStatsRoutes(router, storage) {
|
|
3
|
+
/**
|
|
4
|
+
* GET /eval-stats
|
|
5
|
+
* Aggregate eval statistics for dashboard hero cards.
|
|
6
|
+
*/
|
|
7
|
+
router.get('/eval-stats', async (req, res) => {
|
|
8
|
+
try {
|
|
9
|
+
const { period } = evalStatsPeriodSchema.parse(req.query);
|
|
10
|
+
const stats = await storage.getEvalStats(period);
|
|
11
|
+
res.json(stats);
|
|
12
|
+
}
|
|
13
|
+
catch (err) {
|
|
14
|
+
if (err instanceof Error && err.name === 'ZodError') {
|
|
15
|
+
res.status(400).json({ error: 'Invalid query parameters', details: err.issues });
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
throw err;
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
/**
|
|
22
|
+
* GET /eval-stats/trend
|
|
23
|
+
* Eval scores bucketed over time for the trend chart.
|
|
24
|
+
*/
|
|
25
|
+
router.get('/eval-stats/trend', async (req, res) => {
|
|
26
|
+
try {
|
|
27
|
+
const { period } = evalStatsPeriodSchema.parse(req.query);
|
|
28
|
+
const trend = await storage.getEvalStatsTrend(period);
|
|
29
|
+
res.json(trend);
|
|
30
|
+
}
|
|
31
|
+
catch (err) {
|
|
32
|
+
if (err instanceof Error && err.name === 'ZodError') {
|
|
33
|
+
res.status(400).json({ error: 'Invalid query parameters', details: err.issues });
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
throw err;
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
/**
|
|
40
|
+
* GET /eval-stats/rules
|
|
41
|
+
* Per-rule pass rates for the rule breakdown chart.
|
|
42
|
+
* Sorted by passRate ASC (worst rules first).
|
|
43
|
+
*/
|
|
44
|
+
router.get('/eval-stats/rules', async (req, res) => {
|
|
45
|
+
try {
|
|
46
|
+
const { period } = evalStatsPeriodSchema.parse(req.query);
|
|
47
|
+
const rules = await storage.getEvalStatsRules(period);
|
|
48
|
+
res.json(rules);
|
|
49
|
+
}
|
|
50
|
+
catch (err) {
|
|
51
|
+
if (err instanceof Error && err.name === 'ZodError') {
|
|
52
|
+
res.status(400).json({ error: 'Invalid query parameters', details: err.issues });
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
throw err;
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
/**
|
|
59
|
+
* GET /eval-stats/failures
|
|
60
|
+
* Recent failing evaluations for the failures table.
|
|
61
|
+
*/
|
|
62
|
+
router.get('/eval-stats/failures', async (req, res) => {
|
|
63
|
+
try {
|
|
64
|
+
const query = evalStatsFailuresSchema.parse(req.query);
|
|
65
|
+
const failures = await storage.getEvalStatsFailures(query.period, query.limit);
|
|
66
|
+
res.json(failures);
|
|
67
|
+
}
|
|
68
|
+
catch (err) {
|
|
69
|
+
if (err instanceof Error && err.name === 'ZodError') {
|
|
70
|
+
res.status(400).json({ error: 'Invalid query parameters', details: err.issues });
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
throw err;
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { evalQuerySchema } from '../validation.js';
|
|
2
|
+
export function registerEvaluationRoutes(router, storage) {
|
|
3
|
+
router.get('/evaluations', async (req, res) => {
|
|
4
|
+
const query = evalQuerySchema.parse(req.query);
|
|
5
|
+
const result = await storage.queryEvalResults({
|
|
6
|
+
eval_type: query.eval_type,
|
|
7
|
+
passed: query.passed,
|
|
8
|
+
since: query.since,
|
|
9
|
+
until: query.until,
|
|
10
|
+
limit: query.limit,
|
|
11
|
+
offset: query.offset,
|
|
12
|
+
});
|
|
13
|
+
res.json(result);
|
|
14
|
+
});
|
|
15
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export function registerFilterRoutes(router, storage) {
|
|
2
|
+
router.get('/filters', async (_req, res) => {
|
|
3
|
+
const [agentNames, frameworks] = await Promise.all([
|
|
4
|
+
storage.getDistinctValues('agent_name'),
|
|
5
|
+
storage.getDistinctValues('framework'),
|
|
6
|
+
]);
|
|
7
|
+
res.json({ agent_names: agentNames, frameworks });
|
|
8
|
+
});
|
|
9
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
const startTime = Date.now();
|
|
2
|
+
export function registerHealthRoutes(router, storage, version) {
|
|
3
|
+
const serverVersion = version ?? 'unknown';
|
|
4
|
+
router.get('/health', async (_req, res) => {
|
|
5
|
+
const uptime_seconds = Math.floor((Date.now() - startTime) / 1000);
|
|
6
|
+
if (storage) {
|
|
7
|
+
try {
|
|
8
|
+
const summary = await storage.getDashboardSummary(1);
|
|
9
|
+
res.json({
|
|
10
|
+
status: 'ok',
|
|
11
|
+
version: serverVersion,
|
|
12
|
+
uptime_seconds,
|
|
13
|
+
trace_count: summary.total_traces,
|
|
14
|
+
storage: 'connected',
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
res.status(503).json({ status: 'degraded', version: serverVersion, uptime_seconds, storage: 'disconnected' });
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
res.json({ status: 'ok', version: serverVersion, uptime_seconds });
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { registerTraceRoutes } from './traces.js';
|
|
2
|
+
export { registerSummaryRoutes } from './summary.js';
|
|
3
|
+
export { registerEvaluationRoutes } from './evaluations.js';
|
|
4
|
+
export { registerEvalStatsRoutes } from './eval-stats.js';
|
|
5
|
+
export { registerFilterRoutes } from './filters.js';
|
|
6
|
+
export { registerHealthRoutes } from './health.js';
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { registerTraceRoutes } from './traces.js';
|
|
2
|
+
export { registerSummaryRoutes } from './summary.js';
|
|
3
|
+
export { registerEvaluationRoutes } from './evaluations.js';
|
|
4
|
+
export { registerEvalStatsRoutes } from './eval-stats.js';
|
|
5
|
+
export { registerFilterRoutes } from './filters.js';
|
|
6
|
+
export { registerHealthRoutes } from './health.js';
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { summaryQuerySchema } from '../validation.js';
|
|
2
|
+
export function registerSummaryRoutes(router, storage) {
|
|
3
|
+
router.get('/summary', async (req, res) => {
|
|
4
|
+
const query = summaryQuerySchema.parse(req.query);
|
|
5
|
+
const summary = await storage.getDashboardSummary(query.hours);
|
|
6
|
+
res.json(summary);
|
|
7
|
+
});
|
|
8
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { traceQuerySchema } from '../validation.js';
|
|
2
|
+
export function registerTraceRoutes(router, storage) {
|
|
3
|
+
router.get('/traces', async (req, res) => {
|
|
4
|
+
const query = traceQuerySchema.parse(req.query);
|
|
5
|
+
const result = await storage.queryTraces({
|
|
6
|
+
filter: {
|
|
7
|
+
agent_name: query.agent_name,
|
|
8
|
+
framework: query.framework,
|
|
9
|
+
since: query.since,
|
|
10
|
+
until: query.until,
|
|
11
|
+
},
|
|
12
|
+
limit: query.limit,
|
|
13
|
+
offset: query.offset,
|
|
14
|
+
sort_by: query.sort_by,
|
|
15
|
+
sort_order: query.sort_order,
|
|
16
|
+
});
|
|
17
|
+
res.json(result);
|
|
18
|
+
});
|
|
19
|
+
router.get('/traces/:id', async (req, res) => {
|
|
20
|
+
const trace = await storage.getTrace(req.params.id);
|
|
21
|
+
if (!trace) {
|
|
22
|
+
res.status(404).json({ error: 'Trace not found' });
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
const spans = await storage.getSpansByTraceId(req.params.id);
|
|
26
|
+
const evals = await storage.getEvalsByTraceId(req.params.id);
|
|
27
|
+
res.json({ trace, spans, evals });
|
|
28
|
+
});
|
|
29
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import express from 'express';
|
|
2
|
+
import type { Server } from 'node:http';
|
|
3
|
+
import type { IStorageAdapter } from '../types/query.js';
|
|
4
|
+
import type { IrisConfig } from '../types/config.js';
|
|
5
|
+
import type { Logger } from '../utils/logger.js';
|
|
6
|
+
export interface DashboardServer {
|
|
7
|
+
app: express.Application;
|
|
8
|
+
start(): Server;
|
|
9
|
+
}
|
|
10
|
+
export declare function createDashboardServer(storage: IStorageAdapter, config: IrisConfig, logger: Logger): DashboardServer;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import express from 'express';
|
|
2
|
+
import helmet from 'helmet';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
import { dirname, join } from 'node:path';
|
|
5
|
+
import { existsSync } from 'node:fs';
|
|
6
|
+
import { createAuthMiddleware } from '../middleware/auth.js';
|
|
7
|
+
import { createCorsMiddleware } from '../middleware/cors.js';
|
|
8
|
+
import { createErrorHandler } from '../middleware/error-handler.js';
|
|
9
|
+
import { createApiRateLimiter } from '../middleware/rate-limit.js';
|
|
10
|
+
import { registerTraceRoutes } from './routes/traces.js';
|
|
11
|
+
import { registerSummaryRoutes } from './routes/summary.js';
|
|
12
|
+
import { registerEvaluationRoutes } from './routes/evaluations.js';
|
|
13
|
+
import { registerFilterRoutes } from './routes/filters.js';
|
|
14
|
+
import { registerEvalStatsRoutes } from './routes/eval-stats.js';
|
|
15
|
+
import { registerHealthRoutes } from './routes/health.js';
|
|
16
|
+
export function createDashboardServer(storage, config, logger) {
|
|
17
|
+
const app = express();
|
|
18
|
+
// Security headers
|
|
19
|
+
app.use(helmet({
|
|
20
|
+
contentSecurityPolicy: {
|
|
21
|
+
directives: {
|
|
22
|
+
defaultSrc: ["'self'"],
|
|
23
|
+
scriptSrc: ["'self'"],
|
|
24
|
+
styleSrc: ["'self'", "'unsafe-inline'"],
|
|
25
|
+
connectSrc: ["'self'"],
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
}));
|
|
29
|
+
// Body parser with size limit
|
|
30
|
+
app.use(express.json({ limit: config.security.requestSizeLimit }));
|
|
31
|
+
// CORS
|
|
32
|
+
app.use(createCorsMiddleware(config.security.allowedOrigins));
|
|
33
|
+
// Authentication
|
|
34
|
+
app.use(createAuthMiddleware(config));
|
|
35
|
+
// API routes with rate limiting
|
|
36
|
+
const router = express.Router();
|
|
37
|
+
router.use(createApiRateLimiter(config));
|
|
38
|
+
registerTraceRoutes(router, storage);
|
|
39
|
+
registerSummaryRoutes(router, storage);
|
|
40
|
+
registerEvaluationRoutes(router, storage);
|
|
41
|
+
registerEvalStatsRoutes(router, storage);
|
|
42
|
+
registerFilterRoutes(router, storage);
|
|
43
|
+
registerHealthRoutes(router, storage, config.server.version);
|
|
44
|
+
app.use('/api/v1', router);
|
|
45
|
+
// Serve static dashboard files if built (rate limited)
|
|
46
|
+
const currentDir = dirname(fileURLToPath(import.meta.url));
|
|
47
|
+
const staticDir = join(currentDir, '..', '..', 'dist', 'dashboard');
|
|
48
|
+
if (existsSync(staticDir)) {
|
|
49
|
+
app.use(createApiRateLimiter(config));
|
|
50
|
+
app.use(express.static(staticDir));
|
|
51
|
+
app.get('/{*path}', (_req, res) => {
|
|
52
|
+
res.sendFile(join(staticDir, 'index.html'));
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
// Error handler (must be last)
|
|
56
|
+
app.use(createErrorHandler(logger));
|
|
57
|
+
return {
|
|
58
|
+
app,
|
|
59
|
+
start() {
|
|
60
|
+
return app.listen(config.dashboard.port, () => {
|
|
61
|
+
logger.info(`Dashboard available at http://localhost:${config.dashboard.port}`);
|
|
62
|
+
});
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const traceQuerySchema: z.ZodObject<{
|
|
3
|
+
agent_name: z.ZodOptional<z.ZodString>;
|
|
4
|
+
framework: z.ZodOptional<z.ZodString>;
|
|
5
|
+
since: z.ZodOptional<z.ZodString>;
|
|
6
|
+
until: z.ZodOptional<z.ZodString>;
|
|
7
|
+
limit: z.ZodDefault<z.ZodNumber>;
|
|
8
|
+
offset: z.ZodDefault<z.ZodNumber>;
|
|
9
|
+
sort_by: z.ZodDefault<z.ZodEnum<["timestamp", "latency_ms", "cost_usd"]>>;
|
|
10
|
+
sort_order: z.ZodDefault<z.ZodEnum<["asc", "desc"]>>;
|
|
11
|
+
}, "strip", z.ZodTypeAny, {
|
|
12
|
+
limit: number;
|
|
13
|
+
offset: number;
|
|
14
|
+
sort_by: "timestamp" | "latency_ms" | "cost_usd";
|
|
15
|
+
sort_order: "asc" | "desc";
|
|
16
|
+
agent_name?: string | undefined;
|
|
17
|
+
framework?: string | undefined;
|
|
18
|
+
since?: string | undefined;
|
|
19
|
+
until?: string | undefined;
|
|
20
|
+
}, {
|
|
21
|
+
agent_name?: string | undefined;
|
|
22
|
+
framework?: string | undefined;
|
|
23
|
+
since?: string | undefined;
|
|
24
|
+
until?: string | undefined;
|
|
25
|
+
limit?: number | undefined;
|
|
26
|
+
offset?: number | undefined;
|
|
27
|
+
sort_by?: "timestamp" | "latency_ms" | "cost_usd" | undefined;
|
|
28
|
+
sort_order?: "asc" | "desc" | undefined;
|
|
29
|
+
}>;
|
|
30
|
+
export declare const evalQuerySchema: z.ZodObject<{
|
|
31
|
+
eval_type: z.ZodOptional<z.ZodString>;
|
|
32
|
+
passed: z.ZodOptional<z.ZodEffects<z.ZodEnum<["true", "false"]>, boolean, "true" | "false">>;
|
|
33
|
+
since: z.ZodOptional<z.ZodString>;
|
|
34
|
+
until: z.ZodOptional<z.ZodString>;
|
|
35
|
+
limit: z.ZodDefault<z.ZodNumber>;
|
|
36
|
+
offset: z.ZodDefault<z.ZodNumber>;
|
|
37
|
+
}, "strip", z.ZodTypeAny, {
|
|
38
|
+
limit: number;
|
|
39
|
+
offset: number;
|
|
40
|
+
since?: string | undefined;
|
|
41
|
+
until?: string | undefined;
|
|
42
|
+
eval_type?: string | undefined;
|
|
43
|
+
passed?: boolean | undefined;
|
|
44
|
+
}, {
|
|
45
|
+
since?: string | undefined;
|
|
46
|
+
until?: string | undefined;
|
|
47
|
+
limit?: number | undefined;
|
|
48
|
+
offset?: number | undefined;
|
|
49
|
+
eval_type?: string | undefined;
|
|
50
|
+
passed?: "true" | "false" | undefined;
|
|
51
|
+
}>;
|
|
52
|
+
export declare const summaryQuerySchema: z.ZodObject<{
|
|
53
|
+
hours: z.ZodDefault<z.ZodNumber>;
|
|
54
|
+
}, "strip", z.ZodTypeAny, {
|
|
55
|
+
hours: number;
|
|
56
|
+
}, {
|
|
57
|
+
hours?: number | undefined;
|
|
58
|
+
}>;
|
|
59
|
+
export declare const evalStatsPeriodSchema: z.ZodObject<{
|
|
60
|
+
period: z.ZodDefault<z.ZodEnum<["24h", "7d", "30d"]>>;
|
|
61
|
+
}, "strip", z.ZodTypeAny, {
|
|
62
|
+
period: "24h" | "7d" | "30d";
|
|
63
|
+
}, {
|
|
64
|
+
period?: "24h" | "7d" | "30d" | undefined;
|
|
65
|
+
}>;
|
|
66
|
+
export declare const evalStatsFailuresSchema: z.ZodObject<{
|
|
67
|
+
period: z.ZodDefault<z.ZodEnum<["24h", "7d", "30d"]>>;
|
|
68
|
+
limit: z.ZodDefault<z.ZodNumber>;
|
|
69
|
+
}, "strip", z.ZodTypeAny, {
|
|
70
|
+
limit: number;
|
|
71
|
+
period: "24h" | "7d" | "30d";
|
|
72
|
+
}, {
|
|
73
|
+
limit?: number | undefined;
|
|
74
|
+
period?: "24h" | "7d" | "30d" | undefined;
|
|
75
|
+
}>;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export const traceQuerySchema = z.object({
|
|
3
|
+
agent_name: z.string().optional(),
|
|
4
|
+
framework: z.string().optional(),
|
|
5
|
+
since: z.string().optional(),
|
|
6
|
+
until: z.string().optional(),
|
|
7
|
+
limit: z.coerce.number().int().min(1).max(1000).default(50),
|
|
8
|
+
offset: z.coerce.number().int().min(0).default(0),
|
|
9
|
+
sort_by: z.enum(['timestamp', 'latency_ms', 'cost_usd']).default('timestamp'),
|
|
10
|
+
sort_order: z.enum(['asc', 'desc']).default('desc'),
|
|
11
|
+
});
|
|
12
|
+
export const evalQuerySchema = z.object({
|
|
13
|
+
eval_type: z.string().optional(),
|
|
14
|
+
passed: z.enum(['true', 'false']).transform((v) => v === 'true').optional(),
|
|
15
|
+
since: z.string().optional(),
|
|
16
|
+
until: z.string().optional(),
|
|
17
|
+
limit: z.coerce.number().int().min(1).max(1000).default(50),
|
|
18
|
+
offset: z.coerce.number().int().min(0).default(0),
|
|
19
|
+
});
|
|
20
|
+
export const summaryQuerySchema = z.object({
|
|
21
|
+
hours: z.coerce.number().int().min(1).max(8760).default(24),
|
|
22
|
+
});
|
|
23
|
+
export const evalStatsPeriodSchema = z.object({
|
|
24
|
+
period: z.enum(['24h', '7d', '30d']).default('24h'),
|
|
25
|
+
});
|
|
26
|
+
export const evalStatsFailuresSchema = z.object({
|
|
27
|
+
period: z.enum(['24h', '7d', '30d']).default('24h'),
|
|
28
|
+
limit: z.coerce.number().int().min(1).max(100).default(10),
|
|
29
|
+
});
|
package/package.json
CHANGED
package/server.json
CHANGED
|
@@ -6,12 +6,12 @@
|
|
|
6
6
|
"url": "https://github.com/iris-eval/mcp-server",
|
|
7
7
|
"source": "github"
|
|
8
8
|
},
|
|
9
|
-
"version": "0.1.
|
|
9
|
+
"version": "0.1.7",
|
|
10
10
|
"packages": [
|
|
11
11
|
{
|
|
12
12
|
"registryType": "npm",
|
|
13
13
|
"identifier": "@iris-eval/mcp-server",
|
|
14
|
-
"version": "0.1.
|
|
14
|
+
"version": "0.1.7",
|
|
15
15
|
"transport": {
|
|
16
16
|
"type": "stdio"
|
|
17
17
|
},
|