@juspay/neurolink
Version:
Universal AI Development Platform with working MCP integration, multi-provider support, voice (TTS/STT/realtime), and professional CLI. 58+ external MCP servers discoverable, multimodal file processing, RAG pipelines. Build, test, and deploy AI applicatio
274 lines • 11.2 kB
JavaScript
/**
* Built-in agent tools for TaskManager.
*
* These tools allow the AI to self-schedule, manage, and inspect tasks
* during conversations. Created per-instance via `createTaskTools()` factory,
* following the same pattern as `createFileTools()` in files/fileTools.ts.
*
* @module tasks/tools/taskTools
*/
import { tool } from "ai";
import { z } from "zod";
import { logger } from "../../utils/logger.js";
import { TaskError } from "../errors.js";
/**
* Parse a schedule object from tool input.
* Accepts: { type: "cron", expression } | { type: "interval", every } | { type: "once", at }
*/
function parseSchedule(input) {
const type = input.type;
if (type === "cron") {
if (!input.expression || typeof input.expression !== "string") {
throw TaskError.create("SCHEDULE_FAILED", "Cron schedule requires an 'expression' field");
}
return {
type: "cron",
expression: input.expression,
...(input.timezone ? { timezone: input.timezone } : {}),
};
}
if (type === "interval") {
if (typeof input.every !== "number" ||
!isFinite(input.every) ||
input.every <= 0) {
throw TaskError.create("SCHEDULE_FAILED", "Interval schedule requires a positive 'every' field (milliseconds)");
}
return { type: "interval", every: input.every };
}
if (type === "once") {
if (!input.at) {
throw TaskError.create("SCHEDULE_FAILED", "Once schedule requires an 'at' field (ISO 8601 date string)");
}
return { type: "once", at: input.at };
}
throw TaskError.create("SCHEDULE_FAILED", `Invalid schedule type: "${type}". Must be "cron", "interval", or "once".`);
}
/**
* Create task management tools bound to a TaskManager instance.
*
* These tools follow the same factory pattern as `createFileTools()` in
* `src/lib/files/fileTools.ts`. The `manager` is captured via closure,
* eliminating the need for module-level singleton state.
*
* @param manager - The TaskManager instance to bind to
* @returns Record of tool name to tool definition
*
* @example
* ```typescript
* const manager = new TaskManager(neurolink, config);
* const tools = createTaskTools(manager);
* // tools.createTask, tools.listTasks, tools.getTaskRuns, etc.
* ```
*/
export function createTaskTools(manager) {
return {
createTask: tool({
description: 'Schedule a recurring or one-shot task that runs a prompt on a schedule. Use schedule type "cron" for calendar-based (e.g. "0 9 * * *"), "interval" for fixed frequency (every N milliseconds), or "once" for a single future execution.',
inputSchema: z.object({
name: z.string().describe("Human-readable task name"),
prompt: z.string().describe("The prompt to execute on each run"),
schedule: z
.object({
type: z.enum(["cron", "interval", "once"]),
expression: z
.string()
.optional()
.describe('Cron expression (for type "cron"), e.g. "0 9 * * *"'),
timezone: z
.string()
.optional()
.describe('IANA timezone for cron, e.g. "America/New_York"'),
every: z
.number()
.optional()
.describe('Interval in milliseconds (for type "interval")'),
at: z
.string()
.optional()
.describe('ISO 8601 timestamp (for type "once")'),
})
.describe("When to run the task"),
mode: z
.enum(["isolated", "continuation"])
.optional()
.describe('Execution mode. "isolated" = fresh context per run (default). "continuation" = preserves conversation history across runs.'),
}),
execute: async ({ name, prompt, schedule, mode }) => {
try {
const parsedSchedule = parseSchedule(schedule);
const task = await manager.create({
name,
prompt,
schedule: parsedSchedule,
mode: mode,
});
return {
success: true,
taskId: task.id,
name: task.name,
status: task.status,
mode: task.mode,
nextRunAt: task.nextRunAt,
schedule: task.schedule,
};
}
catch (error) {
logger.error("[taskTools] createTask failed", {
error: String(error),
});
return {
success: false,
error: error instanceof Error ? error.message : String(error),
};
}
},
}),
listTasks: tool({
description: "List all scheduled tasks and their current status.",
inputSchema: z.object({
status: z
.enum([
"active",
"paused",
"completed",
"failed",
"cancelled",
"pending",
])
.optional()
.describe("Filter by task status"),
}),
execute: async ({ status }) => {
try {
const tasks = await manager.list(status
? {
status: status,
}
: undefined);
return {
success: true,
count: tasks.length,
tasks: tasks.map((t) => ({
taskId: t.id,
name: t.name,
status: t.status,
mode: t.mode,
schedule: t.schedule,
runCount: t.runCount,
lastRunAt: t.lastRunAt,
nextRunAt: t.nextRunAt,
})),
};
}
catch (error) {
logger.error("[taskTools] listTasks failed", {
error: String(error),
});
return {
success: false,
error: error instanceof Error ? error.message : String(error),
};
}
},
}),
getTaskRuns: tool({
description: "Get the run history of a scheduled task, showing recent executions and their results.",
inputSchema: z.object({
taskId: z.string().describe("The task ID"),
limit: z
.number()
.optional()
.describe("Max results to return (default: 10)"),
}),
execute: async ({ taskId, limit }) => {
try {
const runs = await manager.runs(taskId, { limit: limit ?? 10 });
return {
success: true,
taskId,
count: runs.length,
runs: runs.map((r) => ({
runId: r.runId,
status: r.status,
output: r.output
? r.output.length > 500
? r.output.slice(0, 500) + "..."
: r.output
: undefined,
durationMs: r.durationMs,
timestamp: r.timestamp,
error: r.error,
})),
};
}
catch (error) {
logger.error("[taskTools] getTaskRuns failed", {
error: String(error),
});
return {
success: false,
error: error instanceof Error ? error.message : String(error),
};
}
},
}),
deleteTask: tool({
description: "Cancel and permanently remove a scheduled task.",
inputSchema: z.object({
taskId: z.string().describe("The task ID to delete"),
}),
execute: async ({ taskId }) => {
try {
const task = await manager.get(taskId);
if (!task) {
return { success: false, error: `Task not found: ${taskId}` };
}
await manager.delete(taskId);
return { success: true, deletedTask: task.name, taskId };
}
catch (error) {
logger.error("[taskTools] deleteTask failed", {
error: String(error),
});
return {
success: false,
error: error instanceof Error ? error.message : String(error),
};
}
},
}),
runTaskNow: tool({
description: "Immediately execute a scheduled task outside of its normal schedule. Returns the run result.",
inputSchema: z.object({
taskId: z.string().describe("The task ID to run"),
}),
execute: async ({ taskId }) => {
try {
const result = await manager.run(taskId);
return {
success: true,
runId: result.runId,
status: result.status,
output: result.output
? result.output.length > 1000
? result.output.slice(0, 1000) + "..."
: result.output
: undefined,
durationMs: result.durationMs,
error: result.error,
};
}
catch (error) {
logger.error("[taskTools] runTaskNow failed", {
error: String(error),
});
return {
success: false,
error: error instanceof Error ? error.message : String(error),
};
}
},
}),
};
}
//# sourceMappingURL=taskTools.js.map