HEX
Server: LiteSpeed
System: Linux houston.panomity.com 6.8.0-100-generic #100-Ubuntu SMP PREEMPT_DYNAMIC Tue Jan 13 16:40:06 UTC 2026 x86_64
User: nudepix (1011)
PHP: 7.4.33
Disabled: pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare,
Upload Files
File: //opt/agentcloud/webapp/src/controllers/task.ts
'use strict';

import { dynamicResponse } from '@dr';
import { getAgentById, getAgentsByTeam,removeAgentsModel } from 'db/agent';
import { getAssetById } from 'db/asset';
import { getDatasourcesByTeam } from 'db/datasource';
import { addTask, deleteTaskById, getTaskById, getTasksByTeam, updateTask } from 'db/task';
import { getToolsByTeam } from 'db/tool';
import { chainValidations } from 'lib/utils/validationUtils';
import toObjectId from 'misc/toobjectid';
import toSnakeCase from 'misc/tosnakecase';
import { Task } from 'struct/task';

export async function tasksData(req, res, _next) {
	const [tasks, tools, agents] = await Promise.all([
		getTasksByTeam(req.params.resourceSlug),
		getToolsByTeam(req.params.resourceSlug),
		getAgentsByTeam(req.params.resourceSlug),
	]);
	return {
		csrf: req.csrfToken(),
		tools,
		tasks,
		agents,
	};
}

/**
* GET /[resourceSlug]/tasks
* task page html
*/
export async function tasksPage(app, req, res, next) {
	const data = await tasksData(req, res, next);
	res.locals.data = { ...data, account: res.locals.account };
	return app.render(req, res, `/${req.params.resourceSlug}/tasks`);
}

/**
* GET /[resourceSlug]/tasks.json
* team tasks json data
*/
export async function tasksJson(req, res, next) {
	const data = await tasksData(req, res, next);
	return res.json({ ...data, account: res.locals.account });
}

export async function taskData(req, res, _next) {
	const [task, tools, agents] = await Promise.all([
		getTaskById(req.params.resourceSlug, req.params.taskId),
		getToolsByTeam(req.params.resourceSlug),
		getAgentsByTeam(req.params.resourceSlug),
	]);
	return {
		csrf: req.csrfToken(),
		tools,
		task,
		agents,
	};
}

/**
* GET /[resourceSlug]/task/:taskId.json
* task json data
*/
export async function taskJson(req, res, next) {
	const data = await taskData(req, res, next);
	return res.json({ ...data, account: res.locals.account });
}

/**
* GET /[resourceSlug]/task/:taskId/edit
* task edit page html
*/
export async function taskEditPage(app, req, res, next) {
	const data = await taskData(req, res, next);
	res.locals.data = { ...data, account: res.locals.account };
	return app.render(req, res, `/${req.params.resourceSlug}/task/${req.params.taskId}/edit`);
}

/**
* GET /[resourceSlug]/task/add
* task add page html
*/
export async function taskAddPage(app, req, res, next) {
	const data = await taskData(req, res, next);
	res.locals.data = { ...data, account: res.locals.account };
	return app.render(req, res, `/${req.params.resourceSlug}/task/add`);
}

export async function addTaskApi(req, res, next) {

	const { name, description, requiresHumanInput, expectedOutput, toolIds, asyncExecution, agentId, iconId }  = req.body;

	let validationError = chainValidations(req.body, [
		{ field: 'name', validation: { notEmpty: true, lengthMin: 1, customError: 'Name must not be empty.' }},
		{ field: 'description', validation: { notEmpty: true, lengthMin: 1, customError: 'Description must not be empty.' }},
		// Include other fields as necessary
	], { name: 'Name', description: 'Description', expectedOutput: 'Expected Output', toolIds: 'Tool IDs' });

	if (validationError ) {
		return dynamicResponse(req, res, 400, { error: validationError });
	}

	if (toolIds && !Array.isArray(toolIds) || toolIds.some(id => typeof id !== 'string')) {
		return dynamicResponse(req, res, 400, { error: 'Invalid inputs' });
	}

	const foundAgent = await getAgentById(req.params.resourceSlug, agentId);
	if (!foundAgent) {
		return dynamicResponse(req, res, 400, { error: 'Invalid inputs' });
	}
	
	const foundIcon = await getAssetById(iconId);

	const addedTask = await addTask({
		orgId: res.locals.matchingOrg.id,
		teamId: toObjectId(req.params.resourceSlug),
		name,
		description,
		expectedOutput,
		toolIds: toolIds.map(toObjectId),
		agentId: toObjectId(agentId),
		asyncExecution: asyncExecution === true,
		requiresHumanInput: requiresHumanInput === true,
		icon: foundIcon ? {
			id: foundIcon._id,
			filename: foundIcon.filename,
		} : null,
	});

	return dynamicResponse(req, res, 302, { _id: addedTask.insertedId, redirect: `/${req.params.resourceSlug}/tasks` });

}

export async function editTaskApi(req, res, next) {

	const { name, requiresHumanInput, description, expectedOutput, toolIds, asyncExecution, agentId }  = req.body;

	const task = await getTaskById(req.params.resourceSlug, req.params.taskId);
	if (!task) {
		return dynamicResponse(req, res, 400, { error: 'Invalid inputs' });
	}

	await updateTask(req.params.resourceSlug, req.params.taskId, {
		name,
		description,
		expectedOutput,
		toolIds: toolIds ? toolIds.map(toObjectId) : [],
		asyncExecution: asyncExecution === true,
		requiresHumanInput: requiresHumanInput === true,
		agentId: toObjectId(agentId)
	});

	return dynamicResponse(req, res, 302, { /*redirect: `/${req.params.resourceSlug}/tasks`*/ });

}

/**
* @api {delete} /forms/task/[taskId] Delete a task
* @apiName delete
* @apiGroup Task
*
* @apiParam {String} taskId task id
*/
export async function deleteTaskApi(req, res, next) {

	const { taskId } = req.body;

	if (!taskId || typeof taskId !== 'string' || taskId.length !== 24) {
		return dynamicResponse(req, res, 400, { error: 'Invalid inputs' });
	}

	await Promise.all([
		deleteTaskById(req.params.resourceSlug, taskId),
		//TODO: reference handling?
	]);

	return dynamicResponse(req, res, 302, { });

}