rippletide 1.0.7 → 1.0.9
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/bin/rippletide +32 -2
- package/dist/App.d.ts +10 -0
- package/dist/App.js +305 -32
- package/dist/api/client.d.ts +26 -57
- package/dist/api/client.js +25 -512
- package/dist/api/connection.d.ts +11 -0
- package/dist/api/connection.js +116 -0
- package/dist/api/endpoint.d.ts +11 -0
- package/dist/api/endpoint.js +76 -0
- package/dist/api/evaluation.d.ts +27 -0
- package/dist/api/evaluation.js +299 -0
- package/dist/api/knowledge.d.ts +31 -0
- package/dist/api/knowledge.js +138 -0
- package/dist/api/llm.d.ts +2 -0
- package/dist/api/llm.js +98 -0
- package/dist/api/response.d.ts +2 -0
- package/dist/api/response.js +66 -0
- package/dist/errors/handler.d.ts +11 -0
- package/dist/errors/handler.js +155 -0
- package/dist/errors/index.d.ts +3 -0
- package/dist/errors/index.js +3 -0
- package/dist/errors/transform.d.ts +7 -0
- package/dist/errors/transform.js +60 -0
- package/dist/errors/types.d.ts +44 -0
- package/dist/errors/types.js +103 -0
- package/dist/index.js +152 -6
- package/dist/utils/pinecone.js +16 -11
- package/dist/utils/postgresql.js +7 -3
- package/dist/utils/templates.d.ts +21 -0
- package/dist/utils/templates.js +71 -0
- package/package.json +3 -2
- package/src/App.tsx +397 -37
- package/src/api/client.ts +55 -621
- package/src/api/connection.ts +139 -0
- package/src/api/endpoint.ts +97 -0
- package/src/api/evaluation.ts +390 -0
- package/src/api/knowledge.ts +179 -0
- package/src/api/llm.ts +124 -0
- package/src/api/response.ts +77 -0
- package/src/errors/handler.ts +191 -0
- package/src/errors/index.ts +4 -0
- package/src/errors/transform.ts +107 -0
- package/src/errors/types.ts +180 -0
- package/src/index.tsx +164 -7
- package/src/utils/pinecone.ts +16 -11
- package/src/utils/postgresql.ts +7 -3
- package/src/utils/templates.ts +104 -0
- package/templates/banking_analyst/config.json +12 -0
- package/templates/banking_analyst/qanda.json +62 -0
- package/templates/blog_to_linkedin/config.json +12 -0
- package/templates/blog_to_linkedin/qanda.json +66 -0
- package/templates/customer_service/config.json +12 -0
- package/templates/customer_service/qanda.json +62 -0
- package/templates/local_dev/config.json +7 -0
- package/templates/luxe_concierge/config.json +12 -0
- package/templates/luxe_concierge/qanda.json +54 -0
- package/templates/openai_compatible/config.json +13 -0
- package/templates/project_manager/config.json +12 -0
- package/templates/project_manager/qanda.json +62 -0
- package/dist/components/InputPrompt.d.ts +0 -8
- package/dist/components/InputPrompt.js +0 -12
- package/dist/demo.d.ts +0 -2
- package/dist/demo.js +0 -97
- package/dist/scripts/test-postgresql.d.ts +0 -2
- package/dist/scripts/test-postgresql.js +0 -53
- package/dist/utils/postgresql-qa-generator.d.ts +0 -7
- package/dist/utils/postgresql-qa-generator.js +0 -265
package/bin/rippletide
CHANGED
|
@@ -3,6 +3,15 @@
|
|
|
3
3
|
const args = process.argv.slice(2);
|
|
4
4
|
const cmd = args[0];
|
|
5
5
|
|
|
6
|
+
async function loadErrorHandler() {
|
|
7
|
+
try {
|
|
8
|
+
const module = await import('../dist/errors/handler.js');
|
|
9
|
+
return module.ErrorHandler;
|
|
10
|
+
} catch {
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
6
15
|
async function main() {
|
|
7
16
|
if (!cmd || cmd === 'eval') {
|
|
8
17
|
await import('../dist/index.js');
|
|
@@ -19,11 +28,13 @@ Usage:
|
|
|
19
28
|
Options:
|
|
20
29
|
-b, --backend-url <url> Backend API URL (default: https://rippletide-backend.azurewebsites.net)
|
|
21
30
|
-d, --dashboard-url <url> Dashboard URL (default: https://eval.rippletide.com)
|
|
31
|
+
--debug Show detailed error information and stack traces
|
|
22
32
|
-h, --help Show this help message
|
|
23
33
|
|
|
24
34
|
Examples:
|
|
25
35
|
rippletide eval
|
|
26
36
|
rippletide eval -b http://localhost:3001 -d http://localhost:5173
|
|
37
|
+
rippletide eval --debug
|
|
27
38
|
`);
|
|
28
39
|
return;
|
|
29
40
|
}
|
|
@@ -33,7 +44,26 @@ Examples:
|
|
|
33
44
|
process.exit(1);
|
|
34
45
|
}
|
|
35
46
|
|
|
36
|
-
main().catch((err) => {
|
|
37
|
-
|
|
47
|
+
main().catch(async (err) => {
|
|
48
|
+
const ErrorHandler = await loadErrorHandler();
|
|
49
|
+
|
|
50
|
+
if (ErrorHandler) {
|
|
51
|
+
ErrorHandler.handle(err);
|
|
52
|
+
} else {
|
|
53
|
+
const isDebug = args.includes('--debug');
|
|
54
|
+
console.error('\nError: An error occurred while running the CLI');
|
|
55
|
+
|
|
56
|
+
if (err?.message) {
|
|
57
|
+
console.error(` ${err.message}`);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (isDebug && err?.stack) {
|
|
61
|
+
console.error('\n[DEBUG] Stack trace:');
|
|
62
|
+
console.error(err.stack);
|
|
63
|
+
} else if (!isDebug) {
|
|
64
|
+
console.error('\nRun with --debug flag for more details');
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
38
68
|
process.exit(1);
|
|
39
69
|
});
|
package/dist/App.d.ts
CHANGED
|
@@ -2,6 +2,16 @@ import React from 'react';
|
|
|
2
2
|
interface AppProps {
|
|
3
3
|
backendUrl?: string;
|
|
4
4
|
dashboardUrl?: string;
|
|
5
|
+
nonInteractive?: boolean;
|
|
6
|
+
agentEndpoint?: string;
|
|
7
|
+
knowledgeSource?: string;
|
|
8
|
+
pineconeUrl?: string;
|
|
9
|
+
pineconeApiKey?: string;
|
|
10
|
+
postgresqlConnection?: string;
|
|
11
|
+
customHeaders?: Record<string, string>;
|
|
12
|
+
customBodyTemplate?: string;
|
|
13
|
+
customResponseField?: string;
|
|
14
|
+
templatePath?: string;
|
|
5
15
|
}
|
|
6
16
|
export declare const App: React.FC<AppProps>;
|
|
7
17
|
export {};
|
package/dist/App.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { useState, useEffect } from 'react';
|
|
2
|
-
import { Box, Text } from 'ink';
|
|
2
|
+
import { Box, Text, useApp } from 'ink';
|
|
3
3
|
import { Header } from './components/Header.js';
|
|
4
4
|
import { TextInput } from './components/TextInput.js';
|
|
5
5
|
import { SelectMenu } from './components/SelectMenu.js';
|
|
@@ -9,6 +9,8 @@ import { Summary } from './components/Summary.js';
|
|
|
9
9
|
import { api } from './api/client.js';
|
|
10
10
|
import { getPineconeQAndA } from './utils/pinecone.js';
|
|
11
11
|
import { getPostgreSQLQAndA, parsePostgreSQLConnectionString } from './utils/postgresql.js';
|
|
12
|
+
import { BaseError, ValidationError } from './errors/types.js';
|
|
13
|
+
import { logger } from './utils/logger.js';
|
|
12
14
|
const knowledgeSources = [
|
|
13
15
|
{ label: 'Local Files (qanda.json)', value: 'files', description: 'Use qanda.json from current directory' },
|
|
14
16
|
{ label: 'Pinecone', value: 'pinecone', description: 'Fetch Q&A from Pinecone database' },
|
|
@@ -18,16 +20,24 @@ const knowledgeSources = [
|
|
|
18
20
|
{ label: 'GitHub Repository', value: 'github', description: 'Import from GitHub repo', disabled: true },
|
|
19
21
|
{ label: 'Skip (No Knowledge)', value: 'skip', description: 'Run tests without knowledge base', disabled: true },
|
|
20
22
|
];
|
|
21
|
-
export const App = ({ backendUrl, dashboardUrl }) => {
|
|
22
|
-
const
|
|
23
|
-
const
|
|
24
|
-
const [
|
|
23
|
+
export const App = ({ backendUrl, dashboardUrl, nonInteractive, agentEndpoint: initialAgentEndpoint, knowledgeSource: initialKnowledgeSource, pineconeUrl: initialPineconeUrl, pineconeApiKey: initialPineconeApiKey, postgresqlConnection: initialPostgresqlConnection, customHeaders, customBodyTemplate, customResponseField, templatePath }) => {
|
|
24
|
+
const { exit } = useApp();
|
|
25
|
+
const initialStep = nonInteractive && initialAgentEndpoint ? 'testing-connection' : 'agent-endpoint';
|
|
26
|
+
const [step, setStep] = useState(initialStep);
|
|
27
|
+
const [agentEndpoint, setAgentEndpoint] = useState(initialAgentEndpoint || '');
|
|
28
|
+
const [connectionTestResult, setConnectionTestResult] = useState(null);
|
|
29
|
+
const [customConfig, setCustomConfig] = useState({
|
|
30
|
+
headers: customHeaders,
|
|
31
|
+
bodyTemplate: customBodyTemplate,
|
|
32
|
+
responseField: customResponseField
|
|
33
|
+
});
|
|
34
|
+
const [knowledgeSource, setKnowledgeSource] = useState(initialKnowledgeSource || '');
|
|
25
35
|
const [knowledgeFound, setKnowledgeFound] = useState(false);
|
|
26
|
-
const [pineconeUrl, setPineconeUrl] = useState('');
|
|
27
|
-
const [pineconeApiKey, setPineconeApiKey] = useState('');
|
|
36
|
+
const [pineconeUrl, setPineconeUrl] = useState(initialPineconeUrl || '');
|
|
37
|
+
const [pineconeApiKey, setPineconeApiKey] = useState(initialPineconeApiKey || '');
|
|
28
38
|
const [pineconeQAndA, setPineconeQAndA] = useState([]);
|
|
29
39
|
const [pineconeProgress, setPineconeProgress] = useState('');
|
|
30
|
-
const [postgresqlConnectionString, setPostgresqlConnectionString] = useState('');
|
|
40
|
+
const [postgresqlConnectionString, setPostgresqlConnectionString] = useState(initialPostgresqlConnection || '');
|
|
31
41
|
const [postgresqlQAndA, setPostgresqlQAndA] = useState([]);
|
|
32
42
|
const [postgresqlProgress, setPostgresqlProgress] = useState('');
|
|
33
43
|
const [evaluationProgress, setEvaluationProgress] = useState(0);
|
|
@@ -40,6 +50,67 @@ export const App = ({ backendUrl, dashboardUrl }) => {
|
|
|
40
50
|
api.setBaseUrl(backendUrl);
|
|
41
51
|
}
|
|
42
52
|
}, [backendUrl]);
|
|
53
|
+
useEffect(() => {
|
|
54
|
+
if (step === 'complete' && nonInteractive) {
|
|
55
|
+
setTimeout(() => {
|
|
56
|
+
if (evaluationResult && !evaluationResult.error) {
|
|
57
|
+
exit();
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
process.exit(1);
|
|
61
|
+
}
|
|
62
|
+
}, 1000);
|
|
63
|
+
}
|
|
64
|
+
}, [step, nonInteractive, evaluationResult, exit]);
|
|
65
|
+
useEffect(() => {
|
|
66
|
+
if (step === 'testing-connection') {
|
|
67
|
+
(async () => {
|
|
68
|
+
try {
|
|
69
|
+
const result = customConfig.headers || customConfig.bodyTemplate
|
|
70
|
+
? await api.testAgentConnectionWithConfig(agentEndpoint, customConfig)
|
|
71
|
+
: await api.testAgentConnection(agentEndpoint);
|
|
72
|
+
setConnectionTestResult(result);
|
|
73
|
+
if (result.success) {
|
|
74
|
+
setTimeout(() => {
|
|
75
|
+
setStep('checking-knowledge');
|
|
76
|
+
}, 1500);
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
if (nonInteractive) {
|
|
80
|
+
console.error('Connection failed:', result.message);
|
|
81
|
+
setTimeout(() => {
|
|
82
|
+
setStep('checking-knowledge');
|
|
83
|
+
}, 2000);
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
setTimeout(() => {
|
|
87
|
+
setStep('connection-failed');
|
|
88
|
+
}, 2000);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
catch (error) {
|
|
93
|
+
logger.error('Error testing connection:', error);
|
|
94
|
+
const message = error instanceof BaseError ? error.userMessage : 'Connection test failed';
|
|
95
|
+
setConnectionTestResult({
|
|
96
|
+
success: false,
|
|
97
|
+
message
|
|
98
|
+
});
|
|
99
|
+
if (nonInteractive) {
|
|
100
|
+
console.error('Connection failed:', message);
|
|
101
|
+
setTimeout(() => {
|
|
102
|
+
setStep('checking-knowledge');
|
|
103
|
+
}, 2000);
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
setTimeout(() => {
|
|
107
|
+
setStep('connection-failed');
|
|
108
|
+
}, 2000);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
})();
|
|
112
|
+
}
|
|
113
|
+
}, [step, agentEndpoint, customConfig]);
|
|
43
114
|
useEffect(() => {
|
|
44
115
|
if (step === 'checking-knowledge') {
|
|
45
116
|
(async () => {
|
|
@@ -48,13 +119,42 @@ export const App = ({ backendUrl, dashboardUrl }) => {
|
|
|
48
119
|
setKnowledgeFound(result.found);
|
|
49
120
|
}
|
|
50
121
|
catch (error) {
|
|
51
|
-
|
|
122
|
+
logger.error('Error checking knowledge:', error);
|
|
52
123
|
setKnowledgeFound(false);
|
|
53
124
|
}
|
|
54
|
-
|
|
125
|
+
if (nonInteractive && knowledgeSource) {
|
|
126
|
+
if (knowledgeSource === 'pinecone') {
|
|
127
|
+
if (pineconeUrl && pineconeApiKey) {
|
|
128
|
+
setStep('fetching-pinecone');
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
console.error('Pinecone URL and API key required for Pinecone source');
|
|
132
|
+
process.exit(1);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
else if (knowledgeSource === 'postgresql') {
|
|
136
|
+
if (postgresqlConnectionString) {
|
|
137
|
+
setStep('fetching-postgresql');
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
console.error('PostgreSQL connection string required for PostgreSQL source');
|
|
141
|
+
process.exit(1);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
setStep('running-evaluation');
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
else if (nonInteractive && !knowledgeSource) {
|
|
149
|
+
setKnowledgeSource('files');
|
|
150
|
+
setStep('running-evaluation');
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
setStep('select-source');
|
|
154
|
+
}
|
|
55
155
|
})();
|
|
56
156
|
}
|
|
57
|
-
}, [step]);
|
|
157
|
+
}, [step, nonInteractive, knowledgeSource, pineconeUrl, pineconeApiKey, postgresqlConnectionString]);
|
|
58
158
|
useEffect(() => {
|
|
59
159
|
if (step === 'fetching-pinecone') {
|
|
60
160
|
(async () => {
|
|
@@ -64,14 +164,15 @@ export const App = ({ backendUrl, dashboardUrl }) => {
|
|
|
64
164
|
setStep('running-evaluation');
|
|
65
165
|
}
|
|
66
166
|
catch (error) {
|
|
67
|
-
|
|
167
|
+
logger.error('Error fetching Q&A from Pinecone:', error);
|
|
168
|
+
const errorMessage = error instanceof BaseError ? error.userMessage : error.message;
|
|
68
169
|
setEvaluationResult({
|
|
69
170
|
totalTests: 0,
|
|
70
171
|
passed: 0,
|
|
71
172
|
failed: 0,
|
|
72
173
|
duration: 'Failed',
|
|
73
174
|
evaluationUrl: dashboardUrl || 'https://eval.rippletide.com',
|
|
74
|
-
error:
|
|
175
|
+
error: errorMessage,
|
|
75
176
|
});
|
|
76
177
|
setStep('complete');
|
|
77
178
|
}
|
|
@@ -89,7 +190,7 @@ export const App = ({ backendUrl, dashboardUrl }) => {
|
|
|
89
190
|
else {
|
|
90
191
|
const parts = postgresqlConnectionString.split(',');
|
|
91
192
|
if (parts.length !== 5) {
|
|
92
|
-
throw new
|
|
193
|
+
throw new ValidationError('PostgreSQL connection', postgresqlConnectionString, 'Expected format: host,port,database,user,password or postgresql://...');
|
|
93
194
|
}
|
|
94
195
|
config = {
|
|
95
196
|
host: parts[0].trim(),
|
|
@@ -104,14 +205,15 @@ export const App = ({ backendUrl, dashboardUrl }) => {
|
|
|
104
205
|
setStep('running-evaluation');
|
|
105
206
|
}
|
|
106
207
|
catch (error) {
|
|
107
|
-
|
|
208
|
+
logger.error('Error fetching Q&A from PostgreSQL:', error);
|
|
209
|
+
const errorMessage = error instanceof BaseError ? error.userMessage : error.message;
|
|
108
210
|
setEvaluationResult({
|
|
109
211
|
totalTests: 0,
|
|
110
212
|
passed: 0,
|
|
111
213
|
failed: 0,
|
|
112
214
|
duration: 'Failed',
|
|
113
215
|
evaluationUrl: dashboardUrl || 'https://eval.rippletide.com',
|
|
114
|
-
error:
|
|
216
|
+
error: errorMessage,
|
|
115
217
|
});
|
|
116
218
|
setStep('complete');
|
|
117
219
|
}
|
|
@@ -133,22 +235,48 @@ export const App = ({ backendUrl, dashboardUrl }) => {
|
|
|
133
235
|
setEvaluationProgress(40);
|
|
134
236
|
let testPrompts = [];
|
|
135
237
|
if (knowledgeSource === 'files') {
|
|
136
|
-
|
|
137
|
-
if (knowledgeResult.found && knowledgeResult.path) {
|
|
238
|
+
if (templatePath) {
|
|
138
239
|
try {
|
|
139
240
|
const fs = await import('fs');
|
|
140
|
-
const
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
241
|
+
const path = await import('path');
|
|
242
|
+
const qandaPath = path.join(templatePath, 'qanda.json');
|
|
243
|
+
if (fs.existsSync(qandaPath)) {
|
|
244
|
+
const knowledgeData = JSON.parse(fs.readFileSync(qandaPath, 'utf-8'));
|
|
245
|
+
if (Array.isArray(knowledgeData)) {
|
|
246
|
+
testPrompts = knowledgeData.map((item) => ({
|
|
247
|
+
question: item.question || item.prompt || item.input || 'Test question',
|
|
248
|
+
answer: item.answer || item.response || item.expectedAnswer
|
|
249
|
+
}));
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
else {
|
|
253
|
+
logger.debug('No qanda.json found in template directory:', templatePath);
|
|
146
254
|
}
|
|
147
255
|
}
|
|
148
256
|
catch (error) {
|
|
257
|
+
logger.debug('Error loading prompts from template:', error);
|
|
149
258
|
testPrompts = [];
|
|
150
259
|
}
|
|
151
260
|
}
|
|
261
|
+
else {
|
|
262
|
+
const knowledgeResult = await api.checkKnowledge();
|
|
263
|
+
if (knowledgeResult.found && knowledgeResult.path) {
|
|
264
|
+
try {
|
|
265
|
+
const fs = await import('fs');
|
|
266
|
+
const knowledgeData = JSON.parse(fs.readFileSync(knowledgeResult.path, 'utf-8'));
|
|
267
|
+
if (Array.isArray(knowledgeData)) {
|
|
268
|
+
testPrompts = knowledgeData.slice(0, 5).map((item) => ({
|
|
269
|
+
question: item.question || item.prompt || item.input || 'Test question',
|
|
270
|
+
answer: item.answer || item.response || item.expectedAnswer
|
|
271
|
+
}));
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
catch (error) {
|
|
275
|
+
logger.debug('Error loading prompts from knowledge:', error);
|
|
276
|
+
testPrompts = [];
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
152
280
|
}
|
|
153
281
|
else if (knowledgeSource === 'pinecone' && pineconeQAndA.length > 0) {
|
|
154
282
|
testPrompts = pineconeQAndA.slice(0, 5).map((item) => ({
|
|
@@ -175,7 +303,7 @@ export const App = ({ backendUrl, dashboardUrl }) => {
|
|
|
175
303
|
logs.push({ question: question || '', response: llmResponse });
|
|
176
304
|
setEvaluationLogs([...logs]);
|
|
177
305
|
}
|
|
178
|
-
});
|
|
306
|
+
}, customConfig);
|
|
179
307
|
setEvaluationProgress(100);
|
|
180
308
|
let passed = 0;
|
|
181
309
|
let failed = 0;
|
|
@@ -203,13 +331,15 @@ export const App = ({ backendUrl, dashboardUrl }) => {
|
|
|
203
331
|
setStep('complete');
|
|
204
332
|
}
|
|
205
333
|
catch (error) {
|
|
206
|
-
|
|
334
|
+
logger.error('Error running evaluation:', error);
|
|
335
|
+
const errorMessage = error instanceof BaseError ? error.userMessage : 'Evaluation failed';
|
|
207
336
|
setEvaluationResult({
|
|
208
337
|
totalTests: 0,
|
|
209
338
|
passed: 0,
|
|
210
339
|
failed: 0,
|
|
211
340
|
duration: 'Failed',
|
|
212
341
|
evaluationUrl: dashboardUrl || 'https://eval.rippletide.com',
|
|
342
|
+
error: errorMessage,
|
|
213
343
|
});
|
|
214
344
|
setStep('complete');
|
|
215
345
|
}
|
|
@@ -217,8 +347,12 @@ export const App = ({ backendUrl, dashboardUrl }) => {
|
|
|
217
347
|
}
|
|
218
348
|
}, [step, agentEndpoint, knowledgeSource, pineconeQAndA, postgresqlQAndA]);
|
|
219
349
|
const handleAgentEndpointSubmit = (value) => {
|
|
220
|
-
|
|
221
|
-
|
|
350
|
+
const trimmedValue = value.trim();
|
|
351
|
+
if (!trimmedValue) {
|
|
352
|
+
return;
|
|
353
|
+
}
|
|
354
|
+
setAgentEndpoint(trimmedValue);
|
|
355
|
+
setStep('testing-connection');
|
|
222
356
|
};
|
|
223
357
|
const handleSourceSelect = (value) => {
|
|
224
358
|
setKnowledgeSource(value);
|
|
@@ -247,7 +381,143 @@ export const App = ({ backendUrl, dashboardUrl }) => {
|
|
|
247
381
|
return (React.createElement(Box, { flexDirection: "column", padding: 1 },
|
|
248
382
|
React.createElement(Header, null),
|
|
249
383
|
step === 'agent-endpoint' && (React.createElement(Box, { flexDirection: "column" },
|
|
250
|
-
React.createElement(
|
|
384
|
+
React.createElement(Box, { marginBottom: 1 },
|
|
385
|
+
React.createElement(Text, { color: "#eba1b5" }, "Enter your agent's endpoint URL")),
|
|
386
|
+
React.createElement(Box, { marginBottom: 1 },
|
|
387
|
+
React.createElement(Text, { dimColor: true }, "Examples:"),
|
|
388
|
+
React.createElement(Box, { paddingLeft: 2, flexDirection: "column" },
|
|
389
|
+
React.createElement(Text, { dimColor: true }, "- localhost:8000"),
|
|
390
|
+
React.createElement(Text, { dimColor: true }, "- http://localhost:8000"),
|
|
391
|
+
React.createElement(Text, { dimColor: true }, "- https://my-agent.vercel.app"))),
|
|
392
|
+
React.createElement(TextInput, { label: "Agent endpoint", placeholder: "localhost:8000", onSubmit: handleAgentEndpointSubmit }))),
|
|
393
|
+
step === 'testing-connection' && (React.createElement(Box, { flexDirection: "column" },
|
|
394
|
+
React.createElement(Box, { marginBottom: 1 },
|
|
395
|
+
React.createElement(Spinner, { label: "Testing agent connection..." })),
|
|
396
|
+
connectionTestResult && (React.createElement(Box, { marginTop: 1 },
|
|
397
|
+
React.createElement(Text, { color: connectionTestResult.success ? "green" : "red" }, connectionTestResult.message))))),
|
|
398
|
+
step === 'connection-failed' && (React.createElement(Box, { flexDirection: "column" },
|
|
399
|
+
React.createElement(Box, { marginBottom: 1 },
|
|
400
|
+
React.createElement(Text, { color: "red" }, "Connection failed")),
|
|
401
|
+
React.createElement(Box, { marginBottom: 1 },
|
|
402
|
+
React.createElement(Text, null, connectionTestResult?.message || 'Could not connect to the agent')),
|
|
403
|
+
React.createElement(Box, { marginBottom: 1 },
|
|
404
|
+
React.createElement(Text, { color: "#eba1b5" }, "What would you like to do?")),
|
|
405
|
+
React.createElement(SelectMenu, { title: "Options", options: [
|
|
406
|
+
{ label: 'Try again with same endpoint', value: 'retry', description: 'Test connection again' },
|
|
407
|
+
{ label: 'Change endpoint URL', value: 'change', description: 'Enter a different endpoint' },
|
|
408
|
+
{ label: 'Configure custom parameters', value: 'custom', description: 'Add headers, auth, custom body format' },
|
|
409
|
+
{ label: 'Continue anyway', value: 'continue', description: 'Skip connection test (not recommended)' },
|
|
410
|
+
], onSelect: (value) => {
|
|
411
|
+
if (value === 'retry') {
|
|
412
|
+
setStep('testing-connection');
|
|
413
|
+
}
|
|
414
|
+
else if (value === 'change') {
|
|
415
|
+
setStep('agent-endpoint');
|
|
416
|
+
}
|
|
417
|
+
else if (value === 'custom') {
|
|
418
|
+
setStep('custom-config');
|
|
419
|
+
}
|
|
420
|
+
else if (value === 'continue') {
|
|
421
|
+
setStep('checking-knowledge');
|
|
422
|
+
}
|
|
423
|
+
} }))),
|
|
424
|
+
step === 'custom-config' && (React.createElement(Box, { flexDirection: "column" },
|
|
425
|
+
React.createElement(Box, { marginBottom: 1 },
|
|
426
|
+
React.createElement(Text, { color: "#eba1b5" }, "Configure custom endpoint parameters")),
|
|
427
|
+
React.createElement(Box, { marginBottom: 1 },
|
|
428
|
+
React.createElement(Text, { dimColor: true }, "Choose what to configure:")),
|
|
429
|
+
React.createElement(SelectMenu, { title: "Configuration", options: [
|
|
430
|
+
{ label: 'Add custom headers', value: 'headers', description: 'Authorization, API keys, etc.' },
|
|
431
|
+
{ label: 'Custom request body', value: 'body', description: 'Define exact request structure' },
|
|
432
|
+
{ label: 'Custom response field', value: 'response', description: 'Specify where to find the answer' },
|
|
433
|
+
{ label: 'Test with current config', value: 'test', description: 'Try connection with custom settings' },
|
|
434
|
+
{ label: 'Back', value: 'back', description: 'Return to previous menu' },
|
|
435
|
+
], onSelect: (value) => {
|
|
436
|
+
if (value === 'headers') {
|
|
437
|
+
setStep('custom-headers');
|
|
438
|
+
}
|
|
439
|
+
else if (value === 'body') {
|
|
440
|
+
setStep('custom-body');
|
|
441
|
+
}
|
|
442
|
+
else if (value === 'response') {
|
|
443
|
+
setStep('custom-response');
|
|
444
|
+
}
|
|
445
|
+
else if (value === 'test') {
|
|
446
|
+
setStep('testing-connection');
|
|
447
|
+
}
|
|
448
|
+
else if (value === 'back') {
|
|
449
|
+
setStep('connection-failed');
|
|
450
|
+
}
|
|
451
|
+
} }),
|
|
452
|
+
(customConfig.headers || customConfig.bodyTemplate || customConfig.responseField) && (React.createElement(Box, { marginTop: 1, flexDirection: "column" },
|
|
453
|
+
React.createElement(Text, { color: "green" }, "Current configuration:"),
|
|
454
|
+
customConfig.headers && Object.keys(customConfig.headers).length > 0 && (React.createElement(Text, { dimColor: true },
|
|
455
|
+
"- Headers: ",
|
|
456
|
+
Object.keys(customConfig.headers).join(', '))),
|
|
457
|
+
customConfig.bodyTemplate && (React.createElement(Text, { dimColor: true }, "- Custom body template configured")),
|
|
458
|
+
customConfig.responseField && (React.createElement(Text, { dimColor: true },
|
|
459
|
+
"- Response field: ",
|
|
460
|
+
customConfig.responseField)))))),
|
|
461
|
+
step === 'custom-headers' && (React.createElement(Box, { flexDirection: "column" },
|
|
462
|
+
React.createElement(Box, { marginBottom: 1 },
|
|
463
|
+
React.createElement(Text, { color: "#eba1b5" }, "Add custom headers")),
|
|
464
|
+
React.createElement(Box, { marginBottom: 1 },
|
|
465
|
+
React.createElement(Text, { dimColor: true }, "Format: Header-Name: value (one per line, or comma-separated)"),
|
|
466
|
+
React.createElement(Text, { dimColor: true }, "Examples:"),
|
|
467
|
+
React.createElement(Box, { paddingLeft: 2, flexDirection: "column" },
|
|
468
|
+
React.createElement(Text, { dimColor: true }, "- Authorization: Bearer sk-xxxxx"),
|
|
469
|
+
React.createElement(Text, { dimColor: true }, "- X-API-Key: your-api-key"),
|
|
470
|
+
React.createElement(Text, { dimColor: true }, "- Content-Type: application/json"))),
|
|
471
|
+
React.createElement(TextInput, { label: "Headers (press Enter when done)", placeholder: "Authorization: Bearer token, X-API-Key: key", onSubmit: (value) => {
|
|
472
|
+
const headers = {};
|
|
473
|
+
const headerPairs = value.split(/[,\n]+/);
|
|
474
|
+
headerPairs.forEach(pair => {
|
|
475
|
+
const [key, ...valueParts] = pair.split(':');
|
|
476
|
+
if (key && valueParts.length > 0) {
|
|
477
|
+
headers[key.trim()] = valueParts.join(':').trim();
|
|
478
|
+
}
|
|
479
|
+
});
|
|
480
|
+
setCustomConfig(prev => ({ ...prev, headers }));
|
|
481
|
+
setStep('custom-config');
|
|
482
|
+
} }))),
|
|
483
|
+
step === 'custom-body' && (React.createElement(Box, { flexDirection: "column" },
|
|
484
|
+
React.createElement(Box, { marginBottom: 1 },
|
|
485
|
+
React.createElement(Text, { color: "#eba1b5" }, "Define custom request body")),
|
|
486
|
+
React.createElement(Box, { marginBottom: 1 },
|
|
487
|
+
React.createElement(Text, { dimColor: true },
|
|
488
|
+
"Use ",
|
|
489
|
+
'{question}',
|
|
490
|
+
" as placeholder for the user's question"),
|
|
491
|
+
React.createElement(Text, { dimColor: true }, "Examples:"),
|
|
492
|
+
React.createElement(Box, { paddingLeft: 2, flexDirection: "column" },
|
|
493
|
+
React.createElement(Text, { dimColor: true },
|
|
494
|
+
"- ",
|
|
495
|
+
'{"prompt": "{question}"}'),
|
|
496
|
+
React.createElement(Text, { dimColor: true },
|
|
497
|
+
"- ",
|
|
498
|
+
'{"messages": [{"role": "user", "content": "{question}"}]}'),
|
|
499
|
+
React.createElement(Text, { dimColor: true },
|
|
500
|
+
"- ",
|
|
501
|
+
'{"input": {"text": "{question}"}}'))),
|
|
502
|
+
React.createElement(TextInput, { label: "Body template (JSON format)", placeholder: '{"prompt": "{question}"}', onSubmit: (value) => {
|
|
503
|
+
setCustomConfig(prev => ({ ...prev, bodyTemplate: value }));
|
|
504
|
+
setStep('custom-config');
|
|
505
|
+
} }))),
|
|
506
|
+
step === 'custom-response' && (React.createElement(Box, { flexDirection: "column" },
|
|
507
|
+
React.createElement(Box, { marginBottom: 1 },
|
|
508
|
+
React.createElement(Text, { color: "#eba1b5" }, "Specify response field")),
|
|
509
|
+
React.createElement(Box, { marginBottom: 1 },
|
|
510
|
+
React.createElement(Text, { dimColor: true }, "Where to find the answer in the response?"),
|
|
511
|
+
React.createElement(Text, { dimColor: true }, "Examples:"),
|
|
512
|
+
React.createElement(Box, { paddingLeft: 2, flexDirection: "column" },
|
|
513
|
+
React.createElement(Text, { dimColor: true }, "- answer"),
|
|
514
|
+
React.createElement(Text, { dimColor: true }, "- data.response"),
|
|
515
|
+
React.createElement(Text, { dimColor: true }, "- choices[0].message.content"),
|
|
516
|
+
React.createElement(Text, { dimColor: true }, "- result.text"))),
|
|
517
|
+
React.createElement(TextInput, { label: "Response field path", placeholder: "answer", onSubmit: (value) => {
|
|
518
|
+
setCustomConfig(prev => ({ ...prev, responseField: value }));
|
|
519
|
+
setStep('custom-config');
|
|
520
|
+
} }))),
|
|
251
521
|
step === 'checking-knowledge' && (React.createElement(Box, { flexDirection: "column" },
|
|
252
522
|
React.createElement(Spinner, { label: "Checking for knowledge base in current folder..." }))),
|
|
253
523
|
step === 'select-source' && (React.createElement(Box, { flexDirection: "column" },
|
|
@@ -279,7 +549,7 @@ export const App = ({ backendUrl, dashboardUrl }) => {
|
|
|
279
549
|
React.createElement(Box, null,
|
|
280
550
|
React.createElement(Box, { width: 12 },
|
|
281
551
|
React.createElement(Text, { dimColor: true }, "Endpoint:")),
|
|
282
|
-
React.createElement(Text, null, agentEndpoint
|
|
552
|
+
React.createElement(Text, null, agentEndpoint)),
|
|
283
553
|
React.createElement(Box, null,
|
|
284
554
|
React.createElement(Box, { width: 12 },
|
|
285
555
|
React.createElement(Text, { dimColor: true }, "Data Source:")),
|
|
@@ -295,6 +565,9 @@ export const App = ({ backendUrl, dashboardUrl }) => {
|
|
|
295
565
|
React.createElement(Text, { bold: true, color: "green" }, "LLM Response:")),
|
|
296
566
|
React.createElement(Box, { paddingLeft: 2 },
|
|
297
567
|
React.createElement(Text, null, currentLLMResponse.length > 200 ? currentLLMResponse.substring(0, 200) + '...' : currentLLMResponse)))))),
|
|
298
|
-
step === 'complete' && evaluationResult && (React.createElement(Box, { flexDirection: "column" },
|
|
299
|
-
React.createElement(
|
|
568
|
+
step === 'complete' && evaluationResult && (React.createElement(Box, { flexDirection: "column" }, evaluationResult.error ? (React.createElement(Box, { flexDirection: "column" },
|
|
569
|
+
React.createElement(Text, { color: "red" }, "Error: Evaluation Failed"),
|
|
570
|
+
React.createElement(Text, null, evaluationResult.error),
|
|
571
|
+
React.createElement(Box, { marginTop: 1 },
|
|
572
|
+
React.createElement(Text, { dimColor: true }, "Run with --debug flag for more details")))) : (React.createElement(Summary, { totalTests: evaluationResult.totalTests, passed: evaluationResult.passed, failed: evaluationResult.failed, duration: evaluationResult.duration, evaluationUrl: evaluationResult.evaluationUrl }))))));
|
|
300
573
|
};
|
package/dist/api/client.d.ts
CHANGED
|
@@ -1,59 +1,28 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
failed: number;
|
|
9
|
-
duration: string;
|
|
10
|
-
evaluationUrl: string;
|
|
11
|
-
agentId?: string;
|
|
12
|
-
}
|
|
13
|
-
export interface HallucinationCheckResult {
|
|
14
|
-
question: string;
|
|
15
|
-
llmResponse: string;
|
|
16
|
-
summary: string;
|
|
17
|
-
facts: string[];
|
|
18
|
-
status: 'passed' | 'failed' | 'ambiguous';
|
|
19
|
-
hallucinationLabel: string;
|
|
20
|
-
hallucinationFindings: any[];
|
|
21
|
-
}
|
|
22
|
-
export interface PromptEvaluationResult {
|
|
23
|
-
success: boolean;
|
|
24
|
-
question: string;
|
|
25
|
-
llmResponse?: string;
|
|
26
|
-
hallucinationResult?: HallucinationCheckResult;
|
|
27
|
-
error?: any;
|
|
28
|
-
}
|
|
1
|
+
import { testAgentConnection, testAgentConnectionWithConfig } from './connection.js';
|
|
2
|
+
import { callLLMEndpoint } from './llm.js';
|
|
3
|
+
import { normalizeEndpoint, generatePayloadVariants, type CustomEndpointConfig } from './endpoint.js';
|
|
4
|
+
import { extractResponseText, extractCustomResponseField } from './response.js';
|
|
5
|
+
import { setBackendUrl, generateApiKey, createAgent, addTestPrompts, checkHallucination, runPromptEvaluation, runAllPromptEvaluations, type HallucinationCheckResult, type PromptEvaluationResult } from './evaluation.js';
|
|
6
|
+
import { healthCheck, checkKnowledge, importKnowledge, getTestResults, runEvaluation, type EvaluationConfig, type EvaluationResult } from './knowledge.js';
|
|
7
|
+
export type { CustomEndpointConfig, HallucinationCheckResult, PromptEvaluationResult, EvaluationConfig, EvaluationResult };
|
|
29
8
|
export declare const api: {
|
|
30
|
-
setBaseUrl
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
runAllPromptEvaluations(agentId: string, prompts: any[], agentEndpoint: string, onProgress?: (current: number, total: number, question?: string, llmResponse?: string) => void): Promise<PromptEvaluationResult[]>;
|
|
50
|
-
getTestResults(agentId: string): Promise<any>;
|
|
51
|
-
runEvaluation(config: EvaluationConfig, onProgress?: (progress: number) => void): Promise<{
|
|
52
|
-
totalTests: any;
|
|
53
|
-
passed: number;
|
|
54
|
-
failed: number;
|
|
55
|
-
duration: string;
|
|
56
|
-
evaluationUrl: string;
|
|
57
|
-
agentId: any;
|
|
58
|
-
}>;
|
|
9
|
+
setBaseUrl: typeof setBackendUrl;
|
|
10
|
+
testAgentConnection: typeof testAgentConnection;
|
|
11
|
+
testAgentConnectionWithConfig: typeof testAgentConnectionWithConfig;
|
|
12
|
+
normalizeEndpoint: typeof normalizeEndpoint;
|
|
13
|
+
generatePayloadVariants: typeof generatePayloadVariants;
|
|
14
|
+
extractResponseText: typeof extractResponseText;
|
|
15
|
+
extractCustomResponseField: typeof extractCustomResponseField;
|
|
16
|
+
callLLMEndpoint: typeof callLLMEndpoint;
|
|
17
|
+
generateApiKey: typeof generateApiKey;
|
|
18
|
+
healthCheck: typeof healthCheck;
|
|
19
|
+
checkKnowledge: typeof checkKnowledge;
|
|
20
|
+
createAgent: typeof createAgent;
|
|
21
|
+
importKnowledge: typeof importKnowledge;
|
|
22
|
+
addTestPrompts: typeof addTestPrompts;
|
|
23
|
+
checkHallucination: typeof checkHallucination;
|
|
24
|
+
runPromptEvaluation: typeof runPromptEvaluation;
|
|
25
|
+
runAllPromptEvaluations: typeof runAllPromptEvaluations;
|
|
26
|
+
getTestResults: typeof getTestResults;
|
|
27
|
+
runEvaluation: typeof runEvaluation;
|
|
59
28
|
};
|