78 lines
2.5 KiB
TypeScript
78 lines
2.5 KiB
TypeScript
/**
|
|
* Agent-scoped durable one-shot and fixed-rate reminders over the session event log.
|
|
* @module @deepseek-ai/dsh-tool-schedule
|
|
*/
|
|
|
|
import type { Context } from '@deepseek-ai/cordis'
|
|
import type { Agent } from '@deepseek-ai/dsh-agent'
|
|
import type {} from '@deepseek-ai/dsh-session-persistence'
|
|
import { ScheduleOwner } from './runtime.ts'
|
|
import { registerScheduleTools } from './tools.ts'
|
|
|
|
export type * from './types.ts'
|
|
export {
|
|
SCHEDULE_CHANGE_VERSION,
|
|
MIN_EVERY_INTERVAL_SECONDS,
|
|
ScheduleId,
|
|
ScheduleInputError,
|
|
ScheduleLogError,
|
|
allocateScheduleId,
|
|
createAfterScheduleRecord,
|
|
createAtScheduleRecord,
|
|
createEveryScheduleRecord,
|
|
decodeScheduleChange,
|
|
foldScheduleEvents,
|
|
renderReminderFraming,
|
|
renderEveryReminderBatchFraming,
|
|
resolveEveryOccurrence,
|
|
scheduleView,
|
|
} from './domain.ts'
|
|
export { registerScheduleTools } from './tools.ts'
|
|
|
|
/** Cordis function-plugin name. */
|
|
export const name = 'tool-schedule'
|
|
/** Services required before future root agents can receive Schedule. */
|
|
export const inject = ['agents', 'sessions', 'tools', 'sessionPersistence']
|
|
|
|
type OwnerCleanup = () => void | Promise<void>
|
|
|
|
/** Install Schedule only for root agents published after this plugin loads. */
|
|
export function apply(ctx: Context): void {
|
|
const owners = new Map<Agent, OwnerCleanup>()
|
|
let stopping = false
|
|
|
|
ctx.effect(() => {
|
|
const stopCreated = ctx.on('agent/created', ({ agent }) => {
|
|
if (stopping || owners.has(agent) || !ctx.agents.roots().includes(agent)) return
|
|
const owner = new ScheduleOwner(ctx, agent)
|
|
const cleanup: OwnerCleanup = agent.ctx.effect(() => {
|
|
const disposeTools = registerScheduleTools(ctx, agent.ctx, agent, () => { owner.requestDrive() })
|
|
const stopStatus = agent.ctx.on('agent/status', ({ status }) => {
|
|
if (status === 'idle' && agent.session.events.some(event => event.type === 'schedule/change')) {
|
|
owner.requestDrive()
|
|
}
|
|
})
|
|
owner.start()
|
|
return async () => {
|
|
stopStatus()
|
|
disposeTools()
|
|
try {
|
|
await owner.dispose()
|
|
} finally {
|
|
if (owners.get(agent) === cleanup) owners.delete(agent)
|
|
}
|
|
}
|
|
}, 'tool-schedule.owner()')
|
|
owners.set(agent, cleanup)
|
|
})
|
|
|
|
return async () => {
|
|
stopping = true
|
|
stopCreated()
|
|
const cleanups = [...owners.values()]
|
|
owners.clear()
|
|
await Promise.allSettled(cleanups.map(cleanup => Promise.resolve(cleanup())))
|
|
}
|
|
}, 'tool-schedule.lifecycle()')
|
|
}
|