Add context_mode option for scheduled tasks

Scheduled tasks can now run in either:
- "group" mode: uses the group's conversation session for context
- "isolated" mode: runs with a fresh session (previous behavior)

The tool description guides the agent on when to use each mode and
prompts them to ask the user if unclear. Group mode is now the default.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Gavriel
2026-02-01 22:23:38 +02:00
parent f6e7f7aca9
commit 572338b9a6
5 changed files with 40 additions and 6 deletions

View File

@@ -64,6 +64,11 @@ export function initDatabase(): void {
try {
db.exec(`ALTER TABLE messages ADD COLUMN sender_name TEXT`);
} catch { /* column already exists */ }
// Add context_mode column if it doesn't exist (migration for existing DBs)
try {
db.exec(`ALTER TABLE scheduled_tasks ADD COLUMN context_mode TEXT DEFAULT 'isolated'`);
} catch { /* column already exists */ }
}
/**
@@ -131,8 +136,8 @@ export function getMessagesSince(chatJid: string, sinceTimestamp: string): NewMe
export function createTask(task: Omit<ScheduledTask, 'last_run' | 'last_result'>): void {
db.prepare(`
INSERT INTO scheduled_tasks (id, group_folder, chat_jid, prompt, schedule_type, schedule_value, next_run, status, created_at)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
INSERT INTO scheduled_tasks (id, group_folder, chat_jid, prompt, schedule_type, schedule_value, context_mode, next_run, status, created_at)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
`).run(
task.id,
task.group_folder,
@@ -140,6 +145,7 @@ export function createTask(task: Omit<ScheduledTask, 'last_run' | 'last_result'>
task.prompt,
task.schedule_type,
task.schedule_value,
task.context_mode || 'isolated',
task.next_run,
task.status,
task.created_at

View File

@@ -237,6 +237,7 @@ async function processTaskIpc(
prompt?: string;
schedule_type?: string;
schedule_value?: string;
context_mode?: string;
groupFolder?: string;
chatJid?: string;
},
@@ -295,6 +296,9 @@ async function processTaskIpc(
}
const taskId = `task-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
const contextMode = (data.context_mode === 'group' || data.context_mode === 'isolated')
? data.context_mode
: 'isolated';
createTask({
id: taskId,
group_folder: targetGroup,
@@ -302,11 +306,12 @@ async function processTaskIpc(
prompt: data.prompt,
schedule_type: scheduleType,
schedule_value: data.schedule_value,
context_mode: contextMode,
next_run: nextRun,
status: 'active',
created_at: new Date().toISOString()
});
logger.info({ taskId, sourceGroup, targetGroup }, 'Task created via IPC');
logger.info({ taskId, sourceGroup, targetGroup, contextMode }, 'Task created via IPC');
}
break;
@@ -388,7 +393,11 @@ async function connectWhatsApp(): Promise<void> {
}
} else if (connection === 'open') {
logger.info('Connected to WhatsApp');
startSchedulerLoop({ sendMessage, registeredGroups: () => registeredGroups });
startSchedulerLoop({
sendMessage,
registeredGroups: () => registeredGroups,
getSessions: () => sessions
});
startIpcWatcher();
startMessageLoop();
}

View File

@@ -15,6 +15,7 @@ const logger = pino({
export interface SchedulerDependencies {
sendMessage: (jid: string, text: string) => Promise<void>;
registeredGroups: () => Record<string, RegisteredGroup>;
getSessions: () => Record<string, string>;
}
async function runTask(task: ScheduledTask, deps: SchedulerDependencies): Promise<void> {
@@ -56,9 +57,14 @@ async function runTask(task: ScheduledTask, deps: SchedulerDependencies): Promis
let result: string | null = null;
let error: string | null = null;
// For group context mode, use the group's current session
const sessions = deps.getSessions();
const sessionId = task.context_mode === 'group' ? sessions[task.group_folder] : undefined;
try {
const output = await runContainerAgent(group, {
prompt: task.prompt,
sessionId,
groupFolder: task.group_folder,
chatJid: task.chat_jid,
isMain,

View File

@@ -38,6 +38,7 @@ export interface ScheduledTask {
prompt: string;
schedule_type: 'cron' | 'interval' | 'once';
schedule_value: string;
context_mode: 'group' | 'isolated';
next_run: string | null;
last_run: string | null;
last_result: string | null;