scheduleMessageTool function

AgentTool scheduleMessageTool(
  1. ScheduledMessageQueue queue, {
  2. String? senderMailbox()?,
})

Implementation

AgentTool scheduleMessageTool(
  ScheduledMessageQueue queue, {

  /// The calling agent's own mailbox when it is NOT the host's main agent
  /// (gh-970): a subagent scheduling a self-reminder must default to its
  /// OWN mailbox — the queue's `selfMailbox` always resolves the host's
  /// main mailbox, which silently redirected every subagent reminder into
  /// main's inbox. Resolved per call; null (the main agent) keeps the
  /// legacy defaulting. Hosts wire it to the subagent scope, e.g.
  /// `() => activeSubagentId() == null ? null : manager.mailboxOf(...)`.
  String? Function()? senderMailbox,
}) {
  return AgentTool(
    name: 'schedule_message',
    description:
        'Send a delayed message to an agent mailbox (your own by default) '
        '— schedule a follow-up task to check on something later. The '
        'message wakes the recipient when it fires; it survives restarts.',
    parameters: {
      'type': 'object',
      'properties': {
        'text': {
          'type': 'string',
          'description': 'The message to deliver when the timer fires.',
        },
        'delay': {
          'type': 'string',
          'description':
              'How long to wait: 90s / 25m / 2h / 1d (combinable, e.g. '
              '1h30m).',
        },
        'to': {
          'type': 'string',
          'description': 'Recipient mailbox id; defaults to your own mailbox.',
        },
      },
      'required': ['text', 'delay'],
    },
    tier: ApprovalTier.write,
    execute: (args, cancelToken, onUpdate) async {
      final text = args['text'] as String? ?? '';
      final delay = parseDelay(args['delay'] as String? ?? '');
      if (text.trim().isEmpty) {
        return ToolExecutionResult.text('error: text is required');
      }
      if (delay == null) {
        return ToolExecutionResult.text(
          'error: delay must look like 90s / 25m / 2h / 1d',
        );
      }
      final sender = senderMailbox?.call();
      final id = await queue.schedule(
        text: text.trim(),
        delay: delay,
        to: (args['to'] as String?) ?? sender,
        from: sender,
      );
      final due = DateTime.now().add(delay).toIso8601String();
      // CROSS-TOOL CONTRACT: the obligations ledger's pending-wait arming
      // (AgentCliPersist.recordPendingWait) parses the scheduled id out
      // of this line's `scheduled <id> for ` prefix — keep it stable or
      // update both sides together (pinned by
      // test/cli/agent_cli_persist_pending_wait_test.dart).
      return ToolExecutionResult.text(
        'scheduled $id for $due — it will arrive as [scheduled] mail'
        '${sender == null ? '' : ' in $sender'}',
      );
    },
  );
}