@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
314 lines (313 loc) • 9.93 kB
TypeScript
/**
* Type definitions for the NeuroLink TaskManager system.
*
* TaskManager provides scheduled and self-running task capabilities,
* enabling AI agents to execute prompts on cron, interval, or one-shot schedules.
*/
import type { Cron } from "croner";
import type { createClient } from "redis";
import type { MemoryMetricConfig, MetricConfig } from "./autoresearch.js";
import type { ThinkingLevel } from "./config.js";
/**
* Discriminator for standard vs autoresearch tasks.
* - "standard": Normal prompt-based task (default)
* - "autoresearch": Autonomous experiment loop task
*/
export type ScheduledTaskType = "standard" | "autoresearch";
/**
* Configuration for autoresearch tasks.
* Embedded in TaskDefinition/Task when type === "autoresearch".
*/
export type AutoresearchTaskConfig = {
repoPath: string;
mutablePaths: string[];
runCommand: string;
metric: MetricConfig;
immutablePaths?: string[];
timeoutMs?: number;
maxExperiments?: number;
provider?: string;
model?: string;
thinkingLevel?: ThinkingLevel;
maxBudgetUsd?: number;
programPath?: string;
resultsPath?: string;
statePath?: string;
logPath?: string;
branchPrefix?: string;
memoryMetric?: MemoryMetricConfig;
};
export type TaskScheduleType = "cron" | "interval" | "once";
export type CronSchedule = {
type: "cron";
/** Standard 5-field cron expression, e.g. "0 9 * * *" */
expression: string;
/** IANA timezone, e.g. "America/New_York" */
timezone?: string;
};
export type IntervalSchedule = {
type: "interval";
/** Interval in milliseconds */
every: number;
};
export type OnceSchedule = {
type: "once";
/** ISO 8601 timestamp or Date object */
at: Date | string;
};
export type TaskSchedule = CronSchedule | IntervalSchedule | OnceSchedule;
/**
* - "isolated": Each run gets a fresh context. No memory of previous runs.
* - "continuation": Conversation history is preserved across runs.
*/
export type TaskExecutionMode = "isolated" | "continuation";
export type TaskStatus = "pending" | "active" | "paused" | "completed" | "failed" | "cancelled";
export type TaskDefinition = {
name: string;
prompt: string;
schedule: TaskSchedule;
mode?: TaskExecutionMode;
/** Task type discriminator. Default: "standard" */
type?: ScheduledTaskType;
/** Autoresearch config (required when type === "autoresearch") */
autoresearch?: AutoresearchTaskConfig;
provider?: string;
model?: string;
thinkingLevel?: ThinkingLevel;
systemPrompt?: string;
/** Enable/disable tools for this task. Default: true */
tools?: boolean;
maxTokens?: number;
temperature?: number;
/** Max number of executions. Omit for unlimited. */
maxRuns?: number;
/** Per-run timeout in ms. Default: 120000 */
timeout?: number;
retry?: {
/** Default: 3 */
maxAttempts?: number;
/** Default: [30000, 60000, 300000] */
backoffMs?: number[];
};
onSuccess?: (result: TaskRunResult) => void | Promise<void>;
onError?: (error: TaskRunError) => void | Promise<void>;
/** Called when task reaches a terminal state (completed, failed, cancelled) */
onComplete?: (task: Task) => void | Promise<void>;
metadata?: Record<string, unknown>;
};
export type Task = {
id: string;
name: string;
prompt: string;
schedule: TaskSchedule;
mode: TaskExecutionMode;
/** Task type discriminator. Default: "standard" */
type: ScheduledTaskType;
status: TaskStatus;
/** Autoresearch config (present when type === "autoresearch") */
autoresearch?: AutoresearchTaskConfig;
provider?: string;
model?: string;
thinkingLevel?: ThinkingLevel;
systemPrompt?: string;
tools: boolean;
maxTokens?: number;
temperature?: number;
maxRuns?: number;
timeout: number;
retry: {
maxAttempts: number;
backoffMs: number[];
};
runCount: number;
lastRunAt?: string;
nextRunAt?: string;
createdAt: string;
updatedAt: string;
/** Conversation session ID for continuation mode */
sessionId?: string;
metadata?: Record<string, unknown>;
};
/** Shape of the tasks.json file used by FileTaskStore */
export type TasksFile = {
version: number;
tasks: Record<string, Task>;
};
export type TaskRunResult = {
taskId: string;
runId: string;
status: "success" | "error";
/** AI response text */
output?: string;
toolCalls?: Array<{
name: string;
input: unknown;
output: unknown;
}>;
tokensUsed?: {
input: number;
output: number;
};
durationMs: number;
/** ISO 8601 */
timestamp: string;
error?: string;
};
export type TaskRunError = {
taskId: string;
runId: string;
error: string;
attempt: number;
maxAttempts: number;
willRetry: boolean;
/** ISO 8601 */
timestamp: string;
};
/**
* Abstracts task persistence. Auto-selected based on backend:
* - BullMQ → RedisTaskStore
* - NodeTimeout → FileTaskStore
*/
export type TaskStore = {
readonly type: "redis" | "file";
initialize(): Promise<void>;
shutdown(): Promise<void>;
save(task: Task): Promise<void>;
get(taskId: string): Promise<Task | null>;
list(filter?: {
status?: TaskStatus;
}): Promise<Task[]>;
update(taskId: string, updates: Partial<Task>): Promise<Task>;
delete(taskId: string): Promise<void>;
appendRun(taskId: string, run: TaskRunResult): Promise<void>;
getRuns(taskId: string, options?: {
limit?: number;
status?: string;
}): Promise<TaskRunResult[]>;
appendHistory(taskId: string, messages: ConversationEntry[]): Promise<void>;
getHistory(taskId: string): Promise<ConversationEntry[]>;
clearHistory(taskId: string): Promise<void>;
};
export type ConversationEntry = {
role: "user" | "assistant";
content: string;
timestamp: string;
};
export type TaskExecutorFn = (task: Task) => Promise<TaskRunResult>;
/**
* Abstracts the scheduling/looping mechanism.
* Implementations: BullMQ (production), NodeTimeout (development).
*/
export type TaskBackend = {
readonly name: string;
initialize(): Promise<void>;
shutdown(): Promise<void>;
/** Schedule a task for execution */
schedule(task: Task, executor: TaskExecutorFn): Promise<void>;
/** Cancel a scheduled task */
cancel(taskId: string): Promise<void>;
/** Pause a task's schedule */
pause(taskId: string): Promise<void>;
/** Resume a paused task */
resume(taskId: string): Promise<void>;
/** Check if backend is operational */
isHealthy(): Promise<boolean>;
};
/** Redis client type used by RedisTaskStore */
export type RedisClient = ReturnType<typeof createClient>;
/** Minimal interface for the NeuroLink SDK methods needed by TaskExecutor */
export type NeuroLinkExecutable = {
generate(optionsOrPrompt: unknown): Promise<{
content: string;
toolExecutions?: Array<{
name: string;
input: unknown;
output: unknown;
}>;
usage?: {
input?: number;
output?: number;
};
}>;
};
/** Internal scheduling entry used by NodeTimeoutBackend */
export type ScheduledEntry = {
taskId: string;
executor: TaskExecutorFn;
task: Task;
cronJob?: Cron;
intervalId?: ReturnType<typeof setInterval>;
timeoutId?: ReturnType<typeof setTimeout>;
};
export type TaskBackendName = "bullmq" | "node-timeout";
export type TaskBackendFactoryFn = (config: TaskManagerConfig) => Promise<TaskBackend>;
export type TaskRetentionConfig = {
/** Auto-delete completed tasks after N ms. Default: 30 days */
completedTTL?: number;
/** Auto-delete failed tasks after N ms. Default: 7 days */
failedTTL?: number;
/** Auto-delete cancelled tasks after N ms. Default: 7 days */
cancelledTTL?: number;
/** Auto-expire individual run log entries after N ms. Default: 30 days */
runLogTTL?: number;
};
export type TaskManagerConfig = {
/** Default: true */
enabled?: boolean;
/** Default: "bullmq" */
backend?: TaskBackendName;
redis?: {
host?: string;
port?: number;
password?: string;
db?: number;
/** Alternative: full Redis URL */
url?: string;
};
/** Default: ".neurolink/tasks/tasks.json" */
storePath?: string;
/** Default: ".neurolink/tasks/runs/" */
logsPath?: string;
/** Maximum number of tasks that can exist at once. Default: 100 */
maxTasks?: number;
/** Default: 5 */
maxConcurrentRuns?: number;
/** Max run log entries per task. Default: 2000 */
maxRunLogs?: number;
/** Max continuation history entries per task. Default: 200 (100 exchanges) */
maxHistoryEntries?: number;
taskRetention?: TaskRetentionConfig;
};
export declare const TASK_DEFAULTS: {
readonly enabled: true;
readonly maxTasks: 100;
readonly backend: TaskBackendName;
readonly mode: TaskExecutionMode;
readonly timeout: 120000;
readonly maxConcurrentRuns: 5;
readonly maxRunLogs: 2000;
readonly maxHistoryEntries: 200;
readonly tools: true;
readonly retry: {
readonly maxAttempts: 3;
readonly backoffMs: readonly [30000, 60000, 300000];
};
readonly storePath: ".neurolink/tasks/tasks.json";
readonly logsPath: ".neurolink/tasks/runs/";
readonly redis: {
readonly host: "localhost";
readonly port: 6379;
};
readonly retention: {
readonly completedTTL: number;
readonly failedTTL: number;
readonly cancelledTTL: number;
readonly runLogTTL: number;
};
};
/** State persisted by the CLI task worker daemon */
export type WorkerState = {
pid: number;
startedAt: string;
logFile: string;
};