Module: Pikuri
- Defined in:
- lib/pikuri-core.rb,
lib/pikuri/tool.rb,
lib/pikuri/agent.rb,
lib/pikuri/paths.rb,
lib/pikuri/testing.rb,
lib/pikuri/version.rb,
lib/pikuri/trifecta.rb,
lib/pikuri/extractor.rb,
lib/pikuri/file_type.rb,
lib/pikuri/sanitizer.rb,
lib/pikuri/url_cache.rb,
lib/pikuri/finalizers.rb,
lib/pikuri/subprocess.rb,
lib/pikuri/tool/fetch.rb,
lib/pikuri/agent/event.rb,
lib/pikuri/bundler_env.rb,
lib/pikuri/tool/scraper.rb,
lib/pikuri/agent/control.rb,
lib/pikuri/agent/history.rb,
lib/pikuri/trifecta/node.rb,
lib/pikuri/agent/listener.rb,
lib/pikuri/extractor/html.rb,
lib/pikuri/agent/extension.rb,
lib/pikuri/tool/calculator.rb,
lib/pikuri/tool/parameters.rb,
lib/pikuri/tool/search/exa.rb,
lib/pikuri/tool/web_scrape.rb,
lib/pikuri/tool/web_search.rb,
lib/pikuri/trifecta/report.rb,
lib/pikuri/ruby_llm_patches.rb,
lib/pikuri/agent/synthesizer.rb,
lib/pikuri/tool/search/brave.rb,
lib/pikuri/agent/configurator.rb,
lib/pikuri/tool/search/result.rb,
lib/pikuri/tool/trifecta_legs.rb,
lib/pikuri/agent/listener_list.rb,
lib/pikuri/tool/search/engines.rb,
lib/pikuri/agent/chat_transport.rb,
lib/pikuri/tool/execute_context.rb,
lib/pikuri/extractor/passthrough.rb,
lib/pikuri/trifecta/contribution.rb,
lib/pikuri/tool/search/duckduckgo.rb,
lib/pikuri/agent/extension_context.rb,
lib/pikuri/agent/listener/terminal.rb,
lib/pikuri/agent/control/interloper.rb,
lib/pikuri/agent/control/step_limit.rb,
lib/pikuri/agent/listener/token_log.rb,
lib/pikuri/tool/search/rate_limiter.rb,
lib/pikuri/agent/control/cancellable.rb,
lib/pikuri/agent/listener/rate_limited.rb,
lib/pikuri/agent/context_window_detector.rb,
lib/pikuri/agent/listener/in_memory_event_list.rb
Overview
Boot file: configures the Zeitwerk autoloader for pikuri-core/lib/pikuri/
and eager-loads it, so after require 'pikuri-core' every constant
pikuri-core ships is defined. Sibling gems set up their own loaders into the
same Pikuri:: namespace.
The Pikuri module also owns the logging surface (Pikuri.logger_for, Pikuri.log_io=,
the PIKURI_LOG / PIKURI_LOG_<NAME> env vars): each subsystem holds a
memoized Logger writing through a shared IO that Pikuri.log_io= swaps in one shot.
Why eager-load
The stateless bundled tools (+Tool::CALCULATOR+, Tool::WEB_SCRAPE,
Tool::FETCH) are ALL_CAPS value constants, and Zeitwerk only auto-loads
constants matching its filename↔CamelCase convention. Eager-loading runs the
files defining those values so a bin script can c.add_tool them without
per-file require. (web_search is host-configured via
Tool::WebSearch.build, so it's not a value constant.) Cost: a few ms.
Defined Under Namespace
Modules: BundlerEnv, Extractor, FileType, Finalizers, Paths, RubyLlmPatches, Sanitizer, Testing, Trifecta Classes: Agent, Subprocess, Tool, UrlCache
Constant Summary collapse
- PROMPT_DIRS =
Search path for bundled system prompts. Mutable: each pikuri gem appends its own
prompts/at boot, soPikuri.prompt(name)from a host requiringpikuri-codefindscoding-system-prompt.txtthere. Public so a downstream user can read pikuri's prompts as a starting point; prefer prompt. [File.('../prompts', __dir__)]
- LOG_LEVELS =
Mapping from
PIKURI_LOGenv-var values (lowercased) to Logger level constants. Anything else falls back toINFO. { 'debug' => Logger::DEBUG, 'info' => Logger::INFO, 'warn' => Logger::WARN, 'error' => Logger::ERROR, 'fatal' => Logger::FATAL }.freeze
- Loader =
Zeitwerk loader for every constant under
pikuri-core/lib/pikuri/. A constant (not block-scoped) so a downstream host can add ignore rules without monkey-patching. Sibling gems set up their own loaders. Zeitwerk::Loader.new
- VERSION =
Gem version, advertised in
pikuri.gemspec. Bump on every release following semver: patch for bug fixes, minor for backward-compatible additions to the public surface (+Pikuri::Tool+ /Pikuri::Agent/ listeners / bundled tools), major for breaking changes to that surface or to thebin/pikuri-*CLIs. '0.1.0'
Class Attribute Summary collapse
-
.log_io ⇒ IO
Shared sink every Pikuri.logger_for writes through.
Class Method Summary collapse
-
.logger_for(name) ⇒ Logger
Memoized Logger tagged with
nameas itsprogname. -
.prompt(name) ⇒ String
Read a bundled prompt by basename, searching PROMPT_DIRS in order (+.txt+ auto-appended; Symbols accepted).
-
.prompts(*names) ⇒ String
Read several bundled prompts and join them into one system prompt — the way a binary assembles a base prompt plus shared fragments (e.g. the tool-loop hygiene in
agent-loop.txt).
Class Attribute Details
.log_io ⇒ IO
Returns shared sink every logger_for writes through.
56 57 58 |
# File 'lib/pikuri-core.rb', line 56 def log_io @log_io end |
Class Method Details
.logger_for(name) ⇒ Logger
Memoized Logger tagged with name as its progname. Level resolves
PIKURI_LOG_<NAME> → PIKURI_LOG → INFO. Repeated calls with the same
name return the same instance, so log_io= can rewire them all.
84 85 86 87 88 89 90 91 |
# File 'lib/pikuri-core.rb', line 84 def logger_for(name) @log_loggers[name] ||= begin lg = Logger.new(@log_io, progname: name) override = ENV["PIKURI_LOG_#{name.upcase}"].to_s.downcase lg.level = LOG_LEVELS.fetch(override, @log_default) lg end end |
.prompt(name) ⇒ String
Read a bundled prompt by basename, searching PROMPT_DIRS in order
(+.txt+ auto-appended; Symbols accepted). For downstream users
bootstrapping their own Agent wiring from pikuri's defaults.
103 104 105 106 107 108 109 110 111 112 |
# File 'lib/pikuri-core.rb', line 103 def prompt(name) basename = name.to_s basename += '.txt' unless basename.end_with?('.txt') PROMPT_DIRS.each do |dir| path = File.join(dir, basename) return File.read(path) if File.exist?(path) end available = PROMPT_DIRS.flat_map { |dir| Dir.exist?(dir) ? Dir.children(dir) : [] }.sort.uniq raise ArgumentError, "Unknown pikuri prompt #{name.inspect}; available: #{available.join(', ')}" end |
.prompts(*names) ⇒ String
Read several bundled prompts and join them into one system prompt —
the way a binary assembles a base prompt plus shared fragments (e.g.
the tool-loop hygiene in agent-loop.txt).
system_prompt = Pikuri.prompts(:'pikuri-chat', :'agent-loop')
system_prompt += "\n\nCurrent date: #{...}" # dynamic tail, still one blank line
Each fragment is right-stripped before joining with a single blank
line, and the result carries no trailing newline — so neither the
fragment seams nor a later +"\n\n"+-prefixed append double-blanks,
regardless of the .txt files' own trailing newlines.
129 130 131 |
# File 'lib/pikuri-core.rb', line 129 def prompts(*names) names.map { |name| prompt(name).rstrip }.join("\n\n") end |