Class: Pikuri::Mcp::Thinker

Inherits:
Object
  • Object
show all
Defined in:
lib/pikuri/mcp/thinker.rb

Overview

One-shot LLM pass for the MCP boot-time checks: Synthesizer (description summarization) and Verifier (injection check) call #call with a self-contained prompt and get the model’s reply back as a plain String. Each call constructs a fresh tools-free Agent, runs the prompt as its single turn, and closes it — fresh per call deliberately, so per-server prompts don’t accumulate in one shared chat history and cross-contaminate. The construction cost is noise next to the LLM round-trip, and Cache short-circuits before #call fires anyway.

No listeners (boot passes are silent), no step limit (no tools are wired, so the model has nothing to tick).

Cancellation

cancellable is checked once before each call — the “gentle cancel” semantic: a flag flipped between calls raises promptly; the in-flight HTTP call itself is not interrupted. It is deliberately NOT passed into the one-shot agent: Agent#run_loop resets its cancellable at the turn boundary, which would erase a pending Ctrl+C instead of honoring it (and a tools-free non-streaming turn has no check points anyway).

Failure

Errors from the provider propagate to the caller verbatim —no recovery layer here. Synthesizer rescues at its level and falls back to a default; Verifier lets them bubble.

Constant Summary collapse

SYSTEM_PROMPT =

System prompt for the one-shot agents. The real instructions (synthesis framing, verification rubric) live in the prompt Synthesizer / Verifier build and send as the user turn, so this stays generic.

'You are a one-shot analysis pass inside an agent boot sequence. ' \
'Follow the instructions in the user message exactly and reply ' \
'with only what they ask for — no preamble.'

Instance Method Summary collapse

Constructor Details

#initialize(transport:, cancellable: nil) ⇒ Thinker

Returns a new instance of Thinker.

Parameters:

  • transport (Pikuri::Agent::ChatTransport)

    the model-resolution triple every one-shot agent is constructed with — typically the host agent’s own, so boot passes run against the same model.

  • cancellable (Pikuri::Agent::Control::Cancellable, nil) (defaults to: nil)

    when set, checked before each #call so a boot-time Ctrl+C aborts startup on the next pass.

Raises:

  • (ArgumentError)

    when transport is nil



53
54
55
56
57
58
# File 'lib/pikuri/mcp/thinker.rb', line 53

def initialize(transport:, cancellable: nil)
  raise ArgumentError, 'transport must not be nil' if transport.nil?

  @transport = transport
  @cancellable = cancellable
end

Instance Method Details

#call(prompt) ⇒ String

Run one prompt through a fresh tools-free agent.

Parameters:

  • prompt (String)

    self-contained instructions + data, sent as the single user turn

Returns:

  • (String)

    the assistant’s reply content (+“”+ when the provider produced no assistant message)

Raises:

  • (Pikuri::Agent::Control::Cancellable::Cancelled)

    when the cancellable flag was tripped at the pre-call check



69
70
71
72
73
74
75
76
77
78
# File 'lib/pikuri/mcp/thinker.rb', line 69

def call(prompt)
  @cancellable&.check!
  agent = Pikuri::Agent.new(transport: @transport, system_prompt: SYSTEM_PROMPT)
  begin
    agent.run_loop(user_message: prompt)
    agent.last_assistant_content.to_s
  ensure
    agent.close
  end
end