diff --git a/packages/builtin-tool-cron/src/helpers.ts b/packages/builtin-tool-cron/src/helpers.ts new file mode 100644 index 0000000000..543ddbc98d --- /dev/null +++ b/packages/builtin-tool-cron/src/helpers.ts @@ -0,0 +1,25 @@ +import type { CronJobSummaryForContext } from './types'; + +const formatCronJob = (job: CronJobSummaryForContext): string => { + const status = job.enabled ? 'enabled' : 'disabled'; + const execInfo = + job.remainingExecutions != null ? `${job.remainingExecutions} remaining` : 'unlimited'; + const lastRun = job.lastExecutedAt ?? 'never'; + const desc = job.description ? ` - ${job.description}` : ''; + + return ` - ${job.name || 'Unnamed'} (id: ${job.id}): ${job.cronPattern} [${job.timezone}] [${status}, ${execInfo}, ${job.totalExecutions} completed, last run: ${lastRun}]${desc}`; +}; + +export const generateCronJobsList = (jobs: CronJobSummaryForContext[], total?: number): string => { + if (jobs.length === 0) { + return 'No scheduled tasks configured for this agent.'; + } + + const lines = jobs.map(formatCronJob); + + if (total && total > jobs.length) { + lines.push(` (showing ${jobs.length} of ${total} tasks — use listCronJobs to see all)`); + } + + return lines.join('\n'); +}; diff --git a/packages/builtin-tool-cron/src/index.ts b/packages/builtin-tool-cron/src/index.ts index c6ad95cb5a..fb62eb03d5 100644 --- a/packages/builtin-tool-cron/src/index.ts +++ b/packages/builtin-tool-cron/src/index.ts @@ -1,4 +1,5 @@ export { CronExecutionRuntime, type ICronService } from './ExecutionRuntime'; +export { generateCronJobsList } from './helpers'; export { CronIdentifier, CronManifest } from './manifest'; export { systemPrompt } from './systemRole'; export { diff --git a/packages/builtin-tool-cron/src/systemRole.ts b/packages/builtin-tool-cron/src/systemRole.ts index 28ab37d901..ddea4fc5d0 100644 --- a/packages/builtin-tool-cron/src/systemRole.ts +++ b/packages/builtin-tool-cron/src/systemRole.ts @@ -4,6 +4,7 @@ export const systemPrompt = `You have access to a LobeHub Scheduled Tasks Tool. Current user: {{username}} Session date: {{date}} Current agent: {{agent_id}} +User timezone: {{timezone}} diff --git a/src/services/chat/mecha/contextEngineering.ts b/src/services/chat/mecha/contextEngineering.ts index 71c9301a1f..a4265549c3 100644 --- a/src/services/chat/mecha/contextEngineering.ts +++ b/src/services/chat/mecha/contextEngineering.ts @@ -2,6 +2,11 @@ import { LobeActivatorIdentifier } from '@lobechat/builtin-tool-activator'; import { AgentBuilderIdentifier } from '@lobechat/builtin-tool-agent-builder'; import { AgentManagementIdentifier } from '@lobechat/builtin-tool-agent-management'; import { CredsIdentifier, type CredSummary, generateCredsList } from '@lobechat/builtin-tool-creds'; +import { + CronIdentifier, + type CronJobSummaryForContext, + generateCronJobsList, +} from '@lobechat/builtin-tool-cron'; import { GroupAgentBuilderIdentifier } from '@lobechat/builtin-tool-group-agent-builder'; import { GTDIdentifier } from '@lobechat/builtin-tool-gtd'; import { WebOnboardingIdentifier } from '@lobechat/builtin-tool-web-onboarding'; @@ -377,6 +382,42 @@ export const contextEngineering = async ({ } } + // Resolve cron jobs context for cron tool + // Only inject a small preview (up to 4) to save context window; + // the model can call listCronJobs API for the full list. + const isCronEnabled = tools?.includes(CronIdentifier) ?? false; + let cronJobsList: CronJobSummaryForContext[] | undefined; + let cronJobsTotal = 0; + + if (isCronEnabled && agentId) { + try { + const cronResult = await lambdaClient.agentCronJob.list.query({ agentId, limit: 4 }); + const jobs = (cronResult as any)?.data ?? []; + cronJobsTotal = (cronResult as any)?.pagination?.total ?? jobs.length; + cronJobsList = jobs.map( + (job: any): CronJobSummaryForContext => ({ + cronPattern: job.cronPattern, + description: job.description, + enabled: job.enabled, + id: job.id, + lastExecutedAt: job.lastExecutedAt, + name: job.name, + remainingExecutions: job.remainingExecutions, + timezone: job.timezone ?? 'UTC', + totalExecutions: job.totalExecutions ?? 0, + }), + ); + log( + 'Cron jobs context resolved: count=%d, total=%d', + cronJobsList?.length ?? 0, + cronJobsTotal, + ); + } catch (error) { + // Silently fail - cron context is optional + log('Failed to resolve cron jobs context:', error); + } + } + const userMemoryConfig = enableUserMemories && userMemoryData ? { @@ -694,6 +735,8 @@ export const contextEngineering = async ({ ...VARIABLE_GENERATORS, // NOTICE: required by builtin-tool-creds/src/systemRole.ts CREDS_LIST: () => (credsList ? generateCredsList(credsList) : ''), + // NOTICE: required by builtin-tool-cron/src/systemRole.ts + CRON_JOBS_LIST: () => (cronJobsList ? generateCronJobsList(cronJobsList, cronJobsTotal) : ''), // NOTICE(@nekomeowww): required by builtin-tool-memory/src/systemRole.ts memory_effort: () => (userMemoryConfig ? (memoryContext?.effort ?? '') : ''), // Current agent + topic identity — referenced by the LobeHub builtin