This repository has been archived by the owner on Oct 21, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
33 changed files
with
418 additions
and
111 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
import { DataSource } from 'typeorm' | ||
import { testConfig } from '../../configuration.tests' | ||
import { ConfigService } from '@nestjs/config' | ||
import { CreateTaskDto } from './dto/create-task-dto' | ||
import fetch from 'node-fetch' | ||
|
||
describe('AppController', () => { | ||
// let appController: AgentController | ||
// beforeEach(async () => { | ||
// const appModule: TestingModule = await Test.createTestingModule({ | ||
// // imports: [TypeOrmModule.forFeature([TaskEntity, StepEntity])], | ||
// imports: [], | ||
// controllers: [AgentController], | ||
// providers: [ | ||
// { provide: AgentService, useValue: undefined }, | ||
// { provide: getRepositoryToken(TaskEntity), useClass: TaskEntity }, | ||
// { provide: getRepositoryToken(StepEntity), useClass: StepEntity } | ||
// ] | ||
// }).compile() | ||
// await appModule.init() | ||
// // appController = app.get<AgentController>(AgentController) | ||
// }) | ||
let dataSource: DataSource | ||
let configService: ConfigService | ||
const TASKS_ENDPOINT = '/api/v1/agent/tasks' | ||
|
||
beforeAll(async () => { | ||
configService = new ConfigService(testConfig) | ||
|
||
console.log('Connecting to database') | ||
//@ts-expect-error-next-line | ||
dataSource = new DataSource({ | ||
type: configService.get('database.type'), | ||
host: configService.get('database.host'), | ||
port: configService.get('database.port'), | ||
username: configService.get('database.username'), | ||
password: configService.get<string>('database.password'), | ||
database: configService.get('database.name'), | ||
logging: ['query', 'log', 'error', 'warn', 'info'], | ||
entities: [], | ||
synchronize: true | ||
// logging: true | ||
}) | ||
await dataSource.initialize() | ||
console.log('Conection to database established') | ||
}) | ||
|
||
afterAll(async () => { | ||
try { | ||
if (dataSource.isInitialized) { | ||
await dataSource.query('DELETE FROM steps ') | ||
console.log('Closing database connection ..') | ||
dataSource.destroy() | ||
} | ||
} catch (error) { | ||
console.warn('Error deleting content from db') | ||
} | ||
}) | ||
|
||
describe('root', () => { | ||
it('Can create a task', async () => { | ||
const task = new CreateTaskDto() | ||
task.query = 'My test query' | ||
task.additional_params = [{ param1: 'value1' }, { param2: 'value2' }] | ||
task.artifacts = [{ artifact_id: 'art-0123', url: 'https://url.test' }] | ||
createTask(task).then((response) => { | ||
expect(response.status).toBe(201) | ||
}) | ||
}) | ||
}) | ||
|
||
async function createTask(createTaskDto: CreateTaskDto) { | ||
console.log(`Creating task: ${configService.get('api.url')}`) | ||
return fetch(`${configService.get('api.url')}${TASKS_ENDPOINT}`, { | ||
method: 'post', | ||
body: JSON.stringify(createTaskDto), | ||
headers: { | ||
'Content-Type': 'application/json', | ||
Authorization: `Bearer ${configService.get('api.authToken')}` | ||
} | ||
}) | ||
// return request(configService.get('api.url')) | ||
// .post(TASKS_ENDPOINT) | ||
// .set('Accept', 'application/json') | ||
// .set('Authorization', `Bearer ${configService.get('api.authToken')}`) | ||
// .send(createTaskDto) | ||
} | ||
}) |
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
import { Injectable, Logger } from '@nestjs/common' | ||
import { CreateTaskDto } from './dto/create-task-dto' | ||
import { AgentsFactory } from '../../common/utils/agents-factory' | ||
import { TaskEntity } from '../../database/entities/task.entity' | ||
import { InjectRepository } from '@nestjs/typeorm' | ||
import { StepEntity } from '../../database/entities/step.entity' | ||
import { MoreThan, Repository } from 'typeorm' | ||
import { ExecutionStatus } from '../../common/models/agent-models' | ||
import { AppDataSource } from '../../database/typeorm.config' | ||
|
||
@Injectable() | ||
export class AgentService { | ||
// The maximum number of retries for a step, after which it is marked as failed | ||
readonly MAX_STEP_RETRIES = 3 | ||
constructor( | ||
@InjectRepository(TaskEntity) private taskEntity: Repository<TaskEntity>, | ||
@InjectRepository(StepEntity) private stepEntity: Repository<StepEntity> | ||
) {} | ||
|
||
async createAgentTask(agentTaskDto: CreateTaskDto) { | ||
const task = AgentsFactory.getTaskFromTemplate(agentTaskDto) | ||
const dbTaskEntity: TaskEntity = { | ||
...new TaskEntity(), | ||
name: task.name, | ||
input_query: task.input.query, | ||
input_params: JSON.stringify(task.input.additional_params), | ||
input_artifacts: JSON.stringify(task.input.artifacts) | ||
} | ||
const insertedTask = await this.taskEntity.save(dbTaskEntity) | ||
|
||
const step = AgentsFactory.getStepFromTemplate( | ||
agentTaskDto, | ||
insertedTask.task_id | ||
) | ||
const dbStepEntity: StepEntity = { | ||
...new StepEntity(), | ||
task_id: step.task_id, | ||
name: task.name, | ||
input_query: step.input.query, | ||
is_last: step.is_last, | ||
input_params: JSON.stringify(step.input.additional_params), | ||
input_artifacts: JSON.stringify(step.input.artifacts) | ||
} | ||
await this.stepEntity.save(dbStepEntity) | ||
|
||
return insertedTask | ||
} | ||
|
||
async getPendingTasksFromDb() { | ||
return this.taskEntity.find({ | ||
where: { task_status: ExecutionStatus.PENDING } | ||
}) | ||
} | ||
|
||
async getPendingStepsForTask(task: TaskEntity) { | ||
return this.stepEntity.find({ | ||
where: { step_status: ExecutionStatus.PENDING, task_id: task.task_id } | ||
}) | ||
} | ||
|
||
updateStep(stepId: string, stepUpdated: Partial<StepEntity>) { | ||
Logger.log(`Updating step ${stepId}, with ${JSON.stringify(stepUpdated)}`) | ||
return this.stepEntity.update( | ||
{ step_id: stepId }, | ||
{ ...stepUpdated, updated_at: new Date() } | ||
) | ||
} | ||
|
||
async completeTasksWhenStepsAreDone() { | ||
const tasks = await AppDataSource.query( | ||
`SELECT tasks.task_id as task_id, steps.output as output, steps.output_artifacts as output_artifacts, steps.output_additional as output_additional FROM tasks, steps WHERE tasks.task_id = steps.task_id AND steps.is_last = true AND steps.step_status = \'COMPLETED\' AND tasks.task_status = \'PENDING\' ` | ||
) | ||
for await (const task of tasks) { | ||
Logger.log(`Marking task ${task.task_id} as completed`) | ||
this.taskEntity.update( | ||
{ task_id: task.task_id }, | ||
{ | ||
task_status: ExecutionStatus.COMPLETED, | ||
output: task.output, | ||
output_artifacts: task.output_artifacts, | ||
output_additional: task.output_additional, | ||
updated_at: new Date() | ||
} | ||
) | ||
} | ||
return tasks | ||
} | ||
|
||
async markTasksAsFailedAfterRetries() { | ||
this.stepEntity.update( | ||
{ retries: MoreThan(this.MAX_STEP_RETRIES) }, | ||
{ step_status: ExecutionStatus.FAILED, updated_at: new Date() } | ||
) | ||
const tasks = await AppDataSource.query( | ||
`SELECT tasks.task_id as task_id, steps.output as output, steps.output_artifacts as output_artifacts, steps.output_additional as output_additional FROM tasks, steps WHERE tasks.task_id = steps.task_id AND steps.step_status = \'FAILED\' AND tasks.task_status != \'FAILED\' ` | ||
) | ||
for await (const task of tasks) { | ||
Logger.log(`Marking task ${task.task_id} as failed`) | ||
this.taskEntity.update( | ||
{ task_id: task.task_id }, | ||
{ | ||
task_status: ExecutionStatus.FAILED, | ||
output: task.output, | ||
output_artifacts: task.output_artifacts, | ||
output_additional: task.output_additional, | ||
updated_at: new Date() | ||
} | ||
) | ||
} | ||
return tasks | ||
} | ||
// async addFirstStepToTask(taskId: string) { | ||
// } | ||
|
||
// async addLastStepToTask(taskId: string) { | ||
// } | ||
|
||
async getTaskById(taskId: string) { | ||
const steps = await this.stepEntity.find({ where: { task_id: taskId } }) | ||
const task = await this.taskEntity.findOne({ where: { task_id: taskId } }) | ||
return { task, steps } | ||
} | ||
|
||
listTasks() { | ||
return [] | ||
} | ||
} |
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
export const testConfig = { | ||
api: { | ||
host: process.env.API_HOST || 'localhost', | ||
port: parseInt(process.env.API_PORT, 10) || 4100, | ||
url: | ||
process.env.API_URL || | ||
`http://${process.env.API_HOST || 'localhost'}:${ | ||
process.env.API_PORT || '4100' | ||
}`, | ||
authToken: process.env.API_AUTH_TOKEN, | ||
enableHttpsRedirect: process.env.API_ENABLE_HTTPS_REDIRECT === 'true' | ||
}, | ||
database: { | ||
type: process.env.DATABASE_TYPE || 'sqlite', // sqlite, mysql, postgres, etc | ||
name: process.env.DATABASE_NAME || '/tmp/test/agent-template.db', // path to the database file if sqlite if is a different database type put the database name instead | ||
host: process.env.DATABASE_HOST, | ||
port: parseInt(process.env.DATABASE_PORT, 10), | ||
username: process.env.DATABASE_USERNAME, | ||
password: process.env.DATABASE_PASSWORD, | ||
schena: process.env.DATABASE_SCHEMA | ||
} | ||
} | ||
export default () => testConfig |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.