Class: Pikuri::Thunderbird::ContactSearch

Inherits:
Pikuri::Tool
  • Object
show all
Defined in:
lib/pikuri/thunderbird/contact_search.rb

Overview

The thunderbird_contact_search tool — resolve a person's name (or a partial address) to the email address(es) the user has actually corresponded with, ranked by familiarity. Inbound-only (a pure read, no egress leg), registered whenever Gloda is present — like mail search, and independently useful ("what's Jon's address?").

Its reason to exist is MailCompose: the user says "email Jon Snow a summary," the model has a name and compose needs an address. Rather than invent one (a mis-send / exfil risk) or stop to ask, resolve it against the user's own correspondence graph via Gloda::Contacts#resolve. It returns ranked candidates and never auto-picks — a look-alike sender of received mail can surface, so the human reviewing the To field stays the last line (same posture as ComposeGuard).

Sharing: P_shared_locked — no state of its own, and the Gloda backend it queries locks; see that class's == Sharing.

Constant Summary collapse

DEFAULT_LIMIT =

Returns default / max candidates returned (a short disambiguation list, not a mailbox scan).

Returns:

  • (Integer)

    default / max candidates returned (a short disambiguation list, not a mailbox scan).

5
MAX_LIMIT =
15
DESCRIPTION =

Returns opencode-shape description.

Returns:

  • (String)

    opencode-shape description.

<<~DESC
  Resolve a person's name (or a partial address) to their email address(es), drawn from the user's own Thunderbird correspondence history.

  Usage:
  - Give a name ("Jon Snow") or a fragment ("jon", "acme.com") to find who the user has actually mailed or received mail from.
  - Returns ranked candidates as Name <address> with a familiarity signal — addresses the user has sent mail to rank highest — and never picks one for you.
  - Use it to fill a recipient before drafting mail, then confirm the address with the user: a look-alike sender can appear in received mail, so resolution alone is not proof.
  - Reads Thunderbird's own local index only; it never connects to any server.
DESC

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(backend:) ⇒ ContactSearch

Parameters:



40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/pikuri/thunderbird/contact_search.rb', line 40

def initialize(backend:)
  @backend = backend
  super(
    name: 'thunderbird_contact_search',
    description: DESCRIPTION,
    parameters: Parameters.build { |p|
      p.required_string :query, 'A name or partial address to resolve, e.g. "Jon Snow".'
      p.optional_integer :limit, "Max candidates (default #{DEFAULT_LIMIT}, max #{MAX_LIMIT}), e.g. 5."
    },
    execute: lambda { |query:, limit: DEFAULT_LIMIT|
      ContactSearch.run_search(backend: @backend, query:, limit:)
    },
    trifecta_legs: Pikuri::Thunderbird::INBOUND_LEGS
  )
end

Class Method Details

.run_search(backend:, query:, limit:) ⇒ String

Returns formatted ranked candidates or a no-match line.

Returns:

  • (String)

    formatted ranked candidates or a no-match line.



57
58
59
60
61
62
63
64
# File 'lib/pikuri/thunderbird/contact_search.rb', line 57

def self.run_search(backend:, query:, limit:)
  limit = limit.to_i.clamp(1, MAX_LIMIT)
  candidates = backend.resolve(query:, limit:)
  return "No contacts found matching #{query.inspect}." if candidates.empty?

  header = "#{candidates.size} contact#{candidates.size == 1 ? '' : 's'} (best first):"
  [header, *candidates.map { |c| render(c) }].join("\n\n")
end