Class: Protege::SendEmailTool

Inherits:
Tool
  • Object
show all
Defined in:
app/tools/protege/send_email_tool.rb

Overview

Built-in email tool — the way an agent sends mail, in one of two modes. Subclasses Protege::Tool, so the harness publishes it in the LLM's tool catalog (id :send_email); when the model emits a send_email call, the harness routes the arguments to #use.

From is always enforced to the persona's email_address — the agent cannot impersonate another sender. The mode argument selects behavior:

  • "reply" — continue the current conversation. Subject and threading (+In-Reply-To+ + References) are derived from the inbound message; the subject is the thread's subject, Re: prefixed, NOT a value the model chooses (Gmail and others require a matching subject to thread, so a model-invented subject would split the conversation). The original sender is always a recipient; the model may add more via +to+/+cc+/+bcc+.
  • "new" — start a fresh conversation. The model supplies to and subject (and optional +cc+/+bcc+); no threading headers are set.

Assembly is delegated to Protege::Gateway.build_outbound. The agent may attach files by referencing blob ids — the ids shown in the conversation history, or returned by create_file — resolved through Protege::StoredFile.find and checked against the configured Gateway::AttachmentPolicy limits. (Blob ids currently resolve unscoped; persona scoping is a deferred pass — see the blob-currency spec §9.)

Instance Method Summary collapse

Instance Method Details

#use(context:, mode:, body:, to: [], cc: [], bcc: [], subject: nil, attachments: []) ⇒ Protege::Result

Build the outbound mail for the requested mode and hand it to the gateway for delivery.

Parameters:

  • context (Protege::Orchestrator::Context)

    exposes the inbound message, persona, and deliver

  • mode (String)

    "reply" or "new"

  • body (String)

    plain-text body supplied by the model

  • to (Array<String>) (defaults to: [])

    recipients (required for "new"; additions for "reply")

  • cc (Array<String>) (defaults to: [])

    carbon-copy recipients

  • bcc (Array<String>) (defaults to: [])

    blind-carbon-copy recipients

  • subject (String, nil) (defaults to: nil)

    subject for a "new" email; ignored when replying

  • attachments (Array<Integer>) (defaults to: [])

    blob ids to attach (from history or create_file)

Returns:

  • (Protege::Result)

    success carrying the sent message's id, or a failure (unknown blob, breached limits, nothing to reply to, or a new email missing +to+/+subject+)



91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'app/tools/protege/send_email_tool.rb', line 91

def use(context:, mode:, body:, to: [], cc: [], bcc: [], subject: nil, attachments: [])
  files = resolve_attachments(attachments)
  return files if files.is_a?(Protege::Result) # a failure short-circuits

  mail = build_mail(
    context:, mode:, to:, cc:, bcc:, subject:, body:, attachments: files.map(&:to_mail_attachment)
  )
  return mail if mail.is_a?(Protege::Result) # a validation failure short-circuits

  mail.encoded
  # Hand the blobs to the gateway so the persisted outbound message attaches them by reference
  # (no re-upload) — the mail carries the bytes only for transport.
  context.deliver(mail:, attachments: files.map(&:blob))

  success(message_id: mail.message_id)
end