@juspay/neurolink 9.39.0 → 9.41.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/browser/neurolink.min.js +445 -431
  3. package/dist/cli/commands/task.d.ts +56 -0
  4. package/dist/cli/commands/task.js +835 -0
  5. package/dist/cli/parser.js +4 -1
  6. package/dist/lib/neurolink.d.ts +22 -1
  7. package/dist/lib/neurolink.js +195 -14
  8. package/dist/lib/tasks/backends/bullmqBackend.d.ts +32 -0
  9. package/dist/lib/tasks/backends/bullmqBackend.js +189 -0
  10. package/dist/lib/tasks/backends/nodeTimeoutBackend.d.ts +27 -0
  11. package/dist/lib/tasks/backends/nodeTimeoutBackend.js +141 -0
  12. package/dist/lib/tasks/backends/taskBackendRegistry.d.ts +31 -0
  13. package/dist/lib/tasks/backends/taskBackendRegistry.js +66 -0
  14. package/dist/lib/tasks/errors.d.ts +31 -0
  15. package/dist/lib/tasks/errors.js +18 -0
  16. package/dist/lib/tasks/store/fileTaskStore.d.ts +43 -0
  17. package/dist/lib/tasks/store/fileTaskStore.js +179 -0
  18. package/dist/lib/tasks/store/redisTaskStore.d.ts +42 -0
  19. package/dist/lib/tasks/store/redisTaskStore.js +189 -0
  20. package/dist/lib/tasks/taskExecutor.d.ts +21 -0
  21. package/dist/lib/tasks/taskExecutor.js +166 -0
  22. package/dist/lib/tasks/taskManager.d.ts +60 -0
  23. package/dist/lib/tasks/taskManager.js +393 -0
  24. package/dist/lib/tasks/tools/taskTools.d.ts +135 -0
  25. package/dist/lib/tasks/tools/taskTools.js +274 -0
  26. package/dist/lib/types/configTypes.d.ts +3 -0
  27. package/dist/lib/types/generateTypes.d.ts +42 -0
  28. package/dist/lib/types/index.d.ts +2 -1
  29. package/dist/lib/types/streamTypes.d.ts +7 -0
  30. package/dist/lib/types/taskTypes.d.ts +275 -0
  31. package/dist/lib/types/taskTypes.js +37 -0
  32. package/dist/neurolink.d.ts +22 -1
  33. package/dist/neurolink.js +195 -14
  34. package/dist/tasks/backends/bullmqBackend.d.ts +32 -0
  35. package/dist/tasks/backends/bullmqBackend.js +188 -0
  36. package/dist/tasks/backends/nodeTimeoutBackend.d.ts +27 -0
  37. package/dist/tasks/backends/nodeTimeoutBackend.js +140 -0
  38. package/dist/tasks/backends/taskBackendRegistry.d.ts +31 -0
  39. package/dist/tasks/backends/taskBackendRegistry.js +65 -0
  40. package/dist/tasks/errors.d.ts +31 -0
  41. package/dist/tasks/errors.js +17 -0
  42. package/dist/tasks/store/fileTaskStore.d.ts +43 -0
  43. package/dist/tasks/store/fileTaskStore.js +178 -0
  44. package/dist/tasks/store/redisTaskStore.d.ts +42 -0
  45. package/dist/tasks/store/redisTaskStore.js +188 -0
  46. package/dist/tasks/taskExecutor.d.ts +21 -0
  47. package/dist/tasks/taskExecutor.js +165 -0
  48. package/dist/tasks/taskManager.d.ts +60 -0
  49. package/dist/tasks/taskManager.js +392 -0
  50. package/dist/tasks/tools/taskTools.d.ts +135 -0
  51. package/dist/tasks/tools/taskTools.js +273 -0
  52. package/dist/types/configTypes.d.ts +3 -0
  53. package/dist/types/generateTypes.d.ts +42 -0
  54. package/dist/types/index.d.ts +2 -1
  55. package/dist/types/streamTypes.d.ts +7 -0
  56. package/dist/types/taskTypes.d.ts +275 -0
  57. package/dist/types/taskTypes.js +36 -0
  58. package/package.json +4 -2
@@ -0,0 +1,273 @@
1
+ /**
2
+ * Built-in agent tools for TaskManager.
3
+ *
4
+ * These tools allow the AI to self-schedule, manage, and inspect tasks
5
+ * during conversations. Created per-instance via `createTaskTools()` factory,
6
+ * following the same pattern as `createFileTools()` in files/fileTools.ts.
7
+ *
8
+ * @module tasks/tools/taskTools
9
+ */
10
+ import { tool } from "ai";
11
+ import { z } from "zod";
12
+ import { logger } from "../../utils/logger.js";
13
+ import { TaskError } from "../errors.js";
14
+ /**
15
+ * Parse a schedule object from tool input.
16
+ * Accepts: { type: "cron", expression } | { type: "interval", every } | { type: "once", at }
17
+ */
18
+ function parseSchedule(input) {
19
+ const type = input.type;
20
+ if (type === "cron") {
21
+ if (!input.expression || typeof input.expression !== "string") {
22
+ throw TaskError.create("SCHEDULE_FAILED", "Cron schedule requires an 'expression' field");
23
+ }
24
+ return {
25
+ type: "cron",
26
+ expression: input.expression,
27
+ ...(input.timezone ? { timezone: input.timezone } : {}),
28
+ };
29
+ }
30
+ if (type === "interval") {
31
+ if (typeof input.every !== "number" ||
32
+ !isFinite(input.every) ||
33
+ input.every <= 0) {
34
+ throw TaskError.create("SCHEDULE_FAILED", "Interval schedule requires a positive 'every' field (milliseconds)");
35
+ }
36
+ return { type: "interval", every: input.every };
37
+ }
38
+ if (type === "once") {
39
+ if (!input.at) {
40
+ throw TaskError.create("SCHEDULE_FAILED", "Once schedule requires an 'at' field (ISO 8601 date string)");
41
+ }
42
+ return { type: "once", at: input.at };
43
+ }
44
+ throw TaskError.create("SCHEDULE_FAILED", `Invalid schedule type: "${type}". Must be "cron", "interval", or "once".`);
45
+ }
46
+ /**
47
+ * Create task management tools bound to a TaskManager instance.
48
+ *
49
+ * These tools follow the same factory pattern as `createFileTools()` in
50
+ * `src/lib/files/fileTools.ts`. The `manager` is captured via closure,
51
+ * eliminating the need for module-level singleton state.
52
+ *
53
+ * @param manager - The TaskManager instance to bind to
54
+ * @returns Record of tool name to tool definition
55
+ *
56
+ * @example
57
+ * ```typescript
58
+ * const manager = new TaskManager(neurolink, config);
59
+ * const tools = createTaskTools(manager);
60
+ * // tools.createTask, tools.listTasks, tools.getTaskRuns, etc.
61
+ * ```
62
+ */
63
+ export function createTaskTools(manager) {
64
+ return {
65
+ createTask: tool({
66
+ 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.',
67
+ inputSchema: z.object({
68
+ name: z.string().describe("Human-readable task name"),
69
+ prompt: z.string().describe("The prompt to execute on each run"),
70
+ schedule: z
71
+ .object({
72
+ type: z.enum(["cron", "interval", "once"]),
73
+ expression: z
74
+ .string()
75
+ .optional()
76
+ .describe('Cron expression (for type "cron"), e.g. "0 9 * * *"'),
77
+ timezone: z
78
+ .string()
79
+ .optional()
80
+ .describe('IANA timezone for cron, e.g. "America/New_York"'),
81
+ every: z
82
+ .number()
83
+ .optional()
84
+ .describe('Interval in milliseconds (for type "interval")'),
85
+ at: z
86
+ .string()
87
+ .optional()
88
+ .describe('ISO 8601 timestamp (for type "once")'),
89
+ })
90
+ .describe("When to run the task"),
91
+ mode: z
92
+ .enum(["isolated", "continuation"])
93
+ .optional()
94
+ .describe('Execution mode. "isolated" = fresh context per run (default). "continuation" = preserves conversation history across runs.'),
95
+ }),
96
+ execute: async ({ name, prompt, schedule, mode }) => {
97
+ try {
98
+ const parsedSchedule = parseSchedule(schedule);
99
+ const task = await manager.create({
100
+ name,
101
+ prompt,
102
+ schedule: parsedSchedule,
103
+ mode: mode,
104
+ });
105
+ return {
106
+ success: true,
107
+ taskId: task.id,
108
+ name: task.name,
109
+ status: task.status,
110
+ mode: task.mode,
111
+ nextRunAt: task.nextRunAt,
112
+ schedule: task.schedule,
113
+ };
114
+ }
115
+ catch (error) {
116
+ logger.error("[taskTools] createTask failed", {
117
+ error: String(error),
118
+ });
119
+ return {
120
+ success: false,
121
+ error: error instanceof Error ? error.message : String(error),
122
+ };
123
+ }
124
+ },
125
+ }),
126
+ listTasks: tool({
127
+ description: "List all scheduled tasks and their current status.",
128
+ inputSchema: z.object({
129
+ status: z
130
+ .enum([
131
+ "active",
132
+ "paused",
133
+ "completed",
134
+ "failed",
135
+ "cancelled",
136
+ "pending",
137
+ ])
138
+ .optional()
139
+ .describe("Filter by task status"),
140
+ }),
141
+ execute: async ({ status }) => {
142
+ try {
143
+ const tasks = await manager.list(status
144
+ ? {
145
+ status: status,
146
+ }
147
+ : undefined);
148
+ return {
149
+ success: true,
150
+ count: tasks.length,
151
+ tasks: tasks.map((t) => ({
152
+ taskId: t.id,
153
+ name: t.name,
154
+ status: t.status,
155
+ mode: t.mode,
156
+ schedule: t.schedule,
157
+ runCount: t.runCount,
158
+ lastRunAt: t.lastRunAt,
159
+ nextRunAt: t.nextRunAt,
160
+ })),
161
+ };
162
+ }
163
+ catch (error) {
164
+ logger.error("[taskTools] listTasks failed", {
165
+ error: String(error),
166
+ });
167
+ return {
168
+ success: false,
169
+ error: error instanceof Error ? error.message : String(error),
170
+ };
171
+ }
172
+ },
173
+ }),
174
+ getTaskRuns: tool({
175
+ description: "Get the run history of a scheduled task, showing recent executions and their results.",
176
+ inputSchema: z.object({
177
+ taskId: z.string().describe("The task ID"),
178
+ limit: z
179
+ .number()
180
+ .optional()
181
+ .describe("Max results to return (default: 10)"),
182
+ }),
183
+ execute: async ({ taskId, limit }) => {
184
+ try {
185
+ const runs = await manager.runs(taskId, { limit: limit ?? 10 });
186
+ return {
187
+ success: true,
188
+ taskId,
189
+ count: runs.length,
190
+ runs: runs.map((r) => ({
191
+ runId: r.runId,
192
+ status: r.status,
193
+ output: r.output
194
+ ? r.output.length > 500
195
+ ? r.output.slice(0, 500) + "..."
196
+ : r.output
197
+ : undefined,
198
+ durationMs: r.durationMs,
199
+ timestamp: r.timestamp,
200
+ error: r.error,
201
+ })),
202
+ };
203
+ }
204
+ catch (error) {
205
+ logger.error("[taskTools] getTaskRuns failed", {
206
+ error: String(error),
207
+ });
208
+ return {
209
+ success: false,
210
+ error: error instanceof Error ? error.message : String(error),
211
+ };
212
+ }
213
+ },
214
+ }),
215
+ deleteTask: tool({
216
+ description: "Cancel and permanently remove a scheduled task.",
217
+ inputSchema: z.object({
218
+ taskId: z.string().describe("The task ID to delete"),
219
+ }),
220
+ execute: async ({ taskId }) => {
221
+ try {
222
+ const task = await manager.get(taskId);
223
+ if (!task) {
224
+ return { success: false, error: `Task not found: ${taskId}` };
225
+ }
226
+ await manager.delete(taskId);
227
+ return { success: true, deletedTask: task.name, taskId };
228
+ }
229
+ catch (error) {
230
+ logger.error("[taskTools] deleteTask failed", {
231
+ error: String(error),
232
+ });
233
+ return {
234
+ success: false,
235
+ error: error instanceof Error ? error.message : String(error),
236
+ };
237
+ }
238
+ },
239
+ }),
240
+ runTaskNow: tool({
241
+ description: "Immediately execute a scheduled task outside of its normal schedule. Returns the run result.",
242
+ inputSchema: z.object({
243
+ taskId: z.string().describe("The task ID to run"),
244
+ }),
245
+ execute: async ({ taskId }) => {
246
+ try {
247
+ const result = await manager.run(taskId);
248
+ return {
249
+ success: true,
250
+ runId: result.runId,
251
+ status: result.status,
252
+ output: result.output
253
+ ? result.output.length > 1000
254
+ ? result.output.slice(0, 1000) + "..."
255
+ : result.output
256
+ : undefined,
257
+ durationMs: result.durationMs,
258
+ error: result.error,
259
+ };
260
+ }
261
+ catch (error) {
262
+ logger.error("[taskTools] runTaskNow failed", {
263
+ error: String(error),
264
+ });
265
+ return {
266
+ success: false,
267
+ error: error instanceof Error ? error.message : String(error),
268
+ };
269
+ }
270
+ },
271
+ }),
272
+ };
273
+ }
@@ -3,6 +3,7 @@
3
3
  * Centralized configuration type definitions following the established architecture pattern
4
4
  */
5
5
  import { MCPToolRegistry } from "../mcp/toolRegistry.js";
6
+ import type { TaskManagerConfig } from "./taskTypes.js";
6
7
  import type { HITLConfig } from "../types/hitlTypes.js";
7
8
  import type { ConversationMemoryConfig } from "./conversation.js";
8
9
  import type { ObservabilityConfig } from "./observability.js";
@@ -36,6 +37,8 @@ export type NeurolinkConstructorConfig = {
36
37
  mcp?: MCPEnhancementsConfig;
37
38
  /** Authentication provider configuration */
38
39
  auth?: NeuroLinkAuthConfig;
40
+ /** TaskManager configuration (scheduled and self-running tasks) */
41
+ tasks?: TaskManagerConfig;
39
42
  };
40
43
  /**
41
44
  * Configuration for MCP enhancement modules wired into generate()/stream() paths.
@@ -315,10 +315,23 @@ export type GenerateOptions = {
315
315
  context?: StandardRecord;
316
316
  evaluationDomain?: string;
317
317
  toolUsageContext?: string;
318
+ /**
319
+ * @deprecated Use `conversationMessages` instead. This field uses a simple `{role, content}` shape
320
+ * that is not consumed by `buildMessagesArray()` — messages passed here will NOT reach the AI model
321
+ * as proper conversation turns. `conversationMessages` uses the full `ChatMessage` type and is
322
+ * correctly wired through the entire generate pipeline.
323
+ */
318
324
  conversationHistory?: Array<{
319
325
  role: string;
320
326
  content: string;
321
327
  }>;
328
+ /**
329
+ * Previous conversation as a ChatMessage array.
330
+ * Messages are injected as proper multi-turn conversation history before the current prompt,
331
+ * so the AI model sees them as real prior exchanges (not text dumped into the prompt).
332
+ * Used by task continuation mode and available to external callers.
333
+ */
334
+ conversationMessages?: ChatMessage[];
322
335
  factoryConfig?: {
323
336
  domainType?: string;
324
337
  domainConfig?: StandardRecord;
@@ -426,8 +439,37 @@ export type GenerateOptions = {
426
439
  read?: boolean;
427
440
  /** Whether to write (add/condense) the conversation into memory after completion. Defaults to true. */
428
441
  write?: boolean;
442
+ /**
443
+ * Additional users whose memory should be retrieved/stored alongside the primary user.
444
+ * Each entry can override the condensation prompt and maxWords for that user.
445
+ * Primary user is still determined by context.userId.
446
+ */
447
+ additionalUsers?: AdditionalMemoryUser[];
429
448
  };
430
449
  };
450
+ /**
451
+ * Represents an additional user whose memory should be included in a generate/stream call.
452
+ * Allows per-user prompt overrides for different memory condensation strategies
453
+ * (e.g. personal preferences vs org-level policies).
454
+ */
455
+ export type AdditionalMemoryUser = {
456
+ /** The user/owner ID to retrieve or store memory for. */
457
+ userId: string;
458
+ /**
459
+ * Human-readable label used in the formatted memory context.
460
+ * E.g. "Organization Policy", "Team Context", "User Preferences".
461
+ * If not provided, defaults to userId.
462
+ */
463
+ label?: string;
464
+ /** Whether to read this user's memory and include in context. Defaults to true. */
465
+ read?: boolean;
466
+ /** Whether to write conversation into this user's memory. Defaults to true. */
467
+ write?: boolean;
468
+ /** Custom condensation prompt for this user. Overrides the default Hippocampus prompt. */
469
+ prompt?: string;
470
+ /** Max words for this user's condensed memory. Overrides the default maxWords. */
471
+ maxWords?: number;
472
+ };
431
473
  /**
432
474
  * Generate function result type - Primary output format
433
475
  * Future-ready for multi-modal outputs while maintaining text focus
@@ -22,7 +22,7 @@ export type { DomainConfig, DomainConfigOptions, DomainEvaluationCriteria, Domai
22
22
  export * from "./evaluation.js";
23
23
  export * from "./evaluationProviders.js";
24
24
  export * from "./fileTypes.js";
25
- export type { EnhancedGenerateResult, EnhancedProvider, FactoryEnhancedProvider, GenerateOptions, GenerateResult as GenerateApiResult, // Renamed to avoid conflict with cli.js GenerateResult
25
+ export type { AdditionalMemoryUser, EnhancedGenerateResult, EnhancedProvider, FactoryEnhancedProvider, GenerateOptions, GenerateResult as GenerateApiResult, // Renamed to avoid conflict with cli.js GenerateResult
26
26
  TextGenerationOptions, TextGenerationResult, UnifiedGenerationOptions, } from "./generateTypes.js";
27
27
  export * from "./hitlTypes.js";
28
28
  export * from "./middlewareTypes.js";
@@ -46,3 +46,4 @@ export type { ClientConfig, RequestOptions as ClientRequestOptions, RetryConfig
46
46
  export type { TokenRefresher } from "./subscriptionTypes.js";
47
47
  export * from "./proxyTypes.js";
48
48
  export type { AuthProviderType, AuthProviderConfig, MastraAuthProvider, BetterAuthConfig, Auth0Config, ClerkConfig, FirebaseConfig, SupabaseConfig, WorkOSConfig, JWTConfig, OAuth2Config, CognitoConfig, KeycloakConfig, CustomAuthConfig, BaseAuthProviderConfig, AuthUser, AuthSession, TokenType, TokenValidationResult as AuthTokenValidationResult, TokenClaims, JWK, JWKS, TokenRefreshResult, TokenValidationConfig, TokenExtractionConfig, SessionValidationResult, SessionStorage, AuthorizationResult, AuthRequestContext, AuthenticatedContext, TokenExtractionStrategy, SessionConfig, SessionStorageType, RBACConfig, PermissionDefinition, AuthCacheConfig, AuthMiddlewareOptions, AuthMiddlewareConfig, RBACMiddlewareConfig, AuthErrorCode, AuthErrorInfo, AuthErrorInfo as AuthErrorType, AuthEventType, AuthEventData, AuthEventHandler, AuthProviderFactoryFn, AuthProviderRegistration, AuthHealthCheck, AuthProviderHealthCheck, AuthEvents, AuthProviderMetadata, AuthProviderHealthStatus, AuthTokenValidator, AuthUserAuthorizer, AuthSessionManager, AuthRequestHandler, AuthUserManager, AuthLifecycle, } from "./authTypes.js";
49
+ export type { Task, TaskDefinition, TaskSchedule, TaskScheduleType, CronSchedule, IntervalSchedule, OnceSchedule, TaskExecutionMode, TaskStatus, TaskRunResult, TaskRunError, TaskStore, TaskBackend, TaskBackendName, TaskManagerConfig, TaskRetentionConfig, ConversationEntry as TaskConversationEntry, } from "./taskTypes.js";
@@ -10,6 +10,7 @@ import type { Content, ImageWithAltText } from "./content.js";
10
10
  import type { ChatMessage } from "./conversation.js";
11
11
  import type { AIModelProviderConfig } from "./providers.js";
12
12
  import type { TTSChunk, TTSOptions } from "./ttsTypes.js";
13
+ import type { AdditionalMemoryUser } from "./generateTypes.js";
13
14
  import type { StandardRecord, ValidationSchema } from "./typeAliases.js";
14
15
  /**
15
16
  * Progress tracking and metadata for streaming operations
@@ -435,6 +436,12 @@ export type StreamOptions = {
435
436
  read?: boolean;
436
437
  /** Whether to write (add/condense) the conversation into memory after completion. Defaults to true. */
437
438
  write?: boolean;
439
+ /**
440
+ * Additional users whose memory should be retrieved/stored alongside the primary user.
441
+ * Each entry can override the condensation prompt and maxWords for that user.
442
+ * Primary user is still determined by context.userId.
443
+ */
444
+ additionalUsers?: AdditionalMemoryUser[];
438
445
  };
439
446
  };
440
447
  /**
@@ -0,0 +1,275 @@
1
+ /**
2
+ * Type definitions for the NeuroLink TaskManager system.
3
+ *
4
+ * TaskManager provides scheduled and self-running task capabilities,
5
+ * enabling AI agents to execute prompts on cron, interval, or one-shot schedules.
6
+ */
7
+ import type { Cron } from "croner";
8
+ import type { createClient } from "redis";
9
+ import type { ThinkingLevel } from "./configTypes.js";
10
+ export type TaskScheduleType = "cron" | "interval" | "once";
11
+ export type CronSchedule = {
12
+ type: "cron";
13
+ /** Standard 5-field cron expression, e.g. "0 9 * * *" */
14
+ expression: string;
15
+ /** IANA timezone, e.g. "America/New_York" */
16
+ timezone?: string;
17
+ };
18
+ export type IntervalSchedule = {
19
+ type: "interval";
20
+ /** Interval in milliseconds */
21
+ every: number;
22
+ };
23
+ export type OnceSchedule = {
24
+ type: "once";
25
+ /** ISO 8601 timestamp or Date object */
26
+ at: Date | string;
27
+ };
28
+ export type TaskSchedule = CronSchedule | IntervalSchedule | OnceSchedule;
29
+ /**
30
+ * - "isolated": Each run gets a fresh context. No memory of previous runs.
31
+ * - "continuation": Conversation history is preserved across runs.
32
+ */
33
+ export type TaskExecutionMode = "isolated" | "continuation";
34
+ export type TaskStatus = "pending" | "active" | "paused" | "completed" | "failed" | "cancelled";
35
+ export type TaskDefinition = {
36
+ name: string;
37
+ prompt: string;
38
+ schedule: TaskSchedule;
39
+ mode?: TaskExecutionMode;
40
+ provider?: string;
41
+ model?: string;
42
+ thinkingLevel?: ThinkingLevel;
43
+ systemPrompt?: string;
44
+ /** Enable/disable tools for this task. Default: true */
45
+ tools?: boolean;
46
+ maxTokens?: number;
47
+ temperature?: number;
48
+ /** Max number of executions. Omit for unlimited. */
49
+ maxRuns?: number;
50
+ /** Per-run timeout in ms. Default: 120000 */
51
+ timeout?: number;
52
+ retry?: {
53
+ /** Default: 3 */
54
+ maxAttempts?: number;
55
+ /** Default: [30000, 60000, 300000] */
56
+ backoffMs?: number[];
57
+ };
58
+ onSuccess?: (result: TaskRunResult) => void | Promise<void>;
59
+ onError?: (error: TaskRunError) => void | Promise<void>;
60
+ /** Called when task reaches a terminal state (completed, failed, cancelled) */
61
+ onComplete?: (task: Task) => void | Promise<void>;
62
+ metadata?: Record<string, unknown>;
63
+ };
64
+ export type Task = {
65
+ id: string;
66
+ name: string;
67
+ prompt: string;
68
+ schedule: TaskSchedule;
69
+ mode: TaskExecutionMode;
70
+ status: TaskStatus;
71
+ provider?: string;
72
+ model?: string;
73
+ thinkingLevel?: ThinkingLevel;
74
+ systemPrompt?: string;
75
+ tools: boolean;
76
+ maxTokens?: number;
77
+ temperature?: number;
78
+ maxRuns?: number;
79
+ timeout: number;
80
+ retry: {
81
+ maxAttempts: number;
82
+ backoffMs: number[];
83
+ };
84
+ runCount: number;
85
+ lastRunAt?: string;
86
+ nextRunAt?: string;
87
+ createdAt: string;
88
+ updatedAt: string;
89
+ /** Conversation session ID for continuation mode */
90
+ sessionId?: string;
91
+ metadata?: Record<string, unknown>;
92
+ };
93
+ /** Shape of the tasks.json file used by FileTaskStore */
94
+ export type TasksFile = {
95
+ version: number;
96
+ tasks: Record<string, Task>;
97
+ };
98
+ export type TaskRunResult = {
99
+ taskId: string;
100
+ runId: string;
101
+ status: "success" | "error";
102
+ /** AI response text */
103
+ output?: string;
104
+ toolCalls?: Array<{
105
+ name: string;
106
+ input: unknown;
107
+ output: unknown;
108
+ }>;
109
+ tokensUsed?: {
110
+ input: number;
111
+ output: number;
112
+ };
113
+ durationMs: number;
114
+ /** ISO 8601 */
115
+ timestamp: string;
116
+ error?: string;
117
+ };
118
+ export type TaskRunError = {
119
+ taskId: string;
120
+ runId: string;
121
+ error: string;
122
+ attempt: number;
123
+ maxAttempts: number;
124
+ willRetry: boolean;
125
+ /** ISO 8601 */
126
+ timestamp: string;
127
+ };
128
+ /**
129
+ * Abstracts task persistence. Auto-selected based on backend:
130
+ * - BullMQ → RedisTaskStore
131
+ * - NodeTimeout → FileTaskStore
132
+ */
133
+ export interface TaskStore {
134
+ readonly type: "redis" | "file";
135
+ initialize(): Promise<void>;
136
+ shutdown(): Promise<void>;
137
+ save(task: Task): Promise<void>;
138
+ get(taskId: string): Promise<Task | null>;
139
+ list(filter?: {
140
+ status?: TaskStatus;
141
+ }): Promise<Task[]>;
142
+ update(taskId: string, updates: Partial<Task>): Promise<Task>;
143
+ delete(taskId: string): Promise<void>;
144
+ appendRun(taskId: string, run: TaskRunResult): Promise<void>;
145
+ getRuns(taskId: string, options?: {
146
+ limit?: number;
147
+ status?: string;
148
+ }): Promise<TaskRunResult[]>;
149
+ appendHistory(taskId: string, messages: ConversationEntry[]): Promise<void>;
150
+ getHistory(taskId: string): Promise<ConversationEntry[]>;
151
+ clearHistory(taskId: string): Promise<void>;
152
+ }
153
+ export type ConversationEntry = {
154
+ role: "user" | "assistant";
155
+ content: string;
156
+ timestamp: string;
157
+ };
158
+ export type TaskExecutorFn = (task: Task) => Promise<TaskRunResult>;
159
+ /**
160
+ * Abstracts the scheduling/looping mechanism.
161
+ * Implementations: BullMQ (production), NodeTimeout (development).
162
+ */
163
+ export interface TaskBackend {
164
+ readonly name: string;
165
+ initialize(): Promise<void>;
166
+ shutdown(): Promise<void>;
167
+ /** Schedule a task for execution */
168
+ schedule(task: Task, executor: TaskExecutorFn): Promise<void>;
169
+ /** Cancel a scheduled task */
170
+ cancel(taskId: string): Promise<void>;
171
+ /** Pause a task's schedule */
172
+ pause(taskId: string): Promise<void>;
173
+ /** Resume a paused task */
174
+ resume(taskId: string): Promise<void>;
175
+ /** Check if backend is operational */
176
+ isHealthy(): Promise<boolean>;
177
+ }
178
+ /** Redis client type used by RedisTaskStore */
179
+ export type RedisClient = ReturnType<typeof createClient>;
180
+ /** Minimal interface for the NeuroLink SDK methods needed by TaskExecutor */
181
+ export type NeuroLinkExecutable = {
182
+ generate(optionsOrPrompt: unknown): Promise<{
183
+ content: string;
184
+ toolExecutions?: Array<{
185
+ name: string;
186
+ input: unknown;
187
+ output: unknown;
188
+ }>;
189
+ usage?: {
190
+ input?: number;
191
+ output?: number;
192
+ };
193
+ }>;
194
+ };
195
+ /** Internal scheduling entry used by NodeTimeoutBackend */
196
+ export type ScheduledEntry = {
197
+ taskId: string;
198
+ executor: TaskExecutorFn;
199
+ task: Task;
200
+ cronJob?: Cron;
201
+ intervalId?: ReturnType<typeof setInterval>;
202
+ timeoutId?: ReturnType<typeof setTimeout>;
203
+ };
204
+ export type TaskBackendName = "bullmq" | "node-timeout";
205
+ export type TaskBackendFactoryFn = (config: TaskManagerConfig) => Promise<TaskBackend>;
206
+ export type TaskRetentionConfig = {
207
+ /** Auto-delete completed tasks after N ms. Default: 30 days */
208
+ completedTTL?: number;
209
+ /** Auto-delete failed tasks after N ms. Default: 7 days */
210
+ failedTTL?: number;
211
+ /** Auto-delete cancelled tasks after N ms. Default: 7 days */
212
+ cancelledTTL?: number;
213
+ /** Auto-expire individual run log entries after N ms. Default: 30 days */
214
+ runLogTTL?: number;
215
+ };
216
+ export type TaskManagerConfig = {
217
+ /** Default: true */
218
+ enabled?: boolean;
219
+ /** Default: "bullmq" */
220
+ backend?: TaskBackendName;
221
+ redis?: {
222
+ host?: string;
223
+ port?: number;
224
+ password?: string;
225
+ db?: number;
226
+ /** Alternative: full Redis URL */
227
+ url?: string;
228
+ };
229
+ /** Default: ".neurolink/tasks/tasks.json" */
230
+ storePath?: string;
231
+ /** Default: ".neurolink/tasks/runs/" */
232
+ logsPath?: string;
233
+ /** Maximum number of tasks that can exist at once. Default: 100 */
234
+ maxTasks?: number;
235
+ /** Default: 5 */
236
+ maxConcurrentRuns?: number;
237
+ /** Max run log entries per task. Default: 2000 */
238
+ maxRunLogs?: number;
239
+ /** Max continuation history entries per task. Default: 200 (100 exchanges) */
240
+ maxHistoryEntries?: number;
241
+ taskRetention?: TaskRetentionConfig;
242
+ };
243
+ export declare const TASK_DEFAULTS: {
244
+ readonly enabled: true;
245
+ readonly maxTasks: 100;
246
+ readonly backend: TaskBackendName;
247
+ readonly mode: TaskExecutionMode;
248
+ readonly timeout: 120000;
249
+ readonly maxConcurrentRuns: 5;
250
+ readonly maxRunLogs: 2000;
251
+ readonly maxHistoryEntries: 200;
252
+ readonly tools: true;
253
+ readonly retry: {
254
+ readonly maxAttempts: 3;
255
+ readonly backoffMs: readonly [30000, 60000, 300000];
256
+ };
257
+ readonly storePath: ".neurolink/tasks/tasks.json";
258
+ readonly logsPath: ".neurolink/tasks/runs/";
259
+ readonly redis: {
260
+ readonly host: "localhost";
261
+ readonly port: 6379;
262
+ };
263
+ readonly retention: {
264
+ readonly completedTTL: number;
265
+ readonly failedTTL: number;
266
+ readonly cancelledTTL: number;
267
+ readonly runLogTTL: number;
268
+ };
269
+ };
270
+ /** State persisted by the CLI task worker daemon */
271
+ export type WorkerState = {
272
+ pid: number;
273
+ startedAt: string;
274
+ logFile: string;
275
+ };