rippletide 1.0.13 → 1.0.15
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 +4 -26
- package/dist/App.d.ts +1 -0
- package/dist/App.js +70 -14
- package/dist/api/knowledge.d.ts +4 -1
- package/dist/api/knowledge.js +36 -6
- package/dist/index.js +8 -13
- package/dist/utils/analytics.js +0 -5
- package/dist/utils/templates.d.ts +5 -3
- package/dist/utils/templates.js +88 -18
- package/package.json +1 -1
- package/src/App.tsx +69 -13
- package/src/api/knowledge.ts +42 -7
- package/src/index.tsx +8 -7
- package/src/utils/templates.ts +102 -20
- package/templates/luxe_concierge/qanda.json +1 -1
package/bin/rippletide
CHANGED
|
@@ -13,12 +13,6 @@ async function loadErrorHandler() {
|
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
async function main() {
|
|
16
|
-
if (!cmd || cmd === 'eval') {
|
|
17
|
-
process.argv = ['node', 'dist/index.js', ...args.slice(cmd === 'eval' ? 1 : 0)];
|
|
18
|
-
await import('../dist/index.js');
|
|
19
|
-
return;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
16
|
if (cmd === 'list-templates' || cmd === 'templates') {
|
|
23
17
|
process.argv = ['node', 'dist/index.js', ...args];
|
|
24
18
|
await import('../dist/index.js');
|
|
@@ -26,29 +20,13 @@ async function main() {
|
|
|
26
20
|
}
|
|
27
21
|
|
|
28
22
|
if (cmd === '--help' || cmd === '-h') {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
Usage:
|
|
33
|
-
rippletide eval [options] Run the Rippletide evaluation UI
|
|
34
|
-
|
|
35
|
-
Options:
|
|
36
|
-
-b, --backend-url <url> Backend API URL (default: https://rippletide-backend.azurewebsites.net)
|
|
37
|
-
-d, --dashboard-url <url> Dashboard URL (default: https://eval.rippletide.com)
|
|
38
|
-
--debug Show detailed error information and stack traces
|
|
39
|
-
-h, --help Show this help message
|
|
40
|
-
|
|
41
|
-
Examples:
|
|
42
|
-
rippletide eval
|
|
43
|
-
rippletide eval -b http://localhost:3001 -d http://localhost:5173
|
|
44
|
-
rippletide eval --debug
|
|
45
|
-
`);
|
|
23
|
+
process.argv = ['node', 'dist/index.js', '--help'];
|
|
24
|
+
await import('../dist/index.js');
|
|
46
25
|
return;
|
|
47
26
|
}
|
|
48
27
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
process.exit(1);
|
|
28
|
+
process.argv = ['node', 'dist/index.js', ...args.slice(cmd === 'eval' ? 1 : 0)];
|
|
29
|
+
await import('../dist/index.js');
|
|
52
30
|
}
|
|
53
31
|
|
|
54
32
|
main().catch(async (err) => {
|
package/dist/App.d.ts
CHANGED
package/dist/App.js
CHANGED
|
@@ -22,7 +22,7 @@ const knowledgeSources = [
|
|
|
22
22
|
{ label: 'GitHub Repository', value: 'github', description: 'Import from GitHub repo', disabled: true },
|
|
23
23
|
{ label: 'Skip (No Knowledge)', value: 'skip', description: 'Run tests without knowledge base', disabled: true },
|
|
24
24
|
];
|
|
25
|
-
export const App = ({ backendUrl, dashboardUrl, nonInteractive, agentEndpoint: initialAgentEndpoint, knowledgeSource: initialKnowledgeSource, pineconeUrl: initialPineconeUrl, pineconeApiKey: initialPineconeApiKey, postgresqlConnection: initialPostgresqlConnection, pdfPath: initialPdfPath, customHeaders, customBodyTemplate, customResponseField, templatePath }) => {
|
|
25
|
+
export const App = ({ backendUrl, dashboardUrl, nonInteractive, agentEndpoint: initialAgentEndpoint, knowledgeSource: initialKnowledgeSource, pineconeUrl: initialPineconeUrl, pineconeApiKey: initialPineconeApiKey, postgresqlConnection: initialPostgresqlConnection, pdfPath: initialPdfPath, customHeaders, customBodyTemplate, customResponseField, templatePath, isRemoteTemplate }) => {
|
|
26
26
|
const { exit } = useApp();
|
|
27
27
|
const initialStep = nonInteractive && initialAgentEndpoint ? 'testing-connection' : 'agent-endpoint';
|
|
28
28
|
const [step, setStep] = useState(initialStep);
|
|
@@ -299,25 +299,82 @@ export const App = ({ backendUrl, dashboardUrl, nonInteractive, agentEndpoint: i
|
|
|
299
299
|
setCurrentAgentId(agentId);
|
|
300
300
|
}
|
|
301
301
|
setEvaluationProgress(30);
|
|
302
|
+
if (knowledgeSource === 'files') {
|
|
303
|
+
let knowledgeData = null;
|
|
304
|
+
if (templatePath) {
|
|
305
|
+
try {
|
|
306
|
+
if (isRemoteTemplate) {
|
|
307
|
+
const axios = await import('axios');
|
|
308
|
+
const qandaUrl = `${templatePath}/qanda.json`;
|
|
309
|
+
const response = await axios.default.get(qandaUrl, { timeout: 5000 });
|
|
310
|
+
knowledgeData = response.data;
|
|
311
|
+
}
|
|
312
|
+
else {
|
|
313
|
+
const fs = await import('fs');
|
|
314
|
+
const path = await import('path');
|
|
315
|
+
const qandaPath = path.join(templatePath, 'qanda.json');
|
|
316
|
+
if (fs.existsSync(qandaPath)) {
|
|
317
|
+
knowledgeData = JSON.parse(fs.readFileSync(qandaPath, 'utf-8'));
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
catch (error) {
|
|
322
|
+
logger.debug('Error loading knowledge from template:', error);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
else {
|
|
326
|
+
const knowledgeResult = await api.checkKnowledge();
|
|
327
|
+
if (knowledgeResult.found && knowledgeResult.path) {
|
|
328
|
+
try {
|
|
329
|
+
const fs = await import('fs');
|
|
330
|
+
knowledgeData = JSON.parse(fs.readFileSync(knowledgeResult.path, 'utf-8'));
|
|
331
|
+
}
|
|
332
|
+
catch (error) {
|
|
333
|
+
logger.debug('Error loading knowledge:', error);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
if (knowledgeData) {
|
|
338
|
+
setEvaluationProgress(35);
|
|
339
|
+
try {
|
|
340
|
+
const importResult = await api.importKnowledge(agentId, knowledgeData);
|
|
341
|
+
logger.debug('Knowledge import result:', importResult);
|
|
342
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
343
|
+
}
|
|
344
|
+
catch (error) {
|
|
345
|
+
logger.error('Failed to import knowledge:', error?.message || error);
|
|
346
|
+
logger.debug('Import error details:', error?.response?.data);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
}
|
|
302
350
|
setEvaluationProgress(40);
|
|
303
351
|
let testPrompts = [];
|
|
304
352
|
if (knowledgeSource === 'files') {
|
|
305
353
|
if (templatePath) {
|
|
306
354
|
try {
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
const
|
|
312
|
-
|
|
313
|
-
testPrompts = knowledgeData.map((item) => ({
|
|
314
|
-
question: item.question || item.prompt || item.input || 'Test question',
|
|
315
|
-
answer: item.answer || item.response || item.expectedAnswer
|
|
316
|
-
}));
|
|
317
|
-
}
|
|
355
|
+
let knowledgeData = null;
|
|
356
|
+
if (isRemoteTemplate) {
|
|
357
|
+
const axios = await import('axios');
|
|
358
|
+
const qandaUrl = `${templatePath}/qanda.json`;
|
|
359
|
+
const response = await axios.default.get(qandaUrl, { timeout: 5000 });
|
|
360
|
+
knowledgeData = response.data;
|
|
318
361
|
}
|
|
319
362
|
else {
|
|
320
|
-
|
|
363
|
+
const fs = await import('fs');
|
|
364
|
+
const path = await import('path');
|
|
365
|
+
const qandaPath = path.join(templatePath, 'qanda.json');
|
|
366
|
+
if (fs.existsSync(qandaPath)) {
|
|
367
|
+
knowledgeData = JSON.parse(fs.readFileSync(qandaPath, 'utf-8'));
|
|
368
|
+
}
|
|
369
|
+
else {
|
|
370
|
+
logger.debug('No qanda.json found in template directory:', templatePath);
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
if (knowledgeData && Array.isArray(knowledgeData)) {
|
|
374
|
+
testPrompts = knowledgeData.map((item) => ({
|
|
375
|
+
question: item.question || item.prompt || item.input || 'Test question',
|
|
376
|
+
answer: item.answer || item.response || item.expectedAnswer
|
|
377
|
+
}));
|
|
321
378
|
}
|
|
322
379
|
}
|
|
323
380
|
catch (error) {
|
|
@@ -365,7 +422,6 @@ export const App = ({ backendUrl, dashboardUrl, nonInteractive, agentEndpoint: i
|
|
|
365
422
|
}
|
|
366
423
|
const createdPrompts = await api.addTestPrompts(agentId, testPrompts);
|
|
367
424
|
setEvaluationProgress(50);
|
|
368
|
-
// Ensure customConfig has the body template for evaluation
|
|
369
425
|
const evalConfig = {
|
|
370
426
|
...customConfig,
|
|
371
427
|
bodyTemplate: customConfig.bodyTemplate || '{"message": "[eval-question]"}'
|
package/dist/api/knowledge.d.ts
CHANGED
|
@@ -7,7 +7,10 @@ export declare function checkKnowledge(folderPath?: string): Promise<{
|
|
|
7
7
|
found: boolean;
|
|
8
8
|
path?: undefined;
|
|
9
9
|
}>;
|
|
10
|
-
export declare function importKnowledge(agentId: string, knowledgeData: any): Promise<
|
|
10
|
+
export declare function importKnowledge(agentId: string, knowledgeData: any): Promise<{
|
|
11
|
+
imported: number;
|
|
12
|
+
total: number;
|
|
13
|
+
} | null>;
|
|
11
14
|
export declare function getTestResults(agentId: string): Promise<any>;
|
|
12
15
|
export interface EvaluationConfig {
|
|
13
16
|
agentEndpoint: string;
|
package/dist/api/knowledge.js
CHANGED
|
@@ -41,14 +41,44 @@ export async function checkKnowledge(folderPath = '.') {
|
|
|
41
41
|
}
|
|
42
42
|
export async function importKnowledge(agentId, knowledgeData) {
|
|
43
43
|
try {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
44
|
+
logger.debug('Importing knowledge for agent:', agentId);
|
|
45
|
+
logger.debug('Knowledge data type:', Array.isArray(knowledgeData) ? 'array' : typeof knowledgeData);
|
|
46
|
+
logger.debug('Knowledge data length:', Array.isArray(knowledgeData) ? knowledgeData.length : 'N/A');
|
|
47
|
+
if (!Array.isArray(knowledgeData)) {
|
|
48
|
+
logger.warn('Knowledge data is not an array, skipping import');
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
let importedCount = 0;
|
|
52
|
+
for (const item of knowledgeData) {
|
|
53
|
+
try {
|
|
54
|
+
const question = item.question || item.prompt || item.input;
|
|
55
|
+
const answer = item.answer || item.response || item.expectedAnswer;
|
|
56
|
+
if (!question || !answer) {
|
|
57
|
+
logger.debug('Skipping item without question or answer:', item);
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
const response = await client.post(`/api/agents/${agentId}/config`, {
|
|
61
|
+
label: question,
|
|
62
|
+
description: answer,
|
|
63
|
+
type: 'knowledge'
|
|
64
|
+
});
|
|
65
|
+
importedCount++;
|
|
66
|
+
logger.debug(`Imported Q&A ${importedCount}/${knowledgeData.length}: ${question.substring(0, 50)}...`);
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
logger.warn(`Failed to import Q&A pair: ${error?.message || error}`);
|
|
70
|
+
logger.debug('Q&A import error details:', error?.response?.data);
|
|
71
|
+
logger.debug('Q&A import error status:', error?.response?.status);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
logger.info(`Knowledge imported successfully: ${importedCount}/${knowledgeData.length} Q&A pairs`);
|
|
75
|
+
return { imported: importedCount, total: knowledgeData.length };
|
|
48
76
|
}
|
|
49
77
|
catch (error) {
|
|
50
|
-
logger.error('Error importing knowledge:', error);
|
|
51
|
-
|
|
78
|
+
logger.error('Error importing knowledge:', error?.message || error);
|
|
79
|
+
logger.debug('Error details:', error?.response?.data);
|
|
80
|
+
logger.debug('Error status:', error?.response?.status);
|
|
81
|
+
throw error;
|
|
52
82
|
}
|
|
53
83
|
}
|
|
54
84
|
export async function getTestResults(agentId) {
|
package/dist/index.js
CHANGED
|
@@ -6,13 +6,13 @@ import { ErrorHandler } from './errors/handler.js';
|
|
|
6
6
|
import { ValidationError } from './errors/types.js';
|
|
7
7
|
import { listTemplates, loadTemplate, getTemplateOptions } from './utils/templates.js';
|
|
8
8
|
import { analytics } from './utils/analytics.js';
|
|
9
|
-
const parseArgs = () => {
|
|
9
|
+
const parseArgs = async () => {
|
|
10
10
|
const args = process.argv.slice(2);
|
|
11
11
|
if (args[0] === 'list-templates' || args[0] === 'templates') {
|
|
12
|
-
const templates = listTemplates();
|
|
12
|
+
const templates = await listTemplates();
|
|
13
13
|
console.log('\nAvailable Templates:\n');
|
|
14
14
|
if (templates.length === 0) {
|
|
15
|
-
console.log('No templates found
|
|
15
|
+
console.log('No templates found');
|
|
16
16
|
}
|
|
17
17
|
else {
|
|
18
18
|
templates.forEach(template => {
|
|
@@ -37,15 +37,15 @@ const parseArgs = () => {
|
|
|
37
37
|
};
|
|
38
38
|
for (let i = 0; i < args.length; i++) {
|
|
39
39
|
if ((args[i] === '--template' || args[i] === '-t') && args[i + 1]) {
|
|
40
|
-
const template = loadTemplate(args[i + 1]);
|
|
40
|
+
const template = await loadTemplate(args[i + 1]);
|
|
41
41
|
if (!template) {
|
|
42
42
|
console.error(`Template '${args[i + 1]}' not found.`);
|
|
43
43
|
console.log('\nAvailable templates:');
|
|
44
|
-
const templates = listTemplates();
|
|
44
|
+
const templates = await listTemplates();
|
|
45
45
|
templates.forEach(t => console.log(` - ${t.name}`));
|
|
46
46
|
process.exit(1);
|
|
47
47
|
}
|
|
48
|
-
const templateOptions = getTemplateOptions(template);
|
|
48
|
+
const templateOptions = await getTemplateOptions(template);
|
|
49
49
|
Object.assign(options, templateOptions);
|
|
50
50
|
i++;
|
|
51
51
|
}
|
|
@@ -184,14 +184,12 @@ Examples:
|
|
|
184
184
|
};
|
|
185
185
|
async function run() {
|
|
186
186
|
try {
|
|
187
|
-
const options = parseArgs();
|
|
188
|
-
// Check if this is a new user
|
|
187
|
+
const options = await parseArgs();
|
|
189
188
|
const fs = await import('fs');
|
|
190
189
|
const path = await import('path');
|
|
191
190
|
const os = await import('os');
|
|
192
191
|
const configPath = path.join(os.homedir(), '.rippletide', 'config.json');
|
|
193
192
|
const isNewUser = !fs.existsSync(configPath);
|
|
194
|
-
// Track start event and wait for it to be sent
|
|
195
193
|
analytics.track('cli_started', {
|
|
196
194
|
command: process.argv[2] || 'eval',
|
|
197
195
|
has_template: !!options.templatePath,
|
|
@@ -199,19 +197,16 @@ async function run() {
|
|
|
199
197
|
is_non_interactive: options.nonInteractive,
|
|
200
198
|
is_new_user: isNewUser,
|
|
201
199
|
});
|
|
202
|
-
// Track new user activation separately
|
|
203
200
|
if (isNewUser) {
|
|
204
201
|
analytics.track('new_user_activated', {
|
|
205
202
|
source: process.argv[2] || 'eval',
|
|
206
203
|
activation_date: new Date().toISOString(),
|
|
207
204
|
});
|
|
208
205
|
}
|
|
209
|
-
// Give PostHog a moment to send the event
|
|
210
206
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
211
207
|
process.stdout.write('\x1Bc');
|
|
212
|
-
const { waitUntilExit } = render(React.createElement(App, { backendUrl: options.backendUrl, dashboardUrl: options.dashboardUrl, nonInteractive: options.nonInteractive, agentEndpoint: options.agentEndpoint, knowledgeSource: options.knowledgeSource, pineconeUrl: options.pineconeUrl, pineconeApiKey: options.pineconeApiKey, postgresqlConnection: options.postgresqlConnection, customHeaders: options.headers, customBodyTemplate: options.bodyTemplate, customResponseField: options.responseField, templatePath: options.templatePath, pdfPath: options.pdfPath }));
|
|
208
|
+
const { waitUntilExit } = render(React.createElement(App, { backendUrl: options.backendUrl, dashboardUrl: options.dashboardUrl, nonInteractive: options.nonInteractive, agentEndpoint: options.agentEndpoint, knowledgeSource: options.knowledgeSource, pineconeUrl: options.pineconeUrl, pineconeApiKey: options.pineconeApiKey, postgresqlConnection: options.postgresqlConnection, customHeaders: options.headers, customBodyTemplate: options.bodyTemplate, customResponseField: options.responseField, templatePath: options.templatePath, isRemoteTemplate: options.isRemoteTemplate, pdfPath: options.pdfPath }));
|
|
213
209
|
await waitUntilExit();
|
|
214
|
-
// Ensure all events are sent before exiting
|
|
215
210
|
await analytics.shutdown();
|
|
216
211
|
await new Promise(resolve => setTimeout(resolve, 500));
|
|
217
212
|
}
|
package/dist/utils/analytics.js
CHANGED
|
@@ -33,7 +33,6 @@ class Analytics {
|
|
|
33
33
|
if (process.env.DEBUG_ANALYTICS) {
|
|
34
34
|
console.log('[Analytics] Client initialized with ID:', this.distinctId);
|
|
35
35
|
}
|
|
36
|
-
// Force flush on various exit events
|
|
37
36
|
const cleanup = () => {
|
|
38
37
|
if (this.client) {
|
|
39
38
|
this.client.shutdown();
|
|
@@ -149,13 +148,11 @@ class Analytics {
|
|
|
149
148
|
const config = this.getConfig();
|
|
150
149
|
const firstSeen = config.first_seen || new Date().toISOString();
|
|
151
150
|
const totalLaunches = (config.total_launches || 0) + 1;
|
|
152
|
-
// Save first seen and increment launch count
|
|
153
151
|
this.saveConfig({
|
|
154
152
|
...config,
|
|
155
153
|
first_seen: firstSeen,
|
|
156
154
|
total_launches: totalLaunches
|
|
157
155
|
});
|
|
158
|
-
// Identify the user with persistent properties
|
|
159
156
|
this.client.identify({
|
|
160
157
|
distinctId: this.distinctId,
|
|
161
158
|
properties: {
|
|
@@ -168,7 +165,6 @@ class Analytics {
|
|
|
168
165
|
hostname_hash: createHash('sha256').update(os.hostname()).digest('hex').substring(0, 8),
|
|
169
166
|
},
|
|
170
167
|
});
|
|
171
|
-
// Also set these as super properties for all events
|
|
172
168
|
this.client.capture({
|
|
173
169
|
distinctId: this.distinctId,
|
|
174
170
|
event: '$set',
|
|
@@ -200,7 +196,6 @@ class Analytics {
|
|
|
200
196
|
});
|
|
201
197
|
}
|
|
202
198
|
catch (error) {
|
|
203
|
-
// Silently fail
|
|
204
199
|
}
|
|
205
200
|
}
|
|
206
201
|
async shutdown() {
|
|
@@ -15,7 +15,9 @@ export interface Template {
|
|
|
15
15
|
name: string;
|
|
16
16
|
path: string;
|
|
17
17
|
config: TemplateConfig;
|
|
18
|
+
isRemote?: boolean;
|
|
18
19
|
}
|
|
19
|
-
export declare const listTemplates: () => Template[]
|
|
20
|
-
export declare const loadTemplate: (templateName: string) => Template | null
|
|
21
|
-
export declare const getTemplateOptions: (template: Template) => any
|
|
20
|
+
export declare const listTemplates: () => Promise<Template[]>;
|
|
21
|
+
export declare const loadTemplate: (templateName: string) => Promise<Template | null>;
|
|
22
|
+
export declare const getTemplateOptions: (template: Template) => Promise<any>;
|
|
23
|
+
export declare const loadRemoteQAndA: (templateName: string) => Promise<any>;
|
package/dist/utils/templates.js
CHANGED
|
@@ -1,25 +1,43 @@
|
|
|
1
1
|
import * as fs from 'fs';
|
|
2
2
|
import * as path from 'path';
|
|
3
|
+
import axios from 'axios';
|
|
4
|
+
const GITHUB_BASE_URL = 'https://raw.githubusercontent.com/rippletideco/starter/refs/heads/main/cli/templates';
|
|
5
|
+
const REMOTE_TEMPLATES = [
|
|
6
|
+
'banking_analyst',
|
|
7
|
+
'blog_to_linkedin',
|
|
8
|
+
'customer_service',
|
|
9
|
+
'local_dev',
|
|
10
|
+
'luxe_concierge',
|
|
11
|
+
'openai_compatible',
|
|
12
|
+
'project_manager'
|
|
13
|
+
];
|
|
3
14
|
const getTemplatesDir = () => {
|
|
4
15
|
const currentDir = process.cwd();
|
|
5
16
|
const cliDir = path.resolve(currentDir);
|
|
6
17
|
const templatesDir = path.join(cliDir, 'templates');
|
|
7
|
-
if (
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
|
|
18
|
+
if (fs.existsSync(templatesDir)) {
|
|
19
|
+
const configFiles = fs.readdirSync(templatesDir, { withFileTypes: true })
|
|
20
|
+
.filter(dirent => dirent.isDirectory())
|
|
21
|
+
.some(dirent => fs.existsSync(path.join(templatesDir, dirent.name, 'config.json')));
|
|
22
|
+
if (configFiles) {
|
|
23
|
+
return templatesDir;
|
|
11
24
|
}
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
25
|
+
}
|
|
26
|
+
const altTemplatesDir = path.join(path.dirname(cliDir), 'cli', 'templates');
|
|
27
|
+
if (fs.existsSync(altTemplatesDir)) {
|
|
28
|
+
const configFiles = fs.readdirSync(altTemplatesDir, { withFileTypes: true })
|
|
29
|
+
.filter(dirent => dirent.isDirectory())
|
|
30
|
+
.some(dirent => fs.existsSync(path.join(altTemplatesDir, dirent.name, 'config.json')));
|
|
31
|
+
if (configFiles) {
|
|
32
|
+
return altTemplatesDir;
|
|
15
33
|
}
|
|
16
34
|
}
|
|
17
|
-
return
|
|
35
|
+
return null;
|
|
18
36
|
};
|
|
19
|
-
|
|
37
|
+
const loadLocalTemplates = () => {
|
|
20
38
|
const templates = [];
|
|
21
39
|
const templatesDir = getTemplatesDir();
|
|
22
|
-
if (!fs.existsSync(templatesDir)) {
|
|
40
|
+
if (!templatesDir || !fs.existsSync(templatesDir)) {
|
|
23
41
|
return templates;
|
|
24
42
|
}
|
|
25
43
|
const dirs = fs.readdirSync(templatesDir, { withFileTypes: true })
|
|
@@ -38,24 +56,65 @@ export const listTemplates = () => {
|
|
|
38
56
|
...config,
|
|
39
57
|
name: config.name || dir,
|
|
40
58
|
description: config.description || `Template: ${dir}`
|
|
41
|
-
}
|
|
59
|
+
},
|
|
60
|
+
isRemote: false
|
|
42
61
|
});
|
|
43
62
|
}
|
|
44
63
|
catch (error) {
|
|
45
|
-
console.error(`Error loading template ${dir}:`, error);
|
|
46
64
|
}
|
|
47
65
|
}
|
|
48
66
|
}
|
|
49
67
|
return templates;
|
|
50
68
|
};
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
69
|
+
const loadRemoteTemplate = async (templateName) => {
|
|
70
|
+
try {
|
|
71
|
+
const configUrl = `${GITHUB_BASE_URL}/${templateName}/config.json`;
|
|
72
|
+
const response = await axios.get(configUrl, { timeout: 5000 });
|
|
73
|
+
const config = response.data;
|
|
74
|
+
return {
|
|
75
|
+
name: templateName,
|
|
76
|
+
path: `${GITHUB_BASE_URL}/${templateName}`,
|
|
77
|
+
config: {
|
|
78
|
+
...config,
|
|
79
|
+
name: config.name || templateName,
|
|
80
|
+
description: config.description || `Template: ${templateName}`
|
|
81
|
+
},
|
|
82
|
+
isRemote: true
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
catch (error) {
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
export const listTemplates = async () => {
|
|
90
|
+
const localTemplates = loadLocalTemplates();
|
|
91
|
+
if (localTemplates.length > 0) {
|
|
92
|
+
return localTemplates;
|
|
93
|
+
}
|
|
94
|
+
const remoteTemplates = [];
|
|
95
|
+
for (const templateName of REMOTE_TEMPLATES) {
|
|
96
|
+
const template = await loadRemoteTemplate(templateName);
|
|
97
|
+
if (template) {
|
|
98
|
+
remoteTemplates.push(template);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return remoteTemplates;
|
|
102
|
+
};
|
|
103
|
+
export const loadTemplate = async (templateName) => {
|
|
104
|
+
const localTemplates = loadLocalTemplates();
|
|
105
|
+
const localTemplate = localTemplates.find(t => t.name.toLowerCase() === templateName.toLowerCase() ||
|
|
54
106
|
t.config.name?.toLowerCase() === templateName.toLowerCase());
|
|
55
|
-
|
|
107
|
+
if (localTemplate) {
|
|
108
|
+
return localTemplate;
|
|
109
|
+
}
|
|
110
|
+
return await loadRemoteTemplate(templateName);
|
|
56
111
|
};
|
|
57
|
-
export const getTemplateOptions = (template) => {
|
|
112
|
+
export const getTemplateOptions = async (template) => {
|
|
58
113
|
const config = template.config;
|
|
114
|
+
let templatePath = template.path;
|
|
115
|
+
if (template.isRemote) {
|
|
116
|
+
templatePath = `${template.path}`;
|
|
117
|
+
}
|
|
59
118
|
return {
|
|
60
119
|
agentEndpoint: config.endpoint_url,
|
|
61
120
|
knowledgeSource: config.knowledge_source || 'files',
|
|
@@ -66,6 +125,17 @@ export const getTemplateOptions = (template) => {
|
|
|
66
125
|
bodyTemplate: config.body_template,
|
|
67
126
|
responseField: config.response_field,
|
|
68
127
|
nonInteractive: true,
|
|
69
|
-
templatePath
|
|
128
|
+
templatePath,
|
|
129
|
+
isRemoteTemplate: template.isRemote
|
|
70
130
|
};
|
|
71
131
|
};
|
|
132
|
+
export const loadRemoteQAndA = async (templateName) => {
|
|
133
|
+
try {
|
|
134
|
+
const qandaUrl = `${GITHUB_BASE_URL}/${templateName}/qanda.json`;
|
|
135
|
+
const response = await axios.get(qandaUrl, { timeout: 5000 });
|
|
136
|
+
return response.data;
|
|
137
|
+
}
|
|
138
|
+
catch (error) {
|
|
139
|
+
return null;
|
|
140
|
+
}
|
|
141
|
+
};
|
package/package.json
CHANGED
package/src/App.tsx
CHANGED
|
@@ -58,6 +58,7 @@ interface AppProps {
|
|
|
58
58
|
customBodyTemplate?: string;
|
|
59
59
|
customResponseField?: string;
|
|
60
60
|
templatePath?: string;
|
|
61
|
+
isRemoteTemplate?: boolean;
|
|
61
62
|
}
|
|
62
63
|
|
|
63
64
|
export const App: React.FC<AppProps> = ({
|
|
@@ -73,7 +74,8 @@ export const App: React.FC<AppProps> = ({
|
|
|
73
74
|
customHeaders,
|
|
74
75
|
customBodyTemplate,
|
|
75
76
|
customResponseField,
|
|
76
|
-
templatePath
|
|
77
|
+
templatePath,
|
|
78
|
+
isRemoteTemplate
|
|
77
79
|
}) => {
|
|
78
80
|
const { exit } = useApp();
|
|
79
81
|
const initialStep = nonInteractive && initialAgentEndpoint ? 'testing-connection' : 'agent-endpoint';
|
|
@@ -368,24 +370,78 @@ export const App: React.FC<AppProps> = ({
|
|
|
368
370
|
|
|
369
371
|
setEvaluationProgress(30);
|
|
370
372
|
|
|
373
|
+
if (knowledgeSource === 'files') {
|
|
374
|
+
let knowledgeData: any = null;
|
|
375
|
+
if (templatePath) {
|
|
376
|
+
try {
|
|
377
|
+
if (isRemoteTemplate) {
|
|
378
|
+
const axios = await import('axios');
|
|
379
|
+
const qandaUrl = `${templatePath}/qanda.json`;
|
|
380
|
+
const response = await axios.default.get(qandaUrl, { timeout: 5000 });
|
|
381
|
+
knowledgeData = response.data;
|
|
382
|
+
} else {
|
|
383
|
+
const fs = await import('fs');
|
|
384
|
+
const path = await import('path');
|
|
385
|
+
const qandaPath = path.join(templatePath, 'qanda.json');
|
|
386
|
+
if (fs.existsSync(qandaPath)) {
|
|
387
|
+
knowledgeData = JSON.parse(fs.readFileSync(qandaPath, 'utf-8'));
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
} catch (error) {
|
|
391
|
+
logger.debug('Error loading knowledge from template:', error);
|
|
392
|
+
}
|
|
393
|
+
} else {
|
|
394
|
+
const knowledgeResult = await api.checkKnowledge();
|
|
395
|
+
if (knowledgeResult.found && knowledgeResult.path) {
|
|
396
|
+
try {
|
|
397
|
+
const fs = await import('fs');
|
|
398
|
+
knowledgeData = JSON.parse(fs.readFileSync(knowledgeResult.path, 'utf-8'));
|
|
399
|
+
} catch (error) {
|
|
400
|
+
logger.debug('Error loading knowledge:', error);
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
if (knowledgeData) {
|
|
406
|
+
setEvaluationProgress(35);
|
|
407
|
+
try {
|
|
408
|
+
const importResult = await api.importKnowledge(agentId, knowledgeData);
|
|
409
|
+
logger.debug('Knowledge import result:', importResult);
|
|
410
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
411
|
+
} catch (error: any) {
|
|
412
|
+
logger.error('Failed to import knowledge:', error?.message || error);
|
|
413
|
+
logger.debug('Import error details:', error?.response?.data);
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
|
|
371
418
|
setEvaluationProgress(40);
|
|
372
419
|
let testPrompts: Array<{question: string, answer?: string}> | string[] = [];
|
|
373
420
|
if (knowledgeSource === 'files') {
|
|
374
421
|
if (templatePath) {
|
|
375
422
|
try {
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
const
|
|
381
|
-
|
|
382
|
-
testPrompts = knowledgeData.map((item: any) => ({
|
|
383
|
-
question: item.question || item.prompt || item.input || 'Test question',
|
|
384
|
-
answer: item.answer || item.response || item.expectedAnswer
|
|
385
|
-
}));
|
|
386
|
-
}
|
|
423
|
+
let knowledgeData: any = null;
|
|
424
|
+
if (isRemoteTemplate) {
|
|
425
|
+
const axios = await import('axios');
|
|
426
|
+
const qandaUrl = `${templatePath}/qanda.json`;
|
|
427
|
+
const response = await axios.default.get(qandaUrl, { timeout: 5000 });
|
|
428
|
+
knowledgeData = response.data;
|
|
387
429
|
} else {
|
|
388
|
-
|
|
430
|
+
const fs = await import('fs');
|
|
431
|
+
const path = await import('path');
|
|
432
|
+
const qandaPath = path.join(templatePath, 'qanda.json');
|
|
433
|
+
if (fs.existsSync(qandaPath)) {
|
|
434
|
+
knowledgeData = JSON.parse(fs.readFileSync(qandaPath, 'utf-8'));
|
|
435
|
+
} else {
|
|
436
|
+
logger.debug('No qanda.json found in template directory:', templatePath);
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
if (knowledgeData && Array.isArray(knowledgeData)) {
|
|
441
|
+
testPrompts = knowledgeData.map((item: any) => ({
|
|
442
|
+
question: item.question || item.prompt || item.input || 'Test question',
|
|
443
|
+
answer: item.answer || item.response || item.expectedAnswer
|
|
444
|
+
}));
|
|
389
445
|
}
|
|
390
446
|
} catch (error) {
|
|
391
447
|
logger.debug('Error loading prompts from template:', error);
|
package/src/api/knowledge.ts
CHANGED
|
@@ -48,14 +48,49 @@ export async function checkKnowledge(folderPath: string = '.') {
|
|
|
48
48
|
|
|
49
49
|
export async function importKnowledge(agentId: string, knowledgeData: any) {
|
|
50
50
|
try {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
51
|
+
logger.debug('Importing knowledge for agent:', agentId);
|
|
52
|
+
logger.debug('Knowledge data type:', Array.isArray(knowledgeData) ? 'array' : typeof knowledgeData);
|
|
53
|
+
logger.debug('Knowledge data length:', Array.isArray(knowledgeData) ? knowledgeData.length : 'N/A');
|
|
54
54
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
55
|
+
if (!Array.isArray(knowledgeData)) {
|
|
56
|
+
logger.warn('Knowledge data is not an array, skipping import');
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
let importedCount = 0;
|
|
61
|
+
for (const item of knowledgeData) {
|
|
62
|
+
try {
|
|
63
|
+
const question = item.question || item.prompt || item.input;
|
|
64
|
+
const answer = item.answer || item.response || item.expectedAnswer;
|
|
65
|
+
|
|
66
|
+
if (!question || !answer) {
|
|
67
|
+
logger.debug('Skipping item without question or answer:', item);
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const response = await client.post(`/api/agents/${agentId}/config`, {
|
|
72
|
+
label: question,
|
|
73
|
+
description: answer,
|
|
74
|
+
type: 'knowledge'
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
importedCount++;
|
|
78
|
+
logger.debug(`Imported Q&A ${importedCount}/${knowledgeData.length}: ${question.substring(0, 50)}...`);
|
|
79
|
+
} catch (error: any) {
|
|
80
|
+
logger.warn(`Failed to import Q&A pair: ${error?.message || error}`);
|
|
81
|
+
logger.debug('Q&A import error details:', error?.response?.data);
|
|
82
|
+
logger.debug('Q&A import error status:', error?.response?.status);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
logger.info(`Knowledge imported successfully: ${importedCount}/${knowledgeData.length} Q&A pairs`);
|
|
87
|
+
|
|
88
|
+
return { imported: importedCount, total: knowledgeData.length };
|
|
89
|
+
} catch (error: any) {
|
|
90
|
+
logger.error('Error importing knowledge:', error?.message || error);
|
|
91
|
+
logger.debug('Error details:', error?.response?.data);
|
|
92
|
+
logger.debug('Error status:', error?.response?.status);
|
|
93
|
+
throw error;
|
|
59
94
|
}
|
|
60
95
|
}
|
|
61
96
|
|
package/src/index.tsx
CHANGED
|
@@ -7,14 +7,14 @@ import { ValidationError } from './errors/types.js';
|
|
|
7
7
|
import { listTemplates, loadTemplate, getTemplateOptions } from './utils/templates.js';
|
|
8
8
|
import { analytics } from './utils/analytics.js';
|
|
9
9
|
|
|
10
|
-
const parseArgs = () => {
|
|
10
|
+
const parseArgs = async () => {
|
|
11
11
|
const args = process.argv.slice(2);
|
|
12
12
|
|
|
13
13
|
if (args[0] === 'list-templates' || args[0] === 'templates') {
|
|
14
|
-
const templates = listTemplates();
|
|
14
|
+
const templates = await listTemplates();
|
|
15
15
|
console.log('\nAvailable Templates:\n');
|
|
16
16
|
if (templates.length === 0) {
|
|
17
|
-
console.log('No templates found
|
|
17
|
+
console.log('No templates found');
|
|
18
18
|
} else {
|
|
19
19
|
templates.forEach(template => {
|
|
20
20
|
console.log(` ${template.name}`);
|
|
@@ -40,15 +40,15 @@ const parseArgs = () => {
|
|
|
40
40
|
|
|
41
41
|
for (let i = 0; i < args.length; i++) {
|
|
42
42
|
if ((args[i] === '--template' || args[i] === '-t') && args[i + 1]) {
|
|
43
|
-
const template = loadTemplate(args[i + 1]);
|
|
43
|
+
const template = await loadTemplate(args[i + 1]);
|
|
44
44
|
if (!template) {
|
|
45
45
|
console.error(`Template '${args[i + 1]}' not found.`);
|
|
46
46
|
console.log('\nAvailable templates:');
|
|
47
|
-
const templates = listTemplates();
|
|
47
|
+
const templates = await listTemplates();
|
|
48
48
|
templates.forEach(t => console.log(` - ${t.name}`));
|
|
49
49
|
process.exit(1);
|
|
50
50
|
}
|
|
51
|
-
const templateOptions = getTemplateOptions(template);
|
|
51
|
+
const templateOptions = await getTemplateOptions(template);
|
|
52
52
|
Object.assign(options, templateOptions);
|
|
53
53
|
i++;
|
|
54
54
|
} else if ((args[i] === '--backend-url' || args[i] === '-b') && args[i + 1]) {
|
|
@@ -177,7 +177,7 @@ Examples:
|
|
|
177
177
|
|
|
178
178
|
async function run() {
|
|
179
179
|
try {
|
|
180
|
-
const options = parseArgs();
|
|
180
|
+
const options = await parseArgs();
|
|
181
181
|
|
|
182
182
|
const fs = await import('fs');
|
|
183
183
|
const path = await import('path');
|
|
@@ -218,6 +218,7 @@ async function run() {
|
|
|
218
218
|
customBodyTemplate={options.bodyTemplate}
|
|
219
219
|
customResponseField={options.responseField}
|
|
220
220
|
templatePath={options.templatePath}
|
|
221
|
+
isRemoteTemplate={options.isRemoteTemplate}
|
|
221
222
|
pdfPath={options.pdfPath}
|
|
222
223
|
/>
|
|
223
224
|
);
|
package/src/utils/templates.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import * as fs from 'fs';
|
|
2
2
|
import * as path from 'path';
|
|
3
|
+
import { fileURLToPath } from 'url';
|
|
4
|
+
import axios from 'axios';
|
|
3
5
|
|
|
4
6
|
export interface TemplateConfig {
|
|
5
7
|
endpoint_url: string;
|
|
@@ -19,33 +21,53 @@ export interface Template {
|
|
|
19
21
|
name: string;
|
|
20
22
|
path: string;
|
|
21
23
|
config: TemplateConfig;
|
|
24
|
+
isRemote?: boolean;
|
|
22
25
|
}
|
|
23
26
|
|
|
24
|
-
const
|
|
27
|
+
const GITHUB_BASE_URL = 'https://raw.githubusercontent.com/rippletideco/starter/refs/heads/main/cli/templates';
|
|
28
|
+
|
|
29
|
+
const REMOTE_TEMPLATES = [
|
|
30
|
+
'banking_analyst',
|
|
31
|
+
'blog_to_linkedin',
|
|
32
|
+
'customer_service',
|
|
33
|
+
'local_dev',
|
|
34
|
+
'luxe_concierge',
|
|
35
|
+
'openai_compatible',
|
|
36
|
+
'project_manager'
|
|
37
|
+
];
|
|
38
|
+
|
|
39
|
+
const getTemplatesDir = (): string | null => {
|
|
25
40
|
const currentDir = process.cwd();
|
|
26
41
|
const cliDir = path.resolve(currentDir);
|
|
27
42
|
const templatesDir = path.join(cliDir, 'templates');
|
|
28
43
|
|
|
29
|
-
if (
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
|
|
44
|
+
if (fs.existsSync(templatesDir)) {
|
|
45
|
+
const configFiles = fs.readdirSync(templatesDir, { withFileTypes: true })
|
|
46
|
+
.filter(dirent => dirent.isDirectory())
|
|
47
|
+
.some(dirent => fs.existsSync(path.join(templatesDir, dirent.name, 'config.json')));
|
|
48
|
+
if (configFiles) {
|
|
49
|
+
return templatesDir;
|
|
33
50
|
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const altTemplatesDir = path.join(path.dirname(cliDir), 'cli', 'templates');
|
|
54
|
+
if (fs.existsSync(altTemplatesDir)) {
|
|
55
|
+
const configFiles = fs.readdirSync(altTemplatesDir, { withFileTypes: true })
|
|
56
|
+
.filter(dirent => dirent.isDirectory())
|
|
57
|
+
.some(dirent => fs.existsSync(path.join(altTemplatesDir, dirent.name, 'config.json')));
|
|
58
|
+
if (configFiles) {
|
|
59
|
+
return altTemplatesDir;
|
|
38
60
|
}
|
|
39
61
|
}
|
|
40
62
|
|
|
41
|
-
return
|
|
63
|
+
return null;
|
|
42
64
|
};
|
|
43
65
|
|
|
44
|
-
|
|
66
|
+
const loadLocalTemplates = (): Template[] => {
|
|
45
67
|
const templates: Template[] = [];
|
|
46
68
|
const templatesDir = getTemplatesDir();
|
|
47
69
|
|
|
48
|
-
if (!fs.existsSync(templatesDir)) {
|
|
70
|
+
if (!templatesDir || !fs.existsSync(templatesDir)) {
|
|
49
71
|
return templates;
|
|
50
72
|
}
|
|
51
73
|
|
|
@@ -66,10 +88,10 @@ export const listTemplates = (): Template[] => {
|
|
|
66
88
|
...config,
|
|
67
89
|
name: config.name || dir,
|
|
68
90
|
description: config.description || `Template: ${dir}`
|
|
69
|
-
}
|
|
91
|
+
},
|
|
92
|
+
isRemote: false
|
|
70
93
|
});
|
|
71
94
|
} catch (error) {
|
|
72
|
-
console.error(`Error loading template ${dir}:`, error);
|
|
73
95
|
}
|
|
74
96
|
}
|
|
75
97
|
}
|
|
@@ -77,18 +99,67 @@ export const listTemplates = (): Template[] => {
|
|
|
77
99
|
return templates;
|
|
78
100
|
};
|
|
79
101
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
102
|
+
const loadRemoteTemplate = async (templateName: string): Promise<Template | null> => {
|
|
103
|
+
try {
|
|
104
|
+
const configUrl = `${GITHUB_BASE_URL}/${templateName}/config.json`;
|
|
105
|
+
const response = await axios.get(configUrl, { timeout: 5000 });
|
|
106
|
+
const config = response.data as TemplateConfig;
|
|
107
|
+
|
|
108
|
+
return {
|
|
109
|
+
name: templateName,
|
|
110
|
+
path: `${GITHUB_BASE_URL}/${templateName}`,
|
|
111
|
+
config: {
|
|
112
|
+
...config,
|
|
113
|
+
name: config.name || templateName,
|
|
114
|
+
description: config.description || `Template: ${templateName}`
|
|
115
|
+
},
|
|
116
|
+
isRemote: true
|
|
117
|
+
};
|
|
118
|
+
} catch (error) {
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
export const listTemplates = async (): Promise<Template[]> => {
|
|
124
|
+
const localTemplates = loadLocalTemplates();
|
|
125
|
+
|
|
126
|
+
if (localTemplates.length > 0) {
|
|
127
|
+
return localTemplates;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const remoteTemplates: Template[] = [];
|
|
131
|
+
for (const templateName of REMOTE_TEMPLATES) {
|
|
132
|
+
const template = await loadRemoteTemplate(templateName);
|
|
133
|
+
if (template) {
|
|
134
|
+
remoteTemplates.push(template);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return remoteTemplates;
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
export const loadTemplate = async (templateName: string): Promise<Template | null> => {
|
|
142
|
+
const localTemplates = loadLocalTemplates();
|
|
143
|
+
const localTemplate = localTemplates.find(t =>
|
|
83
144
|
t.name.toLowerCase() === templateName.toLowerCase() ||
|
|
84
145
|
t.config.name?.toLowerCase() === templateName.toLowerCase()
|
|
85
146
|
);
|
|
86
147
|
|
|
87
|
-
|
|
148
|
+
if (localTemplate) {
|
|
149
|
+
return localTemplate;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
return await loadRemoteTemplate(templateName);
|
|
88
153
|
};
|
|
89
154
|
|
|
90
|
-
export const getTemplateOptions = (template: Template): any => {
|
|
155
|
+
export const getTemplateOptions = async (template: Template): Promise<any> => {
|
|
91
156
|
const config = template.config;
|
|
157
|
+
|
|
158
|
+
let templatePath = template.path;
|
|
159
|
+
if (template.isRemote) {
|
|
160
|
+
templatePath = `${template.path}`;
|
|
161
|
+
}
|
|
162
|
+
|
|
92
163
|
return {
|
|
93
164
|
agentEndpoint: config.endpoint_url,
|
|
94
165
|
knowledgeSource: config.knowledge_source || 'files',
|
|
@@ -99,6 +170,17 @@ export const getTemplateOptions = (template: Template): any => {
|
|
|
99
170
|
bodyTemplate: config.body_template,
|
|
100
171
|
responseField: config.response_field,
|
|
101
172
|
nonInteractive: true,
|
|
102
|
-
templatePath
|
|
173
|
+
templatePath,
|
|
174
|
+
isRemoteTemplate: template.isRemote
|
|
103
175
|
};
|
|
104
176
|
};
|
|
177
|
+
|
|
178
|
+
export const loadRemoteQAndA = async (templateName: string): Promise<any> => {
|
|
179
|
+
try {
|
|
180
|
+
const qandaUrl = `${GITHUB_BASE_URL}/${templateName}/qanda.json`;
|
|
181
|
+
const response = await axios.get(qandaUrl, { timeout: 5000 });
|
|
182
|
+
return response.data;
|
|
183
|
+
} catch (error) {
|
|
184
|
+
return null;
|
|
185
|
+
}
|
|
186
|
+
};
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
},
|
|
42
42
|
{
|
|
43
43
|
"question": "What shopping outputs can you produce?",
|
|
44
|
-
"answer": "Shortlist, "best overall / best value / best statement
|
|
44
|
+
"answer": "Shortlist, \"best overall / best value / best statement,\" sizing guide, care guide, authenticity checklist, buying plan by budget."
|
|
45
45
|
},
|
|
46
46
|
{
|
|
47
47
|
"question": "How do you handle gifts?",
|