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.
Files changed (67) hide show
  1. package/bin/rippletide +32 -2
  2. package/dist/App.d.ts +10 -0
  3. package/dist/App.js +305 -32
  4. package/dist/api/client.d.ts +26 -57
  5. package/dist/api/client.js +25 -512
  6. package/dist/api/connection.d.ts +11 -0
  7. package/dist/api/connection.js +116 -0
  8. package/dist/api/endpoint.d.ts +11 -0
  9. package/dist/api/endpoint.js +76 -0
  10. package/dist/api/evaluation.d.ts +27 -0
  11. package/dist/api/evaluation.js +299 -0
  12. package/dist/api/knowledge.d.ts +31 -0
  13. package/dist/api/knowledge.js +138 -0
  14. package/dist/api/llm.d.ts +2 -0
  15. package/dist/api/llm.js +98 -0
  16. package/dist/api/response.d.ts +2 -0
  17. package/dist/api/response.js +66 -0
  18. package/dist/errors/handler.d.ts +11 -0
  19. package/dist/errors/handler.js +155 -0
  20. package/dist/errors/index.d.ts +3 -0
  21. package/dist/errors/index.js +3 -0
  22. package/dist/errors/transform.d.ts +7 -0
  23. package/dist/errors/transform.js +60 -0
  24. package/dist/errors/types.d.ts +44 -0
  25. package/dist/errors/types.js +103 -0
  26. package/dist/index.js +152 -6
  27. package/dist/utils/pinecone.js +16 -11
  28. package/dist/utils/postgresql.js +7 -3
  29. package/dist/utils/templates.d.ts +21 -0
  30. package/dist/utils/templates.js +71 -0
  31. package/package.json +3 -2
  32. package/src/App.tsx +397 -37
  33. package/src/api/client.ts +55 -621
  34. package/src/api/connection.ts +139 -0
  35. package/src/api/endpoint.ts +97 -0
  36. package/src/api/evaluation.ts +390 -0
  37. package/src/api/knowledge.ts +179 -0
  38. package/src/api/llm.ts +124 -0
  39. package/src/api/response.ts +77 -0
  40. package/src/errors/handler.ts +191 -0
  41. package/src/errors/index.ts +4 -0
  42. package/src/errors/transform.ts +107 -0
  43. package/src/errors/types.ts +180 -0
  44. package/src/index.tsx +164 -7
  45. package/src/utils/pinecone.ts +16 -11
  46. package/src/utils/postgresql.ts +7 -3
  47. package/src/utils/templates.ts +104 -0
  48. package/templates/banking_analyst/config.json +12 -0
  49. package/templates/banking_analyst/qanda.json +62 -0
  50. package/templates/blog_to_linkedin/config.json +12 -0
  51. package/templates/blog_to_linkedin/qanda.json +66 -0
  52. package/templates/customer_service/config.json +12 -0
  53. package/templates/customer_service/qanda.json +62 -0
  54. package/templates/local_dev/config.json +7 -0
  55. package/templates/luxe_concierge/config.json +12 -0
  56. package/templates/luxe_concierge/qanda.json +54 -0
  57. package/templates/openai_compatible/config.json +13 -0
  58. package/templates/project_manager/config.json +12 -0
  59. package/templates/project_manager/qanda.json +62 -0
  60. package/dist/components/InputPrompt.d.ts +0 -8
  61. package/dist/components/InputPrompt.js +0 -12
  62. package/dist/demo.d.ts +0 -2
  63. package/dist/demo.js +0 -97
  64. package/dist/scripts/test-postgresql.d.ts +0 -2
  65. package/dist/scripts/test-postgresql.js +0 -53
  66. package/dist/utils/postgresql-qa-generator.d.ts +0 -7
  67. 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
- console.error('Error running rippletide:', err?.message || err);
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 [step, setStep] = useState('agent-endpoint');
23
- const [agentEndpoint, setAgentEndpoint] = useState('');
24
- const [knowledgeSource, setKnowledgeSource] = useState('');
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
- console.error('Error checking knowledge:', error);
122
+ logger.error('Error checking knowledge:', error);
52
123
  setKnowledgeFound(false);
53
124
  }
54
- setStep('select-source');
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
- console.error('Error fetching Q&A from Pinecone:', error);
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: error.message,
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 Error('Invalid connection format. Expected: host,port,database,user,password or postgresql://...');
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
- console.error('Error fetching Q&A from PostgreSQL:', error);
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: error.message,
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
- const knowledgeResult = await api.checkKnowledge();
137
- if (knowledgeResult.found && knowledgeResult.path) {
238
+ if (templatePath) {
138
239
  try {
139
240
  const fs = await import('fs');
140
- const knowledgeData = JSON.parse(fs.readFileSync(knowledgeResult.path, 'utf-8'));
141
- if (Array.isArray(knowledgeData)) {
142
- testPrompts = knowledgeData.slice(0, 5).map((item) => ({
143
- question: item.question || item.prompt || item.input || 'Test question',
144
- answer: item.answer || item.response || item.expectedAnswer
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
- console.error('Error running evaluation:', error);
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
- setAgentEndpoint(value);
221
- setStep('checking-knowledge');
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(TextInput, { label: "Agent endpoint", placeholder: "http://localhost:8000", onSubmit: handleAgentEndpointSubmit }))),
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 || 'http://localhost:8000')),
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(Summary, { totalTests: evaluationResult.totalTests, passed: evaluationResult.passed, failed: evaluationResult.failed, duration: evaluationResult.duration, evaluationUrl: evaluationResult.evaluationUrl })))));
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
  };
@@ -1,59 +1,28 @@
1
- export interface EvaluationConfig {
2
- agentEndpoint: string;
3
- knowledgeSource?: string;
4
- }
5
- export interface EvaluationResult {
6
- totalTests: number;
7
- passed: number;
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(url: string): void;
31
- generateApiKey(name?: string): Promise<any>;
32
- healthCheck(): Promise<any>;
33
- checkKnowledge(folderPath?: string): Promise<{
34
- found: boolean;
35
- path: string;
36
- } | {
37
- found: boolean;
38
- path?: undefined;
39
- }>;
40
- createAgent(publicUrl: string): Promise<any>;
41
- importKnowledge(agentId: string, knowledgeData: any): Promise<any>;
42
- addTestPrompts(agentId: string, prompts?: string[] | Array<{
43
- question: string;
44
- answer?: string;
45
- }>): Promise<any>;
46
- checkHallucination(agentId: string, question: string, llmResponse: string, expectedAnswer?: string): Promise<HallucinationCheckResult>;
47
- callLLMEndpoint(agentEndpoint: string, question: string): Promise<string>;
48
- runPromptEvaluation(agentId: string, promptId: number, promptText: string, agentEndpoint: string, expectedAnswer?: string, onLLMResponse?: (response: string) => void): Promise<PromptEvaluationResult>;
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
  };