From 436820b1d43c2e03c1281c16dc97d34e50ee6792 Mon Sep 17 00:00:00 2001 From: Marc Warne Date: Sat, 25 Jul 2026 14:34:09 +0100 Subject: [PATCH] fix: preserve agent for scheduled reminders --- scheduler.ts | 1 + test/integration.test.ts | 18 ++++++++++++++++++ test/scheduler.test.ts | 33 +++++++++++++++++++++++++++++++++ test/types.test.ts | 20 ++++++++++++++++++++ tools/reminderadd.ts | 1 + types.ts | 1 + 6 files changed, 74 insertions(+) diff --git a/scheduler.ts b/scheduler.ts index 94076b8..ea62ada 100644 --- a/scheduler.ts +++ b/scheduler.ts @@ -64,6 +64,7 @@ export async function executeReminder( text: reminder.originalPrompt, }, ], + ...(reminder.agent === undefined ? {} : { agent: reminder.agent }), }, }) diff --git a/test/integration.test.ts b/test/integration.test.ts index 58a4324..5f3e76d 100644 --- a/test/integration.test.ts +++ b/test/integration.test.ts @@ -1,5 +1,6 @@ import { test, expect, describe, beforeEach, afterEach } from "bun:test" import RemindersPlugin from "../index" +import { listReminders } from "../storage" import type { PluginInput } from "@opencode-ai/plugin" import { $ } from "bun" @@ -80,6 +81,23 @@ describe("Integration Tests", () => { expect(result).toContain("File change check") }) + test("reminderadd persists the scheduling agent", async () => { + const plugin = await RemindersPlugin(ctx) + + await plugin.tool!.reminderadd.execute( + { + interval_seconds: 60, + type: "one-time" as const, + action_prompt: "check /workspace/test.txt for changes", + description: "Agent preservation test", + }, + { sessionID: "ses-agent-test", agent: "God" } as any, + ) + + const [reminder] = await listReminders(ctx) + expect(reminder.agent).toBe("God") + }) + test("reminderlist tool returns empty for new session", async () => { const plugin = await RemindersPlugin(ctx) diff --git a/test/scheduler.test.ts b/test/scheduler.test.ts index 0d8533a..486c72a 100644 --- a/test/scheduler.test.ts +++ b/test/scheduler.test.ts @@ -151,10 +151,12 @@ describe("Scheduler", () => { test("executeReminder calls session prompt", async () => { let promptCalled = false let capturedPrompt = "" + let capturedAgent: string | undefined ;(ctx.client.session.prompt as any) = async (opts: any) => { promptCalled = true capturedPrompt = opts.body?.parts?.[0]?.text || "" + capturedAgent = opts.body?.agent return { data: {} as any, error: undefined, response: {} as any } } @@ -166,6 +168,7 @@ describe("Scheduler", () => { interval: 100, originalPrompt: "test prompt text", userDescription: "Execute test", + agent: "God", time: { created: Date.now(), nextExecution: Date.now() + 100, @@ -180,6 +183,36 @@ describe("Scheduler", () => { expect(promptCalled).toBe(true) expect(capturedPrompt).toBe("test prompt text") + expect(capturedAgent).toBe("God") + }) + + test("executeReminder omits agent for legacy reminders", async () => { + let capturedBody: any + + ;(ctx.client.session.prompt as any) = async (opts: any) => { + capturedBody = opts.body + return { data: {} as any, error: undefined, response: {} as any } + } + + const reminder: Reminder = { + id: "rem-legacy-agent-test", + sessionID: "ses-test", + projectID: "test-project-123", + type: "one-time", + interval: 100, + originalPrompt: "legacy prompt text", + userDescription: "Legacy agent test", + time: { + created: Date.now(), + nextExecution: Date.now() + 100, + }, + status: "active", + } + + state.reminders.set(reminder.id, reminder) + await executeReminder(reminder, ctx, state, config) + + expect(capturedBody).not.toHaveProperty("agent") }) test("executeReminder updates lastExecution time", async () => { diff --git a/test/types.test.ts b/test/types.test.ts index bd6e386..617f248 100644 --- a/test/types.test.ts +++ b/test/types.test.ts @@ -21,6 +21,26 @@ describe("Reminder Types", () => { expect(() => ReminderSchema.parse(validReminder)).not.toThrow() }) + test("ReminderSchema allows legacy reminders without an agent", () => { + const legacyReminder = { + id: "test-123", + sessionID: "ses-456", + projectID: "prj-789", + type: "one-time" as const, + interval: 5000, + originalPrompt: "check /workspace/test.txt", + userDescription: "Test reminder", + time: { + created: Date.now(), + nextExecution: Date.now() + 5000, + }, + status: "active" as const, + } + + const parsed = ReminderSchema.parse(legacyReminder) + expect(parsed.agent).toBeUndefined() + }) + test("ReminderSchema rejects invalid type", () => { const invalidReminder = { id: "test-123", diff --git a/tools/reminderadd.ts b/tools/reminderadd.ts index 9e6a9d3..275ba76 100644 --- a/tools/reminderadd.ts +++ b/tools/reminderadd.ts @@ -42,6 +42,7 @@ export function createReminderAddTool( interval: args.interval_seconds * 1000, originalPrompt: args.action_prompt, userDescription: args.description, + agent: context.agent, time: { created: Date.now(), nextExecution: Date.now() + args.interval_seconds * 1000, diff --git a/types.ts b/types.ts index 6807372..5607abd 100644 --- a/types.ts +++ b/types.ts @@ -8,6 +8,7 @@ export const ReminderSchema = z.object({ interval: z.number(), originalPrompt: z.string(), userDescription: z.string(), + agent: z.string().optional(), time: z.object({ created: z.number(), nextExecution: z.number(),