pikuri 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +62 -0
- data/GETTING_STARTED.md +223 -0
- data/LICENSE +21 -0
- data/README.md +193 -0
- data/lib/pikuri/agent/chat_transport.rb +41 -0
- data/lib/pikuri/agent/context_window_detector.rb +101 -0
- data/lib/pikuri/agent/listener/in_memory_message_list.rb +33 -0
- data/lib/pikuri/agent/listener/message_listener.rb +93 -0
- data/lib/pikuri/agent/listener/step_limit.rb +97 -0
- data/lib/pikuri/agent/listener/terminal.rb +137 -0
- data/lib/pikuri/agent/listener/token_log.rb +166 -0
- data/lib/pikuri/agent/listener_list.rb +113 -0
- data/lib/pikuri/agent/message.rb +61 -0
- data/lib/pikuri/agent/synthesizer.rb +120 -0
- data/lib/pikuri/agent/tokens.rb +56 -0
- data/lib/pikuri/agent.rb +286 -0
- data/lib/pikuri/subprocess.rb +166 -0
- data/lib/pikuri/tool/bash.rb +272 -0
- data/lib/pikuri/tool/calculator.rb +82 -0
- data/lib/pikuri/tool/confirmer.rb +96 -0
- data/lib/pikuri/tool/edit.rb +196 -0
- data/lib/pikuri/tool/fetch.rb +167 -0
- data/lib/pikuri/tool/glob.rb +310 -0
- data/lib/pikuri/tool/grep.rb +338 -0
- data/lib/pikuri/tool/parameters.rb +314 -0
- data/lib/pikuri/tool/read.rb +254 -0
- data/lib/pikuri/tool/scraper/fetch_error.rb +16 -0
- data/lib/pikuri/tool/scraper/html.rb +285 -0
- data/lib/pikuri/tool/scraper/pdf.rb +54 -0
- data/lib/pikuri/tool/scraper/simple.rb +177 -0
- data/lib/pikuri/tool/search/brave.rb +184 -0
- data/lib/pikuri/tool/search/duckduckgo.rb +196 -0
- data/lib/pikuri/tool/search/engines.rb +154 -0
- data/lib/pikuri/tool/search/exa.rb +217 -0
- data/lib/pikuri/tool/search/rate_limiter.rb +92 -0
- data/lib/pikuri/tool/search/result.rb +29 -0
- data/lib/pikuri/tool/skill.rb +80 -0
- data/lib/pikuri/tool/skill_catalog.rb +376 -0
- data/lib/pikuri/tool/sub_agent.rb +102 -0
- data/lib/pikuri/tool/web_scrape.rb +117 -0
- data/lib/pikuri/tool/web_search.rb +38 -0
- data/lib/pikuri/tool/workspace.rb +150 -0
- data/lib/pikuri/tool/write.rb +170 -0
- data/lib/pikuri/tool.rb +118 -0
- data/lib/pikuri/url_cache.rb +106 -0
- data/lib/pikuri/version.rb +10 -0
- data/lib/pikuri.rb +165 -0
- data/prompts/coding-system-prompt.txt +28 -0
- data/prompts/pikuri-chat.txt +15 -0
- metadata +259 -0
data/lib/pikuri.rb
ADDED
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'logger'
|
|
4
|
+
require 'zeitwerk'
|
|
5
|
+
|
|
6
|
+
# +Pikuri::VERSION+ lives in its own tiny file so the gemspec can read
|
|
7
|
+
# the version constant via +require_relative+ at build time without
|
|
8
|
+
# loading Zeitwerk and every runtime dep. Requiring it here makes the
|
|
9
|
+
# constant available to ordinary +require 'pikuri'+ callers too —
|
|
10
|
+
# without this line, Zeitwerk's ignore-rule below would leave
|
|
11
|
+
# +Pikuri::VERSION+ undefined for anyone using the installed gem.
|
|
12
|
+
require_relative 'pikuri/version'
|
|
13
|
+
|
|
14
|
+
# Boot file: configures the Zeitwerk autoloader for every file under
|
|
15
|
+
# +lib/pikuri/+ and eager-loads them all. After +require 'pikuri'+,
|
|
16
|
+
# every constant pikuri ships (+Pikuri::Agent+, +Pikuri::Tool+,
|
|
17
|
+
# +Pikuri::Tool::Calculator+, +Pikuri::Tool::Scraper::HTML+, ...) is
|
|
18
|
+
# defined and resolvable.
|
|
19
|
+
#
|
|
20
|
+
# Beyond loading, the +Pikuri+ module owns the logging surface — see
|
|
21
|
+
# {.logger_for}, {.log_io=}, and the +PIKURI_LOG+ /
|
|
22
|
+
# +PIKURI_LOG_<NAME>+ env vars. Each subsystem holds its own
|
|
23
|
+
# memoized +Logger+, all writing through a shared IO that
|
|
24
|
+
# {.log_io=} can swap in one shot (handy in tests, daemons, or
|
|
25
|
+
# anywhere stderr isn't the right sink).
|
|
26
|
+
#
|
|
27
|
+
# == Why eager-load
|
|
28
|
+
#
|
|
29
|
+
# Tool implementations (+Pikuri::Tool::CALCULATOR+,
|
|
30
|
+
# +Pikuri::Tool::WEB_SEARCH+, +Pikuri::Tool::WEB_SCRAPE+,
|
|
31
|
+
# +Pikuri::Tool::FETCH+) are +ALL_CAPS+ value constants rather than
|
|
32
|
+
# classes/modules, and Zeitwerk only auto-loads constants that match
|
|
33
|
+
# its filename-↔-CamelCase convention. Eager-loading at boot guarantees
|
|
34
|
+
# the files defining those values run, so the bin script can splat them
|
|
35
|
+
# straight into +Pikuri::Agent.new(tools: [...])+ without per-file
|
|
36
|
+
# +require+ ceremony. The cost is a few milliseconds of startup —
|
|
37
|
+
# negligible compared to a single LLM round-trip.
|
|
38
|
+
module Pikuri
|
|
39
|
+
# Absolute path to the directory holding pikuri's bundled system
|
|
40
|
+
# prompts (+pikuri-chat.txt+, +coding-system-prompt.txt+). Resolves
|
|
41
|
+
# correctly both in a source checkout and in an installed gem because
|
|
42
|
+
# +__dir__+ tracks the file's actual location either way; the gem
|
|
43
|
+
# ships +prompts/+ as a sibling of +lib/+ so the same relative jump
|
|
44
|
+
# works.
|
|
45
|
+
#
|
|
46
|
+
# Exposed publicly so a downstream library user can read pikuri's
|
|
47
|
+
# prompts as a starting point for their own system prompt (or use
|
|
48
|
+
# them verbatim). Prefer {.prompt} for the common case of loading
|
|
49
|
+
# one by name; reach for this constant only if you need the
|
|
50
|
+
# directory itself (e.g. to list available prompts).
|
|
51
|
+
#
|
|
52
|
+
# @return [String]
|
|
53
|
+
PROMPTS_DIR = File.expand_path('../prompts', __dir__)
|
|
54
|
+
|
|
55
|
+
# Mapping from +PIKURI_LOG+ env-var values (lowercased) to
|
|
56
|
+
# {Logger} level constants. Anything else falls back to +INFO+.
|
|
57
|
+
#
|
|
58
|
+
# @return [Hash{String=>Integer}]
|
|
59
|
+
LOG_LEVELS = {
|
|
60
|
+
'debug' => Logger::DEBUG,
|
|
61
|
+
'info' => Logger::INFO,
|
|
62
|
+
'warn' => Logger::WARN,
|
|
63
|
+
'error' => Logger::ERROR,
|
|
64
|
+
'fatal' => Logger::FATAL
|
|
65
|
+
}.freeze
|
|
66
|
+
|
|
67
|
+
@log_io = $stderr
|
|
68
|
+
@log_loggers = {} # name → Logger; lets {.log_io=} rewire all of them
|
|
69
|
+
@log_default = LOG_LEVELS.fetch(ENV['PIKURI_LOG'].to_s.downcase, Logger::INFO)
|
|
70
|
+
|
|
71
|
+
class << self
|
|
72
|
+
# @return [IO] shared sink every {.logger_for} writes through
|
|
73
|
+
attr_reader :log_io
|
|
74
|
+
|
|
75
|
+
# Swap the shared sink (e.g. a +StringIO+ in tests, a file in a
|
|
76
|
+
# daemon). Re-points every logger already handed out by
|
|
77
|
+
# {.logger_for} so callers don't have to re-fetch them.
|
|
78
|
+
#
|
|
79
|
+
# Why we don't use +Logger#reopen+: that method closes the previous
|
|
80
|
+
# sink before installing the new one, which makes "swap to a
|
|
81
|
+
# capture +StringIO+, then swap back to the original" impossible —
|
|
82
|
+
# the original handle would be dead the second time around. Instead
|
|
83
|
+
# we swap each logger's +@logdev+ to a fresh +Logger::LogDevice+
|
|
84
|
+
# over the new +io+, leaving the previous device untouched so the
|
|
85
|
+
# caller can hand the same +IO+ back in later. This uses a documented
|
|
86
|
+
# but internal Logger ivar; if a future Ruby renames it the
|
|
87
|
+
# +Engines+ logging specs will fail loudly.
|
|
88
|
+
#
|
|
89
|
+
# @param io [IO] new sink for every Pikuri logger
|
|
90
|
+
# @return [IO]
|
|
91
|
+
def log_io=(io)
|
|
92
|
+
@log_io = io
|
|
93
|
+
@log_loggers.each_value do |lg|
|
|
94
|
+
lg.instance_variable_set(:@logdev, Logger::LogDevice.new(io))
|
|
95
|
+
end
|
|
96
|
+
io
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# Memoized {Logger} tagged with +name+ in its +progname+, so each
|
|
100
|
+
# subsystem's lines stand out in the shared sink. Level resolves
|
|
101
|
+
# in this order: +PIKURI_LOG_<NAME>+ (e.g. +PIKURI_LOG_ENGINES=debug+),
|
|
102
|
+
# then +PIKURI_LOG+, then +INFO+.
|
|
103
|
+
#
|
|
104
|
+
# Repeated calls with the same +name+ return the same instance so
|
|
105
|
+
# there is one logger per subsystem and {.log_io=} can rewire them
|
|
106
|
+
# all in one shot.
|
|
107
|
+
#
|
|
108
|
+
# @param name [String] subsystem tag (rendered as +progname+)
|
|
109
|
+
# @return [Logger]
|
|
110
|
+
def logger_for(name)
|
|
111
|
+
@log_loggers[name] ||= begin
|
|
112
|
+
lg = Logger.new(@log_io, progname: name)
|
|
113
|
+
override = ENV["PIKURI_LOG_#{name.upcase}"].to_s.downcase
|
|
114
|
+
lg.level = LOG_LEVELS.fetch(override, @log_default)
|
|
115
|
+
lg
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# Read a bundled prompt by basename. +name+ is matched against the
|
|
120
|
+
# files in {PROMPTS_DIR}; a +.txt+ extension is auto-appended if
|
|
121
|
+
# absent. Symbols are accepted as a convenience (+:pikuri-chat+ /
|
|
122
|
+
# +'pikuri-chat'+ / +'pikuri-chat.txt'+ all resolve to the same file).
|
|
123
|
+
#
|
|
124
|
+
# Intended for downstream library users who want to bootstrap their
|
|
125
|
+
# own +Pikuri::Agent+ wiring from pikuri's defaults — read the
|
|
126
|
+
# prompt, customize the bits they care about, hand the result to
|
|
127
|
+
# +Agent.new(system_prompt: ...)+.
|
|
128
|
+
#
|
|
129
|
+
# @example
|
|
130
|
+
# chat_prompt = Pikuri.prompt(:'pikuri-chat')
|
|
131
|
+
# agent = Pikuri::Agent.new(system_prompt: chat_prompt, ...)
|
|
132
|
+
#
|
|
133
|
+
# @param name [String, Symbol] basename of the prompt file
|
|
134
|
+
# @return [String] file contents
|
|
135
|
+
# @raise [ArgumentError] if no matching file exists in {PROMPTS_DIR}
|
|
136
|
+
def prompt(name)
|
|
137
|
+
basename = name.to_s
|
|
138
|
+
basename += '.txt' unless basename.end_with?('.txt')
|
|
139
|
+
path = File.join(PROMPTS_DIR, basename)
|
|
140
|
+
unless File.exist?(path)
|
|
141
|
+
available = Dir.children(PROMPTS_DIR).sort.join(', ')
|
|
142
|
+
raise ArgumentError, "Unknown pikuri prompt #{name.inspect}; available: #{available}"
|
|
143
|
+
end
|
|
144
|
+
File.read(path)
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
Loader = Zeitwerk::Loader.new
|
|
149
|
+
Loader.tag = 'pikuri'
|
|
150
|
+
Loader.push_dir(File.expand_path('.', __dir__))
|
|
151
|
+
Loader.ignore(__FILE__)
|
|
152
|
+
# +lib/pikuri/version.rb+ defines +Pikuri::VERSION+ (an ALL_CAPS value
|
|
153
|
+
# constant), not +Pikuri::Version+ as Zeitwerk would expect from the
|
|
154
|
+
# filename — so tell the loader to skip it. The file is +require_relative+'d
|
|
155
|
+
# at the top of this file (and also by the gemspec at build time), so
|
|
156
|
+
# the constant is defined before Zeitwerk runs.
|
|
157
|
+
Loader.ignore(File.expand_path('pikuri/version.rb', __dir__))
|
|
158
|
+
Loader.inflector.inflect(
|
|
159
|
+
'html' => 'HTML',
|
|
160
|
+
'pdf' => 'PDF',
|
|
161
|
+
'duckduckgo' => 'DuckDuckGo'
|
|
162
|
+
)
|
|
163
|
+
Loader.setup
|
|
164
|
+
Loader.eager_load
|
|
165
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
You are an expert coding assistant who reads, edits, and runs code via tools to solve software engineering tasks.
|
|
2
|
+
|
|
3
|
+
You operate on the local filesystem under a workspace directory. All file-touching tools resolve paths within that workspace; trying to escape returns an error. The `bash` and `write` tools may prompt the user for confirmation before running — if they decline, accept it and don't retry the same operation.
|
|
4
|
+
|
|
5
|
+
You have access to tools described in the API's tool list. To call one, use the standard tool-call mechanism — do not write tool calls as text.
|
|
6
|
+
|
|
7
|
+
If several next steps are independent (e.g. reading two unrelated files, or running unrelated checks), emit them as parallel tool calls in a single turn rather than one at a time.
|
|
8
|
+
|
|
9
|
+
Choosing a tool:
|
|
10
|
+
- File reading: `read` for a known path, `grep` to search file contents by pattern, `glob` to find files by name pattern. Do NOT use `bash` for these (no `cat`, `sed`, `awk`, `rg`, `find`) — the dedicated tools respect the workspace and produce cleaner output.
|
|
11
|
+
- Editing: `edit` for surgical changes — its `old_string` argument must match exact bytes, so always `read` the target file first. Use `write` for new files, or for wholesale rewrites of existing files (which will prompt the user for confirmation).
|
|
12
|
+
- Running things: `bash` for tests, builds, git, scripts, and other shell commands. Briefly explain non-trivial commands before running them.
|
|
13
|
+
- Research: `web_search`, `web_scrape`, `fetch` for stack traces, library docs, current API references — prefer local source via `read` / `grep` when the information is already in the workspace. `sub_agent` to delegate research that would otherwise blow up your context (full-codebase audits, multi-page reading).
|
|
14
|
+
- `calculator` for arithmetic beyond simple mental math.
|
|
15
|
+
|
|
16
|
+
Working on code:
|
|
17
|
+
- Look at neighboring files first — match the existing conventions, library choices, naming, and comment style.
|
|
18
|
+
- Make the smallest change that does the job. Don't refactor, rename, or add features beyond what was asked.
|
|
19
|
+
- If you're unsure how a piece of code is used, `grep` for its callers before editing it.
|
|
20
|
+
- After a substantive change, run the project's tests or build if you can locate them (look at README, package.json, Cargo.toml, Makefile, build.gradle, Gemfile, etc.).
|
|
21
|
+
- Don't add ceremonial comments. Match the surrounding code's commenting style.
|
|
22
|
+
- NEVER commit, push, or open a PR unless the user explicitly asks.
|
|
23
|
+
|
|
24
|
+
Other guidelines:
|
|
25
|
+
- Don't repeat a tool call with identical arguments — re-read the previous observation instead.
|
|
26
|
+
- On a tool error (observation starting with `Error:`): use the data you already have to continue if you can. If you can't, reply to the user that you weren't able to complete the task and briefly say why (e.g. "the test runner isn't on PATH", "the file is outside the workspace"). Do not retry the same call hoping for a different result, and do not loop on rephrased variants of the same failing call.
|
|
27
|
+
- Reference code with `file_path:line_number` so the user can navigate (e.g. `lib/agent.rb:42`).
|
|
28
|
+
- When the task is done, reply in plain text with no tool call — a short summary of what changed and any next steps the user should consider. That is how you finish.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
You are an expert assistant who solves tasks by calling tools when needed.
|
|
2
|
+
|
|
3
|
+
You have access to tools described in the API's tool list. To call one, use the standard tool-call mechanism — do not write tool calls as text.
|
|
4
|
+
|
|
5
|
+
If several next steps are independent (e.g. two unrelated lookups), emit them as parallel tool calls in a single turn rather than one at a time.
|
|
6
|
+
|
|
7
|
+
Choosing a tool:
|
|
8
|
+
- Default to `web_search` whenever a question asks for a specific fact about a named entity — company HQs and headcounts, product versions and release dates, prices, people's bios and roles, anything tying a proper noun to a specific attribute — and for anything time-sensitive or obscure. Your training will *feel* certain on these and is often wrong; check rather than guess. One well-chosen search beats three exploratory ones.
|
|
9
|
+
- Use `calculator` for any arithmetic beyond simple mental math. Don't search the web for "what is X * Y".
|
|
10
|
+
- Reply directly, without any tool, for language and translation, definitions of common terms, and widely-known general history.
|
|
11
|
+
|
|
12
|
+
Other guidelines:
|
|
13
|
+
- Don't repeat a tool call with identical arguments — re-read the previous observation instead.
|
|
14
|
+
- On a tool error (observation starting with `Error:`): use the data you already have to answer if you can. If you can't, reply to the user that you weren't able to find the answer and briefly say why (e.g. "web search hit a rate limit", "the page wasn't reachable"). Do not retry the same call hoping for a different result, and do not loop on rephrased variants of the same failing call.
|
|
15
|
+
- When you have the answer, reply in plain text with no tool call. That is how you finish.
|
metadata
ADDED
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: pikuri
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.0.1
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Martin Vysny
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2026-05-14 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: dentaku
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - "~>"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '3.5'
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - "~>"
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '3.5'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: faraday
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - "~>"
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '2.9'
|
|
34
|
+
type: :runtime
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - "~>"
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '2.9'
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: nokogiri
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - "~>"
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '1.19'
|
|
48
|
+
type: :runtime
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - "~>"
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '1.19'
|
|
55
|
+
- !ruby/object:Gem::Dependency
|
|
56
|
+
name: pdf-reader
|
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
|
58
|
+
requirements:
|
|
59
|
+
- - "~>"
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: '2.15'
|
|
62
|
+
type: :runtime
|
|
63
|
+
prerelease: false
|
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - "~>"
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: '2.15'
|
|
69
|
+
- !ruby/object:Gem::Dependency
|
|
70
|
+
name: rainbow
|
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
|
72
|
+
requirements:
|
|
73
|
+
- - "~>"
|
|
74
|
+
- !ruby/object:Gem::Version
|
|
75
|
+
version: '3.1'
|
|
76
|
+
type: :runtime
|
|
77
|
+
prerelease: false
|
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
79
|
+
requirements:
|
|
80
|
+
- - "~>"
|
|
81
|
+
- !ruby/object:Gem::Version
|
|
82
|
+
version: '3.1'
|
|
83
|
+
- !ruby/object:Gem::Dependency
|
|
84
|
+
name: reverse_markdown
|
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
|
86
|
+
requirements:
|
|
87
|
+
- - "~>"
|
|
88
|
+
- !ruby/object:Gem::Version
|
|
89
|
+
version: '3.0'
|
|
90
|
+
type: :runtime
|
|
91
|
+
prerelease: false
|
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
93
|
+
requirements:
|
|
94
|
+
- - "~>"
|
|
95
|
+
- !ruby/object:Gem::Version
|
|
96
|
+
version: '3.0'
|
|
97
|
+
- !ruby/object:Gem::Dependency
|
|
98
|
+
name: ruby-readability
|
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
|
100
|
+
requirements:
|
|
101
|
+
- - "~>"
|
|
102
|
+
- !ruby/object:Gem::Version
|
|
103
|
+
version: '0.7'
|
|
104
|
+
type: :runtime
|
|
105
|
+
prerelease: false
|
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
107
|
+
requirements:
|
|
108
|
+
- - "~>"
|
|
109
|
+
- !ruby/object:Gem::Version
|
|
110
|
+
version: '0.7'
|
|
111
|
+
- !ruby/object:Gem::Dependency
|
|
112
|
+
name: ruby_llm
|
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
|
114
|
+
requirements:
|
|
115
|
+
- - "~>"
|
|
116
|
+
- !ruby/object:Gem::Version
|
|
117
|
+
version: '1.15'
|
|
118
|
+
type: :runtime
|
|
119
|
+
prerelease: false
|
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
121
|
+
requirements:
|
|
122
|
+
- - "~>"
|
|
123
|
+
- !ruby/object:Gem::Version
|
|
124
|
+
version: '1.15'
|
|
125
|
+
- !ruby/object:Gem::Dependency
|
|
126
|
+
name: tsort
|
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
|
128
|
+
requirements:
|
|
129
|
+
- - "~>"
|
|
130
|
+
- !ruby/object:Gem::Version
|
|
131
|
+
version: '0.2'
|
|
132
|
+
type: :runtime
|
|
133
|
+
prerelease: false
|
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
135
|
+
requirements:
|
|
136
|
+
- - "~>"
|
|
137
|
+
- !ruby/object:Gem::Version
|
|
138
|
+
version: '0.2'
|
|
139
|
+
- !ruby/object:Gem::Dependency
|
|
140
|
+
name: tty-markdown
|
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
|
142
|
+
requirements:
|
|
143
|
+
- - "~>"
|
|
144
|
+
- !ruby/object:Gem::Version
|
|
145
|
+
version: '0.7'
|
|
146
|
+
type: :runtime
|
|
147
|
+
prerelease: false
|
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
149
|
+
requirements:
|
|
150
|
+
- - "~>"
|
|
151
|
+
- !ruby/object:Gem::Version
|
|
152
|
+
version: '0.7'
|
|
153
|
+
- !ruby/object:Gem::Dependency
|
|
154
|
+
name: zeitwerk
|
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
|
156
|
+
requirements:
|
|
157
|
+
- - "~>"
|
|
158
|
+
- !ruby/object:Gem::Version
|
|
159
|
+
version: '2.7'
|
|
160
|
+
type: :runtime
|
|
161
|
+
prerelease: false
|
|
162
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
163
|
+
requirements:
|
|
164
|
+
- - "~>"
|
|
165
|
+
- !ruby/object:Gem::Version
|
|
166
|
+
version: '2.7'
|
|
167
|
+
description: |
|
|
168
|
+
A library for assembling AI assistants: Pikuri::Agent (a thin wrapper around
|
|
169
|
+
ruby_llm's chat loop), Pikuri::Tool with strict argument validation, a
|
|
170
|
+
listener surface for rendering / budgets / sub-agents, and a small set of
|
|
171
|
+
bundled tools (calculator, web search, web scrape, fetch, plus six coding
|
|
172
|
+
tools: read / write / edit / grep / glob / bash). Downstream projects
|
|
173
|
+
(notably the planned pikuri-tui) wire these into actual binaries. The repo
|
|
174
|
+
also ships `bin/pikuri-chat` and `bin/pikuri-code` as demo entry points,
|
|
175
|
+
but they are NOT installed by `gem install pikuri` — they exist to show
|
|
176
|
+
how to wire the library together and to support development.
|
|
177
|
+
email:
|
|
178
|
+
- martin@vysny.me
|
|
179
|
+
executables: []
|
|
180
|
+
extensions: []
|
|
181
|
+
extra_rdoc_files: []
|
|
182
|
+
files:
|
|
183
|
+
- CHANGELOG.md
|
|
184
|
+
- GETTING_STARTED.md
|
|
185
|
+
- LICENSE
|
|
186
|
+
- README.md
|
|
187
|
+
- lib/pikuri.rb
|
|
188
|
+
- lib/pikuri/agent.rb
|
|
189
|
+
- lib/pikuri/agent/chat_transport.rb
|
|
190
|
+
- lib/pikuri/agent/context_window_detector.rb
|
|
191
|
+
- lib/pikuri/agent/listener/in_memory_message_list.rb
|
|
192
|
+
- lib/pikuri/agent/listener/message_listener.rb
|
|
193
|
+
- lib/pikuri/agent/listener/step_limit.rb
|
|
194
|
+
- lib/pikuri/agent/listener/terminal.rb
|
|
195
|
+
- lib/pikuri/agent/listener/token_log.rb
|
|
196
|
+
- lib/pikuri/agent/listener_list.rb
|
|
197
|
+
- lib/pikuri/agent/message.rb
|
|
198
|
+
- lib/pikuri/agent/synthesizer.rb
|
|
199
|
+
- lib/pikuri/agent/tokens.rb
|
|
200
|
+
- lib/pikuri/subprocess.rb
|
|
201
|
+
- lib/pikuri/tool.rb
|
|
202
|
+
- lib/pikuri/tool/bash.rb
|
|
203
|
+
- lib/pikuri/tool/calculator.rb
|
|
204
|
+
- lib/pikuri/tool/confirmer.rb
|
|
205
|
+
- lib/pikuri/tool/edit.rb
|
|
206
|
+
- lib/pikuri/tool/fetch.rb
|
|
207
|
+
- lib/pikuri/tool/glob.rb
|
|
208
|
+
- lib/pikuri/tool/grep.rb
|
|
209
|
+
- lib/pikuri/tool/parameters.rb
|
|
210
|
+
- lib/pikuri/tool/read.rb
|
|
211
|
+
- lib/pikuri/tool/scraper/fetch_error.rb
|
|
212
|
+
- lib/pikuri/tool/scraper/html.rb
|
|
213
|
+
- lib/pikuri/tool/scraper/pdf.rb
|
|
214
|
+
- lib/pikuri/tool/scraper/simple.rb
|
|
215
|
+
- lib/pikuri/tool/search/brave.rb
|
|
216
|
+
- lib/pikuri/tool/search/duckduckgo.rb
|
|
217
|
+
- lib/pikuri/tool/search/engines.rb
|
|
218
|
+
- lib/pikuri/tool/search/exa.rb
|
|
219
|
+
- lib/pikuri/tool/search/rate_limiter.rb
|
|
220
|
+
- lib/pikuri/tool/search/result.rb
|
|
221
|
+
- lib/pikuri/tool/skill.rb
|
|
222
|
+
- lib/pikuri/tool/skill_catalog.rb
|
|
223
|
+
- lib/pikuri/tool/sub_agent.rb
|
|
224
|
+
- lib/pikuri/tool/web_scrape.rb
|
|
225
|
+
- lib/pikuri/tool/web_search.rb
|
|
226
|
+
- lib/pikuri/tool/workspace.rb
|
|
227
|
+
- lib/pikuri/tool/write.rb
|
|
228
|
+
- lib/pikuri/url_cache.rb
|
|
229
|
+
- lib/pikuri/version.rb
|
|
230
|
+
- prompts/coding-system-prompt.txt
|
|
231
|
+
- prompts/pikuri-chat.txt
|
|
232
|
+
homepage: https://codeberg.org/mvysny/pikuri
|
|
233
|
+
licenses:
|
|
234
|
+
- MIT
|
|
235
|
+
metadata:
|
|
236
|
+
source_code_uri: https://codeberg.org/mvysny/pikuri/src/branch/master
|
|
237
|
+
changelog_uri: https://codeberg.org/mvysny/pikuri/src/branch/master/CHANGELOG.md
|
|
238
|
+
bug_tracker_uri: https://codeberg.org/mvysny/pikuri/issues
|
|
239
|
+
rubygems_mfa_required: 'true'
|
|
240
|
+
post_install_message:
|
|
241
|
+
rdoc_options: []
|
|
242
|
+
require_paths:
|
|
243
|
+
- lib
|
|
244
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
245
|
+
requirements:
|
|
246
|
+
- - ">="
|
|
247
|
+
- !ruby/object:Gem::Version
|
|
248
|
+
version: '3.3'
|
|
249
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
250
|
+
requirements:
|
|
251
|
+
- - ">="
|
|
252
|
+
- !ruby/object:Gem::Version
|
|
253
|
+
version: '0'
|
|
254
|
+
requirements: []
|
|
255
|
+
rubygems_version: 3.5.22
|
|
256
|
+
signing_key:
|
|
257
|
+
specification_version: 4
|
|
258
|
+
summary: A small, privacy-first Ruby toolkit for building local AI assistants.
|
|
259
|
+
test_files: []
|