diff --git a/packages/agent/src/index.ts b/packages/agent/src/index.ts index d930e560f..2268363ba 100644 --- a/packages/agent/src/index.ts +++ b/packages/agent/src/index.ts @@ -39,3 +39,5 @@ export * from './shared/lib/token/index.js'; // Token tracking (if index.ts exis // Legacy exports for backward compatibility export type { IAgent } from './shared/types/agents.types.js'; + +export type { AgentConfigSQL } from './agents/studio/studio-graph.js'; diff --git a/packages/core/package.json b/packages/core/package.json index 0cf806780..28335fbe7 100755 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -35,7 +35,7 @@ "@langchain/core": "^0.3.72", "@langchain/community": "^0.3.34", "@types/pg": "^8.11.11", - "file-type": "^19.0.0", + "file-type": "^16.5.4", "pg": "^8.13.3", "prom-client": "^15.1.3", "winston": "^3.17.0", diff --git a/packages/core/src/services/file-validation.service.ts b/packages/core/src/services/file-validation.service.ts index e972cc6cc..ab545bbdb 100644 --- a/packages/core/src/services/file-validation.service.ts +++ b/packages/core/src/services/file-validation.service.ts @@ -1,4 +1,4 @@ -import { fileTypeFromBuffer } from 'file-type'; +import { fromBuffer } from 'file-type'; import logger from '../logger/logger.js'; export type SupportedMimeType = @@ -60,7 +60,7 @@ export class FileValidationService { declaredMimeType?: string ): Promise { try { - const detected = await fileTypeFromBuffer(buffer); + const detected = await fromBuffer(buffer); const detectedMimeType = detected?.mime; logger.debug( diff --git a/packages/database/initdb/03-agents.sql b/packages/database/initdb/03-agents.sql index 87ebb5cfb..916ed0d2e 100644 --- a/packages/database/initdb/03-agents.sql +++ b/packages/database/initdb/03-agents.sql @@ -14,8 +14,8 @@ CREATE TABLE IF NOT EXISTS agents ( -- Human-readable name for the agent -- Used in UI displays and logging - -- Must be unique within a group for clarity - name VARCHAR(255) NOT NULL, + -- Must be unique across the entire system for clarity + name VARCHAR(255) NOT NULL UNIQUE, -- Reference to the user who owns this agent -- Foreign key linking to the user who created and manages this agent diff --git a/packages/server/common/cleanup/cleanup.module.ts b/packages/server/common/cleanup/cleanup.module.ts index 984ddebbb..943190c01 100644 --- a/packages/server/common/cleanup/cleanup.module.ts +++ b/packages/server/common/cleanup/cleanup.module.ts @@ -3,7 +3,7 @@ import { ScheduleModule } from '@nestjs/schedule'; import { CleanupService } from './cleanup.service.js'; @Module({ - imports: [ScheduleModule.forRoot()], + imports: [ScheduleModule], providers: [CleanupService], exports: [CleanupService], }) diff --git a/packages/server/package.json b/packages/server/package.json index 20ce13518..847e1d5e2 100755 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -53,6 +53,7 @@ }, "devDependencies": { "@types/pg": "^8.11.0", - "typescript": "^5.7.3" + "typescript": "^5.7.3", + "tsx": "^4.20.4" } } diff --git a/packages/server/src/agents.storage.ts b/packages/server/src/agents.storage.ts index 4dec56eb3..5bc598511 100644 --- a/packages/server/src/agents.storage.ts +++ b/packages/server/src/agents.storage.ts @@ -234,23 +234,28 @@ export class AgentStorage implements OnModuleInit { rag: this.parseRagConfig(q_res[0].rag), }; this.agentConfigs.push(newAgentDbRecord); - this.createSnakAgentFromConfig(newAgentDbRecord) - .then((snakAgent) => { - const compositeKey = `${newAgentDbRecord.id}|${newAgentDbRecord.user_id}`; - this.agentInstances.set(compositeKey, snakAgent); - this.agentSelector.updateAvailableAgents( - [newAgentDbRecord.id, snakAgent], - newAgentDbRecord.user_id - ); - }) - .catch((error) => { - logger.error( - `Failed to create SnakAgent for new agent ${newAgentDbRecord.id}: ${error}` - ); - throw error; - }); - logger.debug(`Agent ${newAgentDbRecord.id} added to configuration`); - return newAgentDbRecord; + try { + const snakAgent = + await this.createSnakAgentFromConfig(newAgentDbRecord); + const compositeKey = `${newAgentDbRecord.id}|${newAgentDbRecord.user_id}`; + this.agentInstances.set(compositeKey, snakAgent); + this.agentSelector.updateAvailableAgents( + [newAgentDbRecord.id, snakAgent], + newAgentDbRecord.user_id + ); + logger.debug( + `Agent ${newAgentDbRecord.id} added to configuration and instance created` + ); + return newAgentDbRecord; + } catch (error) { + logger.error( + `Failed to create SnakAgent for new agent ${newAgentDbRecord.id}: ${error}` + ); + this.agentConfigs = this.agentConfigs.filter( + (config) => config.id !== newAgentDbRecord.id + ); + throw error; + } } else { logger.error('Failed to add agent to database, no record returned.'); throw new Error('Failed to add agent to database.'); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6de8f7c10..0498fe9ec 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -305,8 +305,8 @@ importers: specifier: ^8.11.11 version: 8.15.5 file-type: - specifier: ^19.0.0 - version: 19.6.0 + specifier: ^16.5.4 + version: 16.5.4 pg: specifier: ^8.13.3 version: 8.16.3 @@ -429,6 +429,9 @@ importers: '@types/pg': specifier: ^8.11.0 version: 8.15.5 + tsx: + specifier: ^4.20.4 + version: 4.20.4 typescript: specifier: ^5.7.3 version: 5.9.2 @@ -2808,9 +2811,6 @@ packages: '@scure/starknet@1.1.0': resolution: {integrity: sha512-83g3M6Ix2qRsPN4wqLDqiRZ2GBNbjVWfboJE/9UjfG+MHr6oDSu/CWgy8hsBSJejr09DkkL+l0Ze4KVrlCIdtQ==} - '@sec-ant/readable-stream@0.4.1': - resolution: {integrity: sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==} - '@sideway/address@4.1.5': resolution: {integrity: sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q==} @@ -4512,10 +4512,6 @@ packages: resolution: {integrity: sha512-/yFHK0aGjFEgDJjEKP0pWCplsPFPhwyfwevf/pVxiN0tmE4L9LmwWxWukdJSHdoCli4VgQLehjJtwQBnqmsKcw==} engines: {node: '>=10'} - file-type@19.6.0: - resolution: {integrity: sha512-VZR5I7k5wkD0HgFnMsq5hOsSc710MJMu5Nc5QYsbe38NN5iPV/XTObYLc/cpttRTf6lX538+5uO1ZQRhYibiZQ==} - engines: {node: '>=18'} - file-type@20.4.1: resolution: {integrity: sha512-hw9gNZXUfZ02Jo0uafWLaFVPter5/k2rfcrjFJJHX/77xtSDOfJuEFb6oKlFV86FLP1SuyHMW1PSk0U9M5tKkQ==} engines: {node: '>=18'} @@ -4708,10 +4704,6 @@ packages: resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} engines: {node: '>=10'} - get-stream@9.0.1: - resolution: {integrity: sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==} - engines: {node: '>=18'} - get-tsconfig@4.10.1: resolution: {integrity: sha512-auHyJ4AgMz7vgS8Hp3N6HXSmlMdUyhSUrfBF16w153rxtLIEOE+HGqaBppczZvnHLqQJfiHotCYpNhl0lUROFQ==} @@ -5103,10 +5095,6 @@ packages: resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} engines: {node: '>=8'} - is-stream@4.0.1: - resolution: {integrity: sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==} - engines: {node: '>=18'} - is-text-path@1.0.1: resolution: {integrity: sha512-xFuJpne9oFz5qDaodwmmG08e3CawH/2ZV8Qqza1Ko7Sk8POWbkRdwIoAWVhqvq0XeUzANEhKo2n0IXUGBm7A/w==} engines: {node: '>=0.10.0'} @@ -6396,10 +6384,6 @@ packages: resolution: {integrity: sha512-ZI3LnwUv5nOGbQzD9c2iDG6toheuXSZP5esSHBjopsXH4dg19soufvpUGA3uohi5anFtGb2lhAVdHzH6R/Evvg==} engines: {node: '>=8'} - peek-readable@5.4.2: - resolution: {integrity: sha512-peBp3qZyuS6cNIJ2akRNG1uo1WJ1d0wTxg/fxMdZ0BqCVhx242bSFHM9eNqflfJVS9SsgkzgT/1UgnsurBOTMg==} - engines: {node: '>=14.16'} - pg-cloudflare@1.2.7: resolution: {integrity: sha512-YgCtzMH0ptvZJslLM1ffsY4EuGaU0cx4XSdXLRFae8bPP4dS5xL1tNB3k2o/N64cHJpwU7dxKli/nZ2lUa5fLg==} @@ -7260,10 +7244,6 @@ packages: resolution: {integrity: sha512-fZtbhtvI9I48xDSywd/somNqgUHl2L2cstmXCCif0itOf96jeW18MBSyrLuNicYQVkvpOxkZtkzujiTJ9LW5Jw==} engines: {node: '>=10'} - strtok3@9.1.1: - resolution: {integrity: sha512-FhwotcEqjr241ZbjFzjlIYg6c5/L/s4yBGWSMvJ9UoExiSqL+FnFA/CaeZx17WGaZMS/4SOZp8wH18jSS4R4lw==} - engines: {node: '>=16'} - sucrase@3.35.0: resolution: {integrity: sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==} engines: {node: '>=16 || 14 >=14.17'} @@ -10129,8 +10109,6 @@ snapshots: '@noble/curves': 1.7.0 '@noble/hashes': 1.6.0 - '@sec-ant/readable-stream@0.4.1': {} - '@sideway/address@4.1.5': dependencies: '@hapi/hoek': 9.3.0 @@ -11002,7 +10980,7 @@ snapshots: buffer@4.9.2: dependencies: base64-js: 1.5.1 - ieee754: 1.1.13 + ieee754: 1.2.1 isarray: 1.0.0 buffer@5.7.1: @@ -12118,13 +12096,6 @@ snapshots: strtok3: 6.3.0 token-types: 4.2.1 - file-type@19.6.0: - dependencies: - get-stream: 9.0.1 - strtok3: 9.1.1 - token-types: 6.1.1 - uint8array-extras: 1.4.1 - file-type@20.4.1: dependencies: '@tokenizer/inflate': 0.2.7 @@ -12347,11 +12318,6 @@ snapshots: get-stream@6.0.1: {} - get-stream@9.0.1: - dependencies: - '@sec-ant/readable-stream': 0.4.1 - is-stream: 4.0.1 - get-tsconfig@4.10.1: dependencies: resolve-pkg-maps: 1.0.0 @@ -12804,8 +12770,6 @@ snapshots: is-stream@2.0.1: {} - is-stream@4.0.1: {} - is-text-path@1.0.1: dependencies: text-extensions: 1.9.0 @@ -14456,8 +14420,6 @@ snapshots: peek-readable@4.1.0: {} - peek-readable@5.4.2: {} - pg-cloudflare@1.2.7: optional: true @@ -15438,11 +15400,6 @@ snapshots: '@tokenizer/token': 0.3.0 peek-readable: 4.1.0 - strtok3@9.1.1: - dependencies: - '@tokenizer/token': 0.3.0 - peek-readable: 5.4.2 - sucrase@3.35.0: dependencies: '@jridgewell/gen-mapping': 0.3.13 diff --git a/tests/package.json b/tests/package.json index 67c44ab4d..98228674d 100644 --- a/tests/package.json +++ b/tests/package.json @@ -9,10 +9,8 @@ "dev": "tsx src/index.ts", "test": "tsx src/main.ts", "demo": "tsx src/demo.ts", - "test:agents": "tsx src/test-agents.ts", - "test:files": "tsx src/test-files.ts", - "test:chat": "tsx src/test-chat.ts", - "test:file-stress": "tsx src/file-test/file-upload-stress-v2.ts", + "test:file-stress": "tsx src/stress-test/file-upload-stress.ts", + "test:agent-stress": "tsx src/stress-test/agent-stress.ts", "clean": "rm -rf dist" }, "dependencies": { @@ -20,12 +18,15 @@ "dotenv": "^16.4.7", "chalk": "^4.1.2", "ora": "^8.1.1", - "form-data": "^4.0.0" + "form-data": "^4.0.0", + "@snakagent/core": "workspace:*", + "@snakagent/server": "workspace:*", + "@snakagent/agents": "workspace:*" }, "devDependencies": { "@types/node": "^22.13.5", "tsup": "^8.4.0", - "tsx": "^4.19.3", + "tsx": "^4.20.4", "typescript": "^5.7.3" }, "engines": { diff --git a/tests/src/agents/cleanup.ts b/tests/src/agents/cleanup.ts new file mode 100644 index 000000000..fbe46a38f --- /dev/null +++ b/tests/src/agents/cleanup.ts @@ -0,0 +1,58 @@ +import chalk from "chalk"; +import { TestRunner } from "../test-runner"; + +export interface CleanupAgent { + testRunner: TestRunner; + agentId: string; + userId?: string; + agentName?: string; + } + + export interface CleanupResult { + success: boolean; + index?: number; + error?: string; + } + + export async function cleanupAgents( + agents: CleanupAgent[], + context: string = 'Cleanup' + ): Promise<{ successful: number; failed: number; results: CleanupResult[] }> { + if (agents.length === 0) { + console.log(chalk.blue(`\n${context}: No agents to cleanup`)); + return { successful: 0, failed: 0, results: [] }; + } + + console.log(chalk.blue(`\n${context}: Cleaning up ${agents.length} agents...`)); + + const cleanupPromises = agents.map(async (agent, index) => { + try { + const testName = `${context} - Delete Agent ${agent.agentId}`; + + await agent.testRunner.runTest(testName, () => + agent.testRunner.client.deleteAgent(agent.agentId) + ); + + return { success: true, index }; + } catch (error) { + const errorMessage = error instanceof Error ? error.message : 'Unknown error'; + console.log(chalk.red(` Error: Failed to cleanup agent ${index + 1}: ${errorMessage}`)); + return { success: false, index, error: errorMessage }; + } + }); + + const settledResults = await Promise.allSettled(cleanupPromises); + const results = settledResults.map((result, index) => { + if (result.status === 'fulfilled') { + return result.value; + } else { + return { success: false, index, error: result.reason?.message || 'Unknown error' }; + } + }); + const successful = results.filter(r => r.success).length; + const failed = results.filter(r => !r.success).length; + + console.log(chalk.green(` Success: ${context} completed: ${successful} successful, ${failed} failed`)); + + return { successful, failed, results }; + } \ No newline at end of file diff --git a/tests/src/agents/creation.ts b/tests/src/agents/creation.ts new file mode 100644 index 000000000..c306b8e51 --- /dev/null +++ b/tests/src/agents/creation.ts @@ -0,0 +1,77 @@ +import chalk from "chalk"; +import { TestRunner } from "../test-runner"; +import { defaultAgentConfiguration, extractAgentNameFromResponse } from "../helpers"; +import { CreateAgentResponse } from "../types"; +import { getAgentByName } from "./list.js"; +import { AgentConfigSQL } from "@snakagent/agents"; +import { AgentInitializationDTO } from "@snakagent/core"; + +async function waitForAgentCreation( + testRunner: TestRunner, + agentName: string, + maxWaitTime: number = 30000, + pollInterval: number = 100, + ): Promise<{ success: boolean; agentId?: string; agent?: AgentConfigSQL; error?: string }> { + const startTime = Date.now(); + + while (Date.now() - startTime < maxWaitTime) { + const result = await getAgentByName(testRunner.client, agentName); + if (result.success && result.agent) { + return { success: true, agentId: result.agent.id, agent: result.agent }; + } + + await new Promise(resolve => setTimeout(resolve, pollInterval)); + } + + return { success: false, error: 'Agent creation timeout' }; + } + +export async function createAgentWithTracking( + testRunner: TestRunner, + agentDefineName: string, + agentConfig?: AgentInitializationDTO + ): Promise<{ success: boolean; agentId?: string; agentName?: string; agent?: AgentConfigSQL; error?: string }> { + try { + let agentName = agentDefineName; + + const createResult = await testRunner.runTest( + `Create Agent ${agentName}`, + () => testRunner.client.createAgent({ + agent: agentConfig || defaultAgentConfiguration(agentName) + }) + ); + const createResponse = createResult.response as CreateAgentResponse; + if (!createResult.success || !createResponse.success) { + return { success: false, error: createResult.error }; + } + + const extractedAgentName = extractAgentNameFromResponse(createResponse); + if (extractedAgentName) { + console.log(chalk.green(` Success: Created agent "${extractedAgentName}"`)); + + if (extractedAgentName !== agentName) { + console.log(chalk.yellow(` Warning: Agent name mismatch! Expected: "${agentName}", Got: "${extractedAgentName}"`)); + agentName = extractedAgentName; + } else { + console.log(chalk.green(` ✓ Agent name verification passed: "${agentName}"`)); + } + } else { + console.log(chalk.yellow(` Warning: Could not extract agent name from response: ${createResult.response}`)); + } + + const waitResult = await waitForAgentCreation(testRunner, agentName, 30000); + + return { + success: waitResult.success, + agentId: waitResult.agentId, + agentName: extractedAgentName || agentName, + agent: waitResult.agent, + error: waitResult.error + }; + } catch (error) { + return { + success: false, + error: error instanceof Error ? error.message : 'Unknown error' + }; + } + } \ No newline at end of file diff --git a/tests/src/agents/list.ts b/tests/src/agents/list.ts new file mode 100644 index 000000000..001691875 --- /dev/null +++ b/tests/src/agents/list.ts @@ -0,0 +1,22 @@ +import chalk from "chalk"; +import { SnakClient } from "../snak-client-http"; +import { AgentConfigSQL } from "@snakagent/agents"; + + export async function getAgentByName( + client: SnakClient, + agentName: string + ): Promise<{ success: boolean; agent?: AgentConfigSQL }> { + try { + const agentResponse = await client.getAgents(); + + const foundAgent = agentResponse.data.find((agent: AgentConfigSQL) => agent.name === agentName); + return { + success: !!foundAgent, + agent: foundAgent + }; + } catch (error) { + console.log(chalk.yellow(`Warning: Error finding agent by name: ${error}`)); + return { success: false }; + } + } + diff --git a/tests/src/file-test/file-upload.ts b/tests/src/file-test/file-upload.ts deleted file mode 100644 index 7baf42ca4..000000000 --- a/tests/src/file-test/file-upload.ts +++ /dev/null @@ -1,185 +0,0 @@ -import { TestRunner } from '../test-runner.js'; -import { SnakConfig } from '../types.js'; -import chalk from 'chalk'; -import dotenv from 'dotenv'; - -dotenv.config(); -if (!process.env.SNAK_USER_ID || !process.env.SERVER_API_KEY) { - throw new Error('SNAK_USER_ID and SERVER_API_KEY must be set'); -} - -const port = process.env.SERVER_PORT || '3002'; -const config: SnakConfig = { - baseUrl: `http://localhost:${port}`, - userId: process.env.SNAK_USER_ID, - apiKey: process.env.SERVER_API_KEY, -}; - -async function testFiles() { - console.log(chalk.blue.bold('Testing File Upload Endpoints\n')); - - const testRunner = new TestRunner(config); - - await testRunner.runTest('Health Check', () => testRunner.client.healthCheck()); - - const createResult = await testRunner.runTest('Create Agent for File Testing', () => - testRunner.client.createAgent({ - agent: { - name: 'File Test Agent', - group: 'test', - description: 'Agent for testing file upload functionality', - lore: [ - 'I am a specialized test agent created to validate file upload and processing functionality.', - 'My purpose is to ensure that the file ingestion system works correctly.', - 'I help test various file formats and processing capabilities.' - ], - objectives: [ - 'Test file upload via multipart form data', - 'Validate text chunking and processing', - 'Test metadata extraction and vector embedding generation', - 'Ensure RAG functionality works with uploaded files' - ], - knowledge: [ - 'I understand file processing workflows', - 'I know how to handle different file formats (txt, json, csv, pdf, docx)', - 'I can validate chunking strategies and embedding generation', - 'I am familiar with vector storage and retrieval systems' - ], - interval: 0, - plugins: [], - memory: { enabled: false, shortTermMemorySize: 0, memorySize: 0 }, - rag: { enabled: true, embeddingModel: 'Xenova/all-MiniLM-L6-v2' }, - mode: 'interactive' - } - }) - ); - - if (!createResult.success) { - console.log(chalk.red('Error: Failed to create test agent. Cannot proceed with file tests.')); - return; - } - let agentId = ''; - try { - const agentsResult = await testRunner.runTest('Get Agents List', () => - testRunner.client.getAgents() - ); - - if (!agentsResult.success || !agentsResult.response) { - console.log(chalk.red('Error: Failed to get agents list. Cannot proceed with file tests.')); - return; - } - - const agentsList = (agentsResult.response as any[]) || []; - - if (agentsList.length === 0) { - console.log(chalk.red('Error: No agents found in the list.')); - return; - } - - const fileTestAgent = agentsList.find((agent: any) => agent.name === 'File Test Agent'); - if (!fileTestAgent) { - console.log(chalk.red('Error: File Test Agent not found in agents list.')); - console.log(chalk.yellow('Available agents:'), agentsList.map((a: any) => a.name)); - return; - } - - agentId = fileTestAgent.id; - console.log(chalk.green(`Success: Using agent ID: ${agentId}`)); - - const textContent = `This is a test document for file upload testing. - - It contains multiple lines and some special characters: éàçùñ - - The purpose of this file is to test the file ingestion system of Snak. - - Key features to test: - - File upload via multipart form data - - Text chunking and processing - - Metadata extraction - - Vector embedding generation - - This should be processed into multiple chunks for RAG functionality.`; - - const textBuffer = Buffer.from(textContent, 'utf-8'); - - await testRunner.runTest('Upload Text File', () => - testRunner.client.uploadFile(agentId, textBuffer, 'test-document.txt') - ); - - const jsonContent = { - "name": "Test Configuration", - "version": "1.0.0", - "settings": { - "debug": true, - "timeout": 30000, - "features": ["file-upload", "rag", "embeddings"] - }, - "agents": [ - { - "id": "agent-1", - "name": "Test Agent", - "model": "gpt-4" - } - ] - }; - - const jsonBuffer = Buffer.from(JSON.stringify(jsonContent, null, 2), 'utf-8'); - - await testRunner.runTest('Upload JSON File', () => - testRunner.client.uploadFile(agentId, jsonBuffer, 'config.json') - ); - - const csvContent = `name,age,city,country -John Doe,30,Paris,France -Jane Smith,25,London,UK -Bob Johnson,35,New York,USA -Alice Brown,28,Berlin,Germany`; - - const csvBuffer = Buffer.from(csvContent, 'utf-8'); - - await testRunner.runTest('Upload CSV File', () => - testRunner.client.uploadFile(agentId, csvBuffer, 'test-data.csv') - ); - - const largeContent = 'This is a large test file.\n'.repeat(20000); // ~500KB - const largeBuffer = Buffer.from(largeContent, 'utf-8'); - - await testRunner.runTest('Upload Large File', () => - testRunner.client.uploadFile(agentId, largeBuffer, 'large-test.txt') - ); - - await testRunner.runTest('List Uploaded Files', () => - testRunner.client.listFiles(agentId) - ); - - const specialContent = 'File with special characters in name'; - const specialBuffer = Buffer.from(specialContent, 'utf-8'); - - await testRunner.runTest('Upload File with Special Characters', () => - testRunner.client.uploadFile(agentId, specialBuffer, 'test-file-éàçùñ.txt') - ); - - const longContent = 'A'.repeat(50000); // 50KB of 'A's - const longBuffer = Buffer.from(longContent, 'utf-8'); - - await testRunner.runTest('Upload Very Long File', () => - testRunner.client.uploadFile(agentId, longBuffer, 'very-long.txt') - ); - - await testRunner.runTest('Final File List', () => - testRunner.client.listFiles(agentId) - ); - } finally { - await testRunner.runTest('Cleanup - Delete Test Agent', () => - testRunner.client.deleteAgent(agentId) - ); - } - - - - testRunner.printSummary(); -} - -if (require.main === module) { - testFiles().catch(console.error); -} \ No newline at end of file diff --git a/tests/src/helpers.ts b/tests/src/helpers.ts new file mode 100644 index 000000000..3f496ea76 --- /dev/null +++ b/tests/src/helpers.ts @@ -0,0 +1,70 @@ +import { randomUUID } from "crypto"; +import { CreateAgentResponse, SnakConfig } from "./types"; +import chalk from "chalk"; +import { AgentInitializationDTO, AgentMode } from "@snakagent/core"; +import dotenv from 'dotenv'; +import path from 'path'; + +dotenv.config({ path: path.resolve(__dirname, '../../.env') }); + +export function generateUserId(): string { + return randomUUID(); +} + +export function extractAgentNameFromResponse(response: CreateAgentResponse): string | null { + try { + const match = response.data.match(/Agent (.+?) added and registered with supervisor/); + return match ? match[1] : null; + } catch (error) { + console.log(chalk.yellow(`Warning: Could not extract agent name from response: ${error}`)); + return null; + } + } + +export function defaultAgentConfiguration(agentName: string): AgentInitializationDTO { + return { + name: agentName, + group: 'stress-test', + description: `Stress test agent: ${agentName}`, + lore: [ + 'I am an agent created for stress testing.', + 'My role is to test system performance.', + 'I help validate system stability and performance.' + ], + objectives: [ + 'Test system performance under high load', + 'Validate creation and management of multiple agents', + 'Verify stability with many concurrent users', + 'Measure system performance metrics' + ], + knowledge: [ + 'I understand stress testing and performance', + 'I know multi-user systems', + 'I can validate system stability', + 'I am familiar with performance metrics' + ], + interval: 0, + max_iterations: 10, + mode: AgentMode.INTERACTIVE, + memory: { + enabled: true, + memory_size: 5, + short_term_memory_size: 5 + }, + rag: { + enabled: true, + embedding_model: 'Xenova/all-MiniLM-L6-v2' + }, + plugins: [] + }; + } + + export function createConfigForUser(): SnakConfig { + const port = process.env.SERVER_PORT || '3002'; + return { + baseUrl: `http://localhost:${port}`, + userId: generateUserId(), + apiKey: process.env.SERVER_API_KEY, + }; + } + diff --git a/tests/src/main.ts b/tests/src/main.ts index 32b76d127..f36d98c6d 100644 --- a/tests/src/main.ts +++ b/tests/src/main.ts @@ -1,30 +1,16 @@ import { TestRunner } from './test-runner.js'; -import { SnakConfig } from './types.js'; import chalk from 'chalk'; -import dotenv from 'dotenv'; -import path from 'path'; +import { createConfigForUser } from './helpers.js'; -dotenv.config({ path: path.resolve(__dirname, '../../.env') }); - -const port = process.env.SERVER_PORT || '3002'; -const config: SnakConfig = { - baseUrl: `http://localhost:${port}`, - userId: process.env.SNAK_USER_ID, - apiKey: process.env.SERVER_API_KEY, -}; +const config = createConfigForUser(); async function main() { console.log(chalk.blue.bold('Snak API Test Suite\n')); - if (!port) { - console.error(chalk.red('Error: SERVER_PORT is required')); - process.exit(1); - } console.log(chalk.blue(`Testing against: ${config.baseUrl}`)); if (config.userId) { console.log(chalk.blue(`User ID: ${config.userId}`)); } - console.log(''); const testRunner = new TestRunner(config); diff --git a/tests/src/snak-client-http.ts b/tests/src/snak-client-http.ts index db15d76c7..0e85dd90d 100644 --- a/tests/src/snak-client-http.ts +++ b/tests/src/snak-client-http.ts @@ -1,15 +1,16 @@ import axios, { AxiosInstance, AxiosResponse } from 'axios'; import FormData from 'form-data'; import { AgentResponse } from '@snakagent/core'; +import { AgentConfigSQL } from '@snakagent/agents'; import { SnakConfig, AgentRequest, FileUploadResponse, FileListResponse, - AgentConfig, CreateAgentRequest, JobStatus, - QueueMetrics + QueueMetrics, + CreateAgentResponse } from './types.js'; export class SnakClient { @@ -63,30 +64,26 @@ export class SnakClient { return response.data; } - async getAgents(): Promise { - const response: AxiosResponse = await this.client.get('/api/agents/get_agents'); + async getAgents(): Promise<{ success: boolean; data: AgentConfigSQL[] }> { + const response: AxiosResponse<{ success: boolean; data: AgentConfigSQL[] }> = await this.client.get('/api/agents/get_agents'); return response.data; } - async getAgent(agentId: string): Promise { - const response: AxiosResponse = await this.client.get(`/api/agents/${agentId}`); - return response.data; + async createAgent(agentData: CreateAgentRequest): Promise { + const response: AxiosResponse = await this.client.post('/api/agents/init_agent', agentData); + return response.data } - async createAgent(agentData: CreateAgentRequest): Promise { - const response: AxiosResponse = await this.client.post('/api/agents/init_agent', agentData); + async updateAgent(agentId: string, agentData: Partial): Promise { + const response: AxiosResponse = await this.client.put(`/api/agents/${agentId}`, agentData); return response.data; } - async updateAgent(agentId: string, agentData: Partial): Promise { - const response: AxiosResponse = await this.client.put(`/api/agents/${agentId}`, agentData); + async deleteAgent(agentId: string): Promise<{ success: boolean; data: string }> { + const response: AxiosResponse<{ success: boolean; data: string }> = await this.client.post('/api/agents/delete_agent', { agent_id: agentId }); return response.data; } - async deleteAgent(agentId: string): Promise { - await this.client.post('/api/agents/delete_agent', { agent_id: agentId }); - } - async uploadFile(agentId: string, fileBuffer: Buffer, filename: string): Promise { const formData = new FormData(); formData.append('agentId', agentId); diff --git a/tests/src/stress-test/agent-stress.ts b/tests/src/stress-test/agent-stress.ts new file mode 100644 index 000000000..122fe81e0 --- /dev/null +++ b/tests/src/stress-test/agent-stress.ts @@ -0,0 +1,201 @@ +import { TestRunner } from '../test-runner.js'; +import { QueueMetrics } from '../types.js'; +import chalk from 'chalk'; +import { createConfigForUser } from '../helpers.js'; +import { createAgentWithTracking } from '../agents/creation.js'; +import { CleanupAgent, cleanupAgents } from '../agents/cleanup.js'; + +interface AgentStressTestResult { + testName: string; + success: boolean; + duration: number; + agentsCreated: number; + agentsVerified: number; + agentsDeleted: number; + queueMetrics: QueueMetrics[]; + throughput: number; + avgProcessingTime: number; + error?: string; +} + +async function testAgentStressWithMultipleUsers() { + console.log(chalk.blue.bold('Agent Stress Test - Multiple Users System\n')); + console.log(chalk.yellow('Testing: Concurrent agent creation with multiple users\n')); + + const testResults: AgentStressTestResult[] = []; + + const repeat = 15; + const testScenarios = [ + { name: '100 Users', users: 3, agentsPerUser: 3 }, + ]; + + const defaultConfig = createConfigForUser(); + const defaultTestRunner = new TestRunner(defaultConfig); + + await defaultTestRunner.runTest('Health Check', () => defaultTestRunner.client.healthCheck()); + + for (let i = 0; i < repeat; i++) { + for (const scenario of testScenarios) { + console.log(chalk.blue(`\nTesting ${scenario.name}: ${scenario.users} users with ${scenario.agentsPerUser} agents each`)); + + const testName = `${scenario.name} - ${scenario.users * scenario.agentsPerUser} agents`; + console.log(chalk.blue(`\nTesting ${scenario.users} users with ${scenario.agentsPerUser} agents each (${scenario.users * scenario.agentsPerUser} total agents)`)); + + const startTime = Date.now(); + + console.log(chalk.blue(`Creating ${scenario.users} users...`)); + const users: { testRunner: TestRunner; userIndex: number }[] = []; + + for (let userIndex = 0; userIndex < scenario.users; userIndex++) { + const userConfig = createConfigForUser(); + const userTestRunner = new TestRunner(userConfig); + users.push({ testRunner: userTestRunner, userIndex }); + } + + console.log(chalk.green(` Success: Created ${scenario.users} users`)); + + console.log(chalk.blue(`Creating ${scenario.users * scenario.agentsPerUser} agents in parallel...`)); + + const agentCreationPromises: Promise<{ success: boolean; agentId?: string; agentName?: string; error?: string; userIndex: number; agentIndex: number }>[] = []; + + for (let userIndex = 0; userIndex < scenario.users; userIndex++) { + const user = users[userIndex]; + for (let agentIndex = 0; agentIndex < scenario.agentsPerUser; agentIndex++) { + const promise = createAgentWithTracking(user.testRunner, `StressTest-User${userIndex}-Agent${agentIndex}-${Date.now()}`) + .then(result => ({ ...result, userIndex, agentIndex })) + .catch(error => ({ + success: false, + error: error instanceof Error ? error.message : 'Unknown error', + userIndex, + agentIndex + })); + agentCreationPromises.push(promise); + } + } + + // Wait for all agent creations to complete + const agentResults = await Promise.all(agentCreationPromises); + const creationTime = Date.now() - startTime; + + const successfulAgents = agentResults.filter(r => r.success); + const failedAgents = agentResults.filter(r => !r.success); + + console.log(chalk.green(` Success: Created ${successfulAgents.length} agents, ${failedAgents.length} failed`)); + + if (successfulAgents.length > 0) { + console.log(chalk.blue(` Created agents:`)); + successfulAgents.forEach((agent, index) => { + if (index < 5) { + console.log(chalk.blue(` • ${agent.agentName || 'Unknown'} (User ${agent.userIndex}, Agent ${agent.agentIndex})`)); + } + }); + if (successfulAgents.length > 5) { + console.log(chalk.blue(` ... and ${successfulAgents.length - 5} more agents`)); + } + } + + const scenarioCreatedAgents: { testRunner: TestRunner; agentId: string; agentName: string; userId: string; userIndex: number; agentIndex: number }[] = []; + + for (const result of successfulAgents) { + const user = users[result.userIndex]; + scenarioCreatedAgents.push({ + testRunner: user.testRunner, + agentId: result.agentId!, + agentName: result.agentName || `Unknown-${result.userIndex}-${result.agentIndex}`, + userId: user.testRunner.client['config'].userId || '', + userIndex: result.userIndex, + agentIndex: result.agentIndex + }); + } + + // Verify all agents are in their respective user lists + console.log(chalk.blue(`\nVerifying agents in user lists...`)); + + await defaultTestRunner.runTest('Health Check', () => defaultTestRunner.client.healthCheck()); + + // Calculate metrics + const avgProcessingTime = creationTime / scenarioCreatedAgents.length; + const throughput = scenarioCreatedAgents.length / (creationTime / 1000); // agents/second + const agentsVerified = successfulAgents.length; + // Store test result + const testResult: AgentStressTestResult = { + testName, + success: successfulAgents.length === scenarioCreatedAgents.length, + duration: creationTime, + agentsCreated: scenarioCreatedAgents.length, + agentsVerified, + agentsDeleted: 0, + queueMetrics: [], + throughput, + avgProcessingTime, + error: agentsVerified < scenarioCreatedAgents.length ? `${scenarioCreatedAgents.length - agentsVerified} agents not verified` : undefined + }; + + testResults.push(testResult); + + console.log(chalk.blue(`\n${testName} ${i}:`)); + console.log(chalk.blue(` • Time: ${creationTime}ms | Throughput: ${throughput.toFixed(2)} agents/s`)); + console.log(chalk.blue(` • Average time per agent: ${(creationTime / scenarioCreatedAgents.length).toFixed(2)}ms`)); + console.log(chalk.blue(` • Success: ${agentsVerified}/${scenarioCreatedAgents.length} | Agents verified: ${agentsVerified}`)); + + + // Cleanup: Delete all agents in parallel + const cleanupAgentsData: CleanupAgent[] = scenarioCreatedAgents.map(agent => ({ + testRunner: agent.testRunner, + agentId: agent.agentId, + userId: agent.userId, + userIndex: agent.userIndex, + agentIndex: agent.agentIndex, + agentName: agent.agentName + })); + + const cleanupResult = await cleanupAgents(cleanupAgentsData, 'Agent Stress Test Cleanup'); + + testResult.agentsDeleted = cleanupResult.successful; + + // Small delay between tests + await new Promise(resolve => setTimeout(resolve, 2000)); + } + } + + console.log(chalk.blue.bold('\nOverall Test Summary:')); + console.log(chalk.blue('='.repeat(50))); + + testResults.forEach(result => { + const status = result.success ? chalk.green('PASS') : chalk.red('FAIL'); + console.log(chalk.blue(`${status} ${result.testName}`)); + console.log(chalk.blue(` Duration: ${result.duration}ms, Throughput: ${result.throughput.toFixed(2)} agents/s`)); + console.log(chalk.blue(` Agents: Created=${result.agentsCreated}, Verified=${result.agentsVerified}, Deleted=${result.agentsDeleted}`)); + if (result.error) { + console.log(chalk.red(` Error: ${result.error}`)); + } + }); + + const totalTests = testResults.length; + const passedTests = testResults.filter(r => r.success).length; + const avgThroughput = testResults.reduce((sum, r) => sum + r.throughput, 0) / totalTests; + + const totalAgentsCreated = testResults.reduce((sum, r) => sum + r.agentsCreated, 0); + const totalAgentsVerified = testResults.reduce((sum, r) => sum + r.agentsVerified, 0); + const totalAgentsDeleted = testResults.reduce((sum, r) => sum + r.agentsDeleted, 0); + + console.log(chalk.blue(`\nFinal Statistics:`)); + console.log(chalk.blue(` • Tests passed: ${passedTests}/${totalTests}`)); + console.log(chalk.blue(` • Average throughput: ${avgThroughput.toFixed(2)} agents/s`)); + console.log(chalk.blue(` • Total agents created: ${totalAgentsCreated}`)); + console.log(chalk.blue(` • Total agents verified: ${totalAgentsVerified}`)); + console.log(chalk.blue(` • Total agents deleted: ${totalAgentsDeleted}`)); + + defaultTestRunner.printSummary(); +} + +if (require.main === module) { + testAgentStressWithMultipleUsers() + .then(() => { + process.exit(0); + }) + .catch((error) => { + console.error(chalk.red('Test execution failed:'), error); + process.exit(1); + }); +} diff --git a/tests/src/file-test/file-upload-stress-v2.ts b/tests/src/stress-test/file-upload-stress.ts similarity index 81% rename from tests/src/file-test/file-upload-stress-v2.ts rename to tests/src/stress-test/file-upload-stress.ts index aa187daaf..0e2e36d6b 100644 --- a/tests/src/file-test/file-upload-stress-v2.ts +++ b/tests/src/stress-test/file-upload-stress.ts @@ -1,27 +1,10 @@ import { TestRunner } from '../test-runner.js'; -import { SnakConfig, JobStatus, QueueMetrics } from '../types.js'; +import { JobStatus, QueueMetrics } from '../types.js'; import chalk from 'chalk'; -import dotenv from 'dotenv'; -import path from 'path'; -import { randomUUID } from 'crypto'; +import { createConfigForUser, defaultAgentConfiguration } from '../helpers.js'; +import { CleanupAgent, cleanupAgents } from '../agents/cleanup.js'; -dotenv.config({ path: path.resolve(__dirname, '../../../.env') }); - -const port = process.env.SERVER_PORT || '3002'; - -function generateUserId(scenarioName: string, fileIndex: number): string { - return randomUUID(); -} - -function createConfigForFile(scenarioName: string, fileIndex: number): SnakConfig { - return { - baseUrl: `http://localhost:${port}`, - userId: generateUserId(scenarioName, fileIndex), - apiKey: process.env.SERVER_API_KEY, -}; -} - -interface TestResult { +interface FileUploadStressTestResult { testName: string; success: boolean; duration: number; @@ -160,7 +143,7 @@ async function testFileStressWithJobQueue() { console.log(chalk.blue.bold('File Upload Stress Test v2 - Job Queue System\n')); console.log(chalk.yellow('Testing: Concurrent file uploads with job queue monitoring\n')); - const testResults: TestResult[] = []; + const testResults: FileUploadStressTestResult[] = []; // Test configurations const testScenarios = [ @@ -171,7 +154,7 @@ async function testFileStressWithJobQueue() { ]; // Health check with default config - const defaultConfig = createConfigForFile('default', 0); + const defaultConfig = createConfigForUser(); const defaultTestRunner = new TestRunner(defaultConfig); await defaultTestRunner.runTest('Health Check', () => defaultTestRunner.client.healthCheck()); @@ -202,49 +185,15 @@ async function testFileStressWithJobQueue() { const totalSize = files.reduce((sum, file) => sum + file.size, 0); - // Create users and agents for each file console.log(chalk.blue(`Creating ${scenario.files} users and agents...`)); const agentCreationPromises = files.map(async (file, index) => { - const fileConfig = createConfigForFile(scenario.name, index); + const fileConfig = createConfigForUser(); const fileTestRunner = new TestRunner(fileConfig); const uniqueAgentName = `FileStressTest-${scenario.name.replace(/\s+/g, '')}-User${index + 1}-${Date.now()}`; const createResult = await fileTestRunner.runTest(`Create Agent for User ${index + 1}`, () => fileTestRunner.client.createAgent({ - agent: { - name: uniqueAgentName, - group: 'test', - description: `Agent for stress testing file uploads - ${scenario.name} - User ${index + 1}`, - lore: [ - `I am designed to handle file uploads for user ${index + 1} in ${scenario.name}.`, - 'My purpose is to test system performance under concurrent user load.', - 'I help validate multi-user file processing capabilities.' - ], - objectives: [ - 'Test concurrent file upload performance with multiple users', - 'Validate system stability under multi-user load', - 'Measure processing times for files from different users', - 'Ensure proper resource management across users' - ], - knowledge: [ - 'I understand multi-user scenarios and concurrent processing', - 'I know how to handle file uploads from different users', - 'I can validate system performance under user load', - 'I am familiar with stress testing methodologies for multi-user systems' - ], - interval: 0, - mode: 'interactive', - memory: { - enabled: true, - memorySize: 10, - shortTermMemorySize: 10 - }, - rag: { - enabled: true, - embeddingModel: 'Xenova/all-MiniLM-L6-v2' - }, - plugins: [] - } + agent: defaultAgentConfiguration(uniqueAgentName) }) ); @@ -363,7 +312,7 @@ async function testFileStressWithJobQueue() { const throughput = (totalSize / 1024) / (totalTime / 1000); // KB/s // Store test result - const testResult: TestResult = { + const testResult: FileUploadStressTestResult = { testName, success: completedJobs === files.length, duration: totalTime, @@ -405,23 +354,13 @@ async function testFileStressWithJobQueue() { await new Promise(resolve => setTimeout(resolve, 2000)); } - console.log(chalk.blue(`\nCleaning up ${scenarioCreatedAgents.length} agents...`)); - const cleanupPromises = scenarioCreatedAgents.map(async (agent: { testRunner: TestRunner; agentId: string; userId: string }, index: number) => { - try { - await agent.testRunner.runTest(`Cleanup - Delete Agent ${index + 1}`, () => - agent.testRunner.client.deleteAgent(agent.agentId) - ); - return { success: true, index }; - } catch (error) { - console.log(chalk.red(` Error: Failed to cleanup agent ${index + 1}: ${error}`)); - return { success: false, index, error }; - } - }); + const cleanupAgentsData: CleanupAgent[] = scenarioCreatedAgents.map((agent, index) => ({ + testRunner: agent.testRunner, + agentId: agent.agentId, + userId: agent.userId + })); - const cleanupResults = await Promise.all(cleanupPromises); - const successfulCleanups = cleanupResults.filter(r => r.success).length; - const failedCleanups = cleanupResults.filter(r => !r.success).length; - console.log(chalk.green(` Success: Cleanup completed: ${successfulCleanups} successful, ${failedCleanups} failed`)); + await cleanupAgents(cleanupAgentsData, 'File Upload Stress Test Cleanup'); } console.log(chalk.blue.bold('\nOverall Test Summary:')); diff --git a/tests/src/stress-test/update-agent-stress.ts b/tests/src/stress-test/update-agent-stress.ts new file mode 100644 index 000000000..e69de29bb diff --git a/tests/src/test-runner.ts b/tests/src/test-runner.ts index 07fd6528d..081b6426e 100644 --- a/tests/src/test-runner.ts +++ b/tests/src/test-runner.ts @@ -1,17 +1,18 @@ +import { defaultAgentConfiguration } from './helpers.js'; import { SnakClient } from './snak-client-http.js'; -import { SnakConfig, TestResult } from './types.js'; +import { SnakConfig, UnitTestResult } from './types.js'; import chalk from 'chalk'; import ora from 'ora'; export class TestRunner { public client: SnakClient; - private results: TestResult[] = []; + private results: UnitTestResult[] = []; constructor(config: SnakConfig) { this.client = new SnakClient(config); } - async runTest(testName: string, testFn: () => Promise): Promise { + async runTest(testName: string, testFn: () => Promise): Promise { const spinner = ora(`Running ${testName}...`).start(); const startTime = Date.now(); @@ -21,7 +22,7 @@ export class TestRunner { spinner.succeed(chalk.green(`Success: ${testName} passed (${duration}ms)`)); - const result: TestResult = { + const result: UnitTestResult = { testName, success: true, durationMs: duration, @@ -35,7 +36,7 @@ export class TestRunner { spinner.fail(chalk.red(`Error: ${testName} failed (${duration}ms)`)); - const result: TestResult = { + const result: UnitTestResult = { testName, success: false, durationMs: duration, @@ -59,48 +60,12 @@ export class TestRunner { // Try to create a test agent based on the starknet-rpc agent example const testAgent = await this.runTest('Create Test Agent', () => this.client.createAgent({ - agent: { - name: 'Test RPC Agent', - group: 'test', - description: 'A test agent created for testing purposes, based on the Starknet RPC agent configuration.', - lore: [ - 'I was created as a test agent to validate the Snak Agent creation system.', - 'Born from the need to test API endpoints and agent functionality.', - 'My purpose is to demonstrate that agent creation works correctly.' - ], - objectives: [ - 'Validate that agent creation endpoints work properly.', - 'Test agent configuration and initialization.', - 'Demonstrate successful agent lifecycle management.', - 'Serve as a reference for other test agents.' - ], - knowledge: [ - 'I have knowledge of the Snak Agent system architecture.', - 'I understand how to interact with the test environment.', - 'I can help validate API functionality and responses.', - 'I stay updated with the test requirements and specifications.' - ], - interval: 15000, - plugins: ['rpc'], - memory: { - enabled: true, - memorySize: 20, - shortTermMemorySize: 15 - }, - rag: { - enabled: true, - embeddingModel: "Xenova/all-MiniLM-L6-v2" - }, - mode: 'interactive' - } + agent: defaultAgentConfiguration('test-agent') }) ); if (testAgent.success && testAgent.response) { console.log('Success: Agent created successfully, response:', testAgent.response); - - // Wait for 1 second to ensure the first agent is created - await new Promise(resolve => setTimeout(resolve, 1000)); const agents = await this.runTest('Get Agents List Again', () => this.client.getAgents() @@ -111,6 +76,9 @@ export class TestRunner { if (agents.success && agents.response && (agents.response as any).data && ((agents.response as any).data as any[]).length > 0) { console.log('Success: Found agents:', ((agents.response as any).data as any[]).length); const agentId = ((agents.response as any).data as any[])[0].id; + + console.log('Waiting 0.5 seconds...'); + await new Promise(resolve => setTimeout(resolve, 500)); await this.runTest('Send Agent Request', () => this.client.sendAgentRequest({ @@ -169,7 +137,7 @@ export class TestRunner { console.log(chalk.blue.bold('\nAll tests completed!\n')); } - getResults(): TestResult[] { + getResults(): UnitTestResult[] { return this.results; } } diff --git a/tests/src/types.ts b/tests/src/types.ts index 0344dc795..ff06667ff 100644 --- a/tests/src/types.ts +++ b/tests/src/types.ts @@ -1,3 +1,5 @@ +import { AgentInitializationDTO, AgentMode } from "@snakagent/core"; + export interface SnakConfig { baseUrl: string; userId?: string; @@ -43,19 +45,6 @@ export interface StoredFile { export type FileListResponse = StoredFile[]; -export interface AgentConfig { - id: string; - name: string; - description: string; - model: string; - temperature: number; - maxTokens: number; - systemPrompt: string; - tools: string[]; - createdAt: string; - updatedAt: string; -} - export interface AgentPrompt { lore: string[]; objectives: string[]; @@ -73,25 +62,17 @@ export interface AgentRag { embeddingModel: string | null; } -export interface AgentInitializationDTO { - name: string; - group: string; - description: string; - lore: string[]; - objectives: string[]; - knowledge: string[]; - interval: number; - plugins: string[]; - memory: AgentMemory; - rag: AgentRag; - mode: string; -} - export interface CreateAgentRequest { agent: AgentInitializationDTO; } -export interface TestResult { + +export interface CreateAgentResponse { + success: boolean; + data: string; +} + +export interface UnitTestResult { testName: string; success: boolean; durationMs: number;