samagotchi 0.154.1 → 0.156.0
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/CHANGELOG.md +29 -1
- data/bin/chi +1 -1
- data/docs/architecture.md +12 -7
- data/docs/bundles.md +21 -0
- data/docs/cli.md +1 -1
- data/docs/guardrails.md +2 -2
- data/docs/hooks.md +1 -1
- data/docs/internals/anthropic.md +5 -5
- data/docs/internals/attached-context.md +9 -6
- data/docs/internals/background-tasks.md +1 -1
- data/docs/internals/block-renderers.md +8 -1
- data/docs/internals/engine.md +642 -831
- data/docs/internals/inline-widgets.md +136 -0
- data/docs/internals/llm-context-forget.md +8 -3
- data/docs/internals/objectives.md +8 -6
- data/docs/internals/participants.md +5 -5
- data/docs/internals/prompt-caching.md +13 -6
- data/docs/internals/remote-sessions.md +3 -1
- data/docs/internals/web-frontend.md +1 -1
- data/docs/internals/working-set.md +2 -1
- data/docs/plugins.md +2 -0
- data/docs/releasing.md +1 -1
- data/docs/sessions.md +4 -4
- data/docs/system-one.md +3 -2
- data/docs/testing.md +1 -1
- data/lib/samagotchi/block_renderers.rb +5 -0
- data/lib/samagotchi/bootstrap/config_writer.rb +1 -1
- data/lib/samagotchi/broadcast_command.rb +3 -3
- data/lib/samagotchi/bundle_command/check.rb +1 -1
- data/lib/samagotchi/bundle_command/try/sandbox.rb +1 -1
- data/lib/samagotchi/bundles/dev/manifest.yml +3 -2
- data/lib/samagotchi/bundles/inline-widgets/manifest.yml +11 -0
- data/lib/samagotchi/bundles/inline-widgets/plugin.rb +76 -0
- data/lib/samagotchi/bundles/system/config_modification_protocol.md +2 -2
- data/lib/samagotchi/bundles/system/manifest.yml +2 -2
- data/lib/samagotchi/child_move.rb +7 -51
- data/lib/samagotchi/children_status.rb +1 -1
- data/lib/samagotchi/cli/parent_wait.rb +1 -1
- data/lib/samagotchi/config.rb +17 -112
- data/lib/samagotchi/context_command.rb +1 -2
- data/lib/samagotchi/context_window.rb +3 -3
- data/lib/samagotchi/desktop/macos.rb +1 -1
- data/lib/samagotchi/engine/context_judge.rb +21 -119
- data/lib/samagotchi/engine/guardrails.rb +4 -2
- data/lib/samagotchi/engine/messages.rb +9 -6
- data/lib/samagotchi/engine/models.rb +5 -2
- data/lib/samagotchi/engine/objectives.rb +30 -80
- data/lib/samagotchi/engine/participants.rb +15 -10
- data/lib/samagotchi/engine/plugins.rb +3 -1
- data/lib/samagotchi/engine/questions.rb +1 -1
- data/lib/samagotchi/engine/side_requests.rb +26 -13
- data/lib/samagotchi/engine/toolkit.rb +35 -191
- data/lib/samagotchi/engine/turn_end.rb +1 -1
- data/lib/samagotchi/engine/turn_helpers.rb +16 -39
- data/lib/samagotchi/engine/verify.rb +7 -143
- data/lib/samagotchi/engine.rb +166 -98
- data/lib/samagotchi/engine_peers.rb +1 -1
- data/lib/samagotchi/event_fanout.rb +18 -12
- data/lib/samagotchi/guardrail_wiring.rb +83 -82
- data/lib/samagotchi/guardrails/gate.rb +41 -40
- data/lib/samagotchi/guardrails/pair_boundary.rb +2 -1
- data/lib/samagotchi/guardrails/review_boundary.rb +2 -1
- data/lib/samagotchi/guardrails/targets.rb +28 -11
- data/lib/samagotchi/guardrails_command.rb +1 -1
- data/lib/samagotchi/host_config.rb +72 -1
- data/lib/samagotchi/host_model.rb +2 -6
- data/lib/samagotchi/host_registry.rb +1 -1
- data/lib/samagotchi/inline_widgets.rb +325 -0
- data/lib/samagotchi/kernel_loop.rb +215 -313
- data/lib/samagotchi/llm/anthropic_wire.rb +2 -2
- data/lib/samagotchi/llm/backend.rb +3 -1
- data/lib/samagotchi/llm/chat_loop.rb +87 -49
- data/lib/samagotchi/llm/native_backend.rb +3 -2
- data/lib/samagotchi/llm_context_apply.rb +54 -1
- data/lib/samagotchi/llm_context_forget.rb +5 -3
- data/lib/samagotchi/llm_context_notice.rb +1 -1
- data/lib/samagotchi/llm_context_strategy.rb +7 -9
- data/lib/samagotchi/llm_context_view.rb +9 -0
- data/lib/samagotchi/model_binding.rb +3 -3
- data/lib/samagotchi/model_price.rb +4 -10
- data/lib/samagotchi/model_profile.rb +6 -6
- data/lib/samagotchi/model_settings.rb +37 -2
- data/lib/samagotchi/note_command.rb +1 -2
- data/lib/samagotchi/objectives_audit.rb +4 -3
- data/lib/samagotchi/participants.rb +2 -2
- data/lib/samagotchi/plugin/context.rb +1 -1
- data/lib/samagotchi/plugin/prompt_sections.rb +7 -0
- data/lib/samagotchi/plugin/sessions.rb +2 -5
- data/lib/samagotchi/plugin/tool_spec.rb +5 -3
- data/lib/samagotchi/project_env.rb +1 -1
- data/lib/samagotchi/question_desk.rb +1 -1
- data/lib/samagotchi/reasoning_history.rb +3 -3
- data/lib/samagotchi/reminder_carry.rb +1 -1
- data/lib/samagotchi/reprefill_meter.rb +45 -0
- data/lib/samagotchi/review_command.rb +1 -1
- data/lib/samagotchi/revise_anchor.rb +1 -1
- data/lib/samagotchi/sampling_settings.rb +3 -3
- data/lib/samagotchi/self_report.rb +7 -7
- data/lib/samagotchi/session.rb +50 -7
- data/lib/samagotchi/session_access/local.rb +7 -5
- data/lib/samagotchi/session_access/remote.rb +17 -3
- data/lib/samagotchi/session_archive_command.rb +2 -2
- data/lib/samagotchi/session_chain.rb +7 -6
- data/lib/samagotchi/session_continue.rb +6 -5
- data/lib/samagotchi/session_delete_command.rb +1 -1
- data/lib/samagotchi/session_manager/delivery.rb +254 -0
- data/lib/samagotchi/session_manager/emptiness.rb +138 -0
- data/lib/samagotchi/session_manager/lifecycle.rb +274 -0
- data/lib/samagotchi/session_manager/listing.rb +189 -0
- data/lib/samagotchi/session_manager/removal.rb +190 -0
- data/lib/samagotchi/session_manager/spawn.rb +242 -0
- data/lib/samagotchi/session_manager/worker_command.rb +157 -0
- data/lib/samagotchi/session_manager.rb +26 -1540
- data/lib/samagotchi/session_metrics.rb +1 -1
- data/lib/samagotchi/sessions_command.rb +1 -1
- data/lib/samagotchi/share_command.rb +1 -1
- data/lib/samagotchi/starting_marker.rb +65 -0
- data/lib/samagotchi/steer_cut_after.rb +3 -3
- data/lib/samagotchi/system_one/recorder.rb +49 -0
- data/lib/samagotchi/system_prompt.rb +37 -30
- data/lib/samagotchi/terminal_ui/exit_lines.rb +1 -1
- data/lib/samagotchi/terminal_ui.rb +2 -6
- data/lib/samagotchi/testing/boundary.rb +7 -0
- data/lib/samagotchi/testing/bundle.rb +7 -5
- data/lib/samagotchi/testing/install.rb +3 -2
- data/lib/samagotchi/testing/sessions.rb +1 -1
- data/lib/samagotchi/thinking.rb +3 -3
- data/lib/samagotchi/token_usage.rb +1 -1
- data/lib/samagotchi/tool_activity.rb +15 -7
- data/lib/samagotchi/tool_declarations.rb +6 -6
- data/lib/samagotchi/tool_output_cut.rb +17 -0
- data/lib/samagotchi/tool_response.rb +4 -3
- data/lib/samagotchi/tool_runner.rb +96 -102
- data/lib/samagotchi/toolkit_binding.rb +40 -14
- data/lib/samagotchi/toolkit_command.rb +1 -1
- data/lib/samagotchi/tools/deferred_tools.rb +17 -21
- data/lib/samagotchi/tools/delegate.rb +10 -5
- data/lib/samagotchi/tools/delegate_result.rb +4 -4
- data/lib/samagotchi/tools/index_hint.rb +14 -0
- data/lib/samagotchi/tools/registry.rb +64 -44
- data/lib/samagotchi/tools/send_note.rb +4 -6
- data/lib/samagotchi/tools/tool_index.rb +150 -102
- data/lib/samagotchi/tools/tool_surface.rb +187 -0
- data/lib/samagotchi/turn_context.rb +68 -0
- data/lib/samagotchi/turn_stages/context_judge.rb +172 -0
- data/lib/samagotchi/turn_stages/objectives.rb +150 -0
- data/lib/samagotchi/turn_stages/toolkit_suggestion.rb +257 -0
- data/lib/samagotchi/turn_stages/verify_anchors.rb +168 -0
- data/lib/samagotchi/turn_stages/warmup.rb +82 -0
- data/lib/samagotchi/turn_state.rb +46 -4
- data/lib/samagotchi/version.rb +1 -1
- data/lib/samagotchi/vision_support.rb +3 -3
- data/lib/samagotchi/web/app.rb +15 -8
- data/lib/samagotchi/web/markdown_renderer.rb +39 -14
- data/lib/samagotchi/web/message_display.rb +1 -1
- data/lib/samagotchi/web/participant_access.rb +2 -2
- data/lib/samagotchi/web/public/app.js +5 -1
- data/lib/samagotchi/web/public/block_host.js +74 -199
- data/lib/samagotchi/web/public/block_renderers.css +2 -0
- data/lib/samagotchi/web/public/block_source.js +7 -4
- data/lib/samagotchi/web/public/block_watch.js +256 -0
- data/lib/samagotchi/web/public/composer_fold.js +3 -0
- data/lib/samagotchi/web/public/index.html +28 -9
- data/lib/samagotchi/web/public/inline_widgets.js +146 -0
- data/lib/samagotchi/web/public/owner_verify.js +1 -1
- data/lib/samagotchi/web/public/participant.js +1 -1
- data/lib/samagotchi/web/public/revise_stack.js +1 -1
- data/lib/samagotchi/web/public/stage_watch.js +6 -2
- data/lib/samagotchi/web/public/text_roots.js +1 -1
- data/lib/samagotchi/web/public/verify_target.js +1 -1
- data/lib/samagotchi/web/public/widget_picks.js +130 -0
- data/lib/samagotchi/web/public/widget_walk.js +230 -0
- data/lib/samagotchi/web/public/widgets.css +70 -0
- data/lib/samagotchi/web/session_access_routes.rb +3 -3
- data/lib/samagotchi/web/session_control.rb +3 -3
- data/lib/samagotchi/web/session_create.rb +3 -3
- data/lib/samagotchi/web/session_hub.rb +1 -1
- data/lib/samagotchi/web/session_show.rb +3 -3
- data/lib/samagotchi/web/session_summary.rb +3 -4
- data/lib/samagotchi/worker.rb +55 -27
- data/lib/samagotchi/worker_boot.rb +184 -0
- data/lib/samagotchi/worker_signals.rb +1 -1
- data/lib/samagotchi/worker_task_wakes.rb +2 -2
- metadata +29 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e545b9da4004e996e2cdee4f53d2cf0a181a47b695fbcb18ca1037e77da6b1cb
|
|
4
|
+
data.tar.gz: 10cb3b94093ab0f0e7d285a2f405577be8fc61f26029a005754a078875d8ebdc
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f20b956f443a5a04680d2a7a162e3a9d44f9b8a66d0855f2827421420a7f8a1053ad01769ff140c442fded2e6cdf58b41f0b37f6a22b7849fcb463d5fdb2b22e
|
|
7
|
+
data.tar.gz: a08049e4ab152265163ea53327655064a1c2415b19c695e03dd21d3b01488453824cb59451fb333618ed1aefc334e97b10b4780cfdee02dd916853e37069858a
|
data/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,32 @@ and commands may change between minor versions. How releases are made:
|
|
|
8
8
|
|
|
9
9
|
## [Unreleased]
|
|
10
10
|
|
|
11
|
+
## [0.156.0] - 2026-11-08
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
|
|
15
|
+
- An id or prefix that names no session is refused in one wording everywhere: `no session ID` (the CLI commands, `chi --resume`/`--attach`, chi web's 404s and the session tools), where some said `Session not found: ID`. A `chi --remote` command shows it the same against an older chi web.
|
|
16
|
+
|
|
17
|
+
### Fixed
|
|
18
|
+
|
|
19
|
+
- `chi sessions list` shows a session whose worker died mid-turn as idle, as chi web does, instead of running (the plain and the `--live`/`--cwd` listings; with `--remote`, once that chi web runs this release).
|
|
20
|
+
|
|
21
|
+
Update with `chi update`.
|
|
22
|
+
|
|
23
|
+
## [0.155.0] - 2026-11-07
|
|
24
|
+
|
|
25
|
+
### Added
|
|
26
|
+
|
|
27
|
+
- The inline-widgets bundle (in the `dev` profile, `chi update`): it teaches the model the `chi-ui` blocks chi web draws, so an answer that leaves you several things to decide comes with picks that fill your reply, and a "how does this work" answer with a walk you step through. The terminal shows the block's YAML; a delegate child and a `-p --non-interactive` run don't get it.
|
|
28
|
+
- `chi bundle check` lists a bundle's prompt sections among what it registers.
|
|
29
|
+
|
|
30
|
+
### Fixed
|
|
31
|
+
|
|
32
|
+
- At the very start of a turn, a plugin's `ctx.turn_author`, a hook's `author:` and `/objectives` could still see the previous turn (its participant, its conversation); they now see the turn that just started.
|
|
33
|
+
- chi web's session bar no longer slides its time and speed chips under the buttons with a long model name: the model name shortens, the buttons move to their own line together, and on a narrow window the ctx/speed/time chips get a line of their own instead of being cut off.
|
|
34
|
+
|
|
35
|
+
Update with `chi update` (the dev profile 0.7.8, inline-widgets 0.1.0 new).
|
|
36
|
+
|
|
11
37
|
## [0.154.1] - 2026-11-07
|
|
12
38
|
|
|
13
39
|
### Fixed
|
|
@@ -5772,7 +5798,9 @@ and long-lived sessions.
|
|
|
5772
5798
|
- A macOS desktop helper (`chi desktop install`): a "Send to chi" Service and a
|
|
5773
5799
|
hotkey panel that send selected text or the clipboard to your sessions.
|
|
5774
5800
|
|
|
5775
|
-
[Unreleased]: https://github.com/dm1try/samagotchi/compare/v0.
|
|
5801
|
+
[Unreleased]: https://github.com/dm1try/samagotchi/compare/v0.156.0...HEAD
|
|
5802
|
+
[0.156.0]: https://github.com/dm1try/samagotchi/compare/v0.155.0...v0.156.0
|
|
5803
|
+
[0.155.0]: https://github.com/dm1try/samagotchi/compare/v0.154.1...v0.155.0
|
|
5776
5804
|
[0.154.1]: https://github.com/dm1try/samagotchi/compare/v0.154.0...v0.154.1
|
|
5777
5805
|
[0.154.0]: https://github.com/dm1try/samagotchi/compare/v0.153.0...v0.154.0
|
|
5778
5806
|
[0.153.0]: https://github.com/dm1try/samagotchi/compare/v0.152.0...v0.153.0
|
data/bin/chi
CHANGED
|
@@ -459,7 +459,7 @@ begin
|
|
|
459
459
|
# Ctrl-C cancelled it.
|
|
460
460
|
exit 1 if %i[turn_failed empty_answer iteration_limit].include?(ended)
|
|
461
461
|
exit Samagotchi::CLI::Exit::INTERRUPTED if ended == :interrupted
|
|
462
|
-
rescue Samagotchi::TerminalUI::SessionBusy, Samagotchi::
|
|
462
|
+
rescue Samagotchi::TerminalUI::SessionBusy, Samagotchi::Session::NotFound, Samagotchi::ModelProfile::MissingModel,
|
|
463
463
|
Samagotchi::Toolkit::Refused => e
|
|
464
464
|
warn "Error: #{e.message}"
|
|
465
465
|
exit 1
|
data/docs/architecture.md
CHANGED
|
@@ -101,10 +101,11 @@ terminal renders the events it gets over the Bridge.
|
|
|
101
101
|
| Core | `Samagotchi::Engine` | System prompt, memory injection, tool declarations, session lifecycle, model↔tool loop (`run_turn`). No terminal coupling. |
|
|
102
102
|
| UI | `Samagotchi::TerminalUI`, `TerminalUI::AttachLauncher` / `AttachedLoop` | `TerminalUI`: the `--non-interactive` one-shot host, its own `Engine`. The attached TUI (every interactive `chi`): a client of the session worker's Bridge, no `Engine`. |
|
|
103
103
|
| Model loops | `KernelLoop` (via `LLM::NativeBackend`), `LLM::ChatLoop` | The model↔tool loop: raw prompt, or a chat API (OpenAI chat, Anthropic Messages), chosen per host (see below). |
|
|
104
|
+
| Turn | `TurnContext`, `TurnState`, `Engine::Turn` | One turn's frozen `TurnContext` (id, session, origin, author, participant mode, controller, folders, git facts, settings, model key/name and the tool surface (`Tools::ToolSurface`) from `generate`): built by `Engine#begin_turn`, published with the running flag by `TurnState` (the only way another thread reads the running turn: `Engine#turn_context` / `#last_turn_context`), handed explicitly down the tool path (`ModelBackend#complete(context:)`, `ToolRunner#run`, `Guardrails::Gate#evaluate`, `KernelLoop#dispatch_tool_call`). `Engine::Turn` keeps only the lifecycle state ([internals/engine.md](internals/engine.md), "Turn and TurnContext"). The turn stages (`TurnStages::ToolkitSuggestion`, `TurnStages::ContextJudge`, `TurnStages::Objectives`, `TurnStages::Warmup`, `TurnStages::VerifyAnchors`, `lib/samagotchi/turn_stages/`): the steps that keep state across the turn, built from the Engine-lifetime objects and called by name from the turn's skeleton with the values of the call (a `SystemOne::Recorder`, the sessions dir), not callbacks into the Engine (internals/engine.md, "Turn stages"). |
|
|
104
105
|
| Adapters | `Samagotchi::Client`, `LLM::OpenAIChat`, `LLM::AnthropicMessages`, `LLM::HTTP` | Raw-prompt servers, the OpenAI chat API, Anthropic's Messages API, and the HTTP they share. |
|
|
105
106
|
| Tools | `lib/samagotchi/tools/*` | Execute, read, edit, write, memory, task_*, web_fetch, delegate/delegate_result, ask_user_question, reminders, send_note, list_sessions, context_read, objectives, forget_outputs, find_tools/call_tool (the tool index), plus runtime/output-guardrails. |
|
|
106
107
|
| Bundles | `lib/samagotchi/memory_bundle/*`, `BundleCommand` | `chi bundle`: install/upgrade (3-way, with a text merge of edited memories), build, uninstall; the install record under `.bundles/<name>/` that the hook, guardrail and plugin loaders read ([internals/bundles.md](internals/bundles.md)). |
|
|
107
|
-
| Background | `Samagotchi::Worker`, `Samagotchi::SessionManager` | `SessionManager` forks/spawns one worker process per session; its `Worker` builds the `Engine` and `Bridge` (no terminal rendering) and runs queued turns. The spawned process (own process group) forks the worker, which `setsid`s and is reparented to init once its starter exits (it waits until the worker holds `owner.lock`, so the spawner's `Process.detach` waiter tells a starting worker): nothing that walks the spawner's process tree reaches it (`SAMAGOTCHI_WORKER_DETACH=1`, `detach_from_spawner`). The lock's pid is the worker's; `spawn`'s `child_pid` is its starter's. |
|
|
108
|
+
| Background | `Samagotchi::Worker`, `Samagotchi::SessionManager` | `SessionManager` (`session_manager.rb`, its parts in `session_manager/`: spawn · worker_command · listing · delivery · lifecycle · removal · emptiness) forks/spawns one worker process per session. The worker process's main (owner lock, detach, signals, project env, what it does as it leaves) is `WorkerBoot` (`worker_boot.rb`), which SessionManager loads only as a worker boots (its `run_session_loop` forwarder); its `Worker` builds the `Engine` and `Bridge` (no terminal rendering) and runs queued turns. The spawned process (own process group) forks the worker, which `setsid`s and is reparented to init once its starter exits (it waits until the worker holds `owner.lock`, so the spawner's `Process.detach` waiter tells a starting worker): nothing that walks the spawner's process tree reaches it (`SAMAGOTCHI_WORKER_DETACH=1`, `detach_from_spawner`). The lock's pid is the worker's; `spawn`'s `child_pid` is its starter's. |
|
|
108
109
|
| Web | `Samagotchi::Web::App`, `Samagotchi::Web::Server`, `Samagotchi::Web::SessionHub` | Rack+WEBrick on one port, `127.0.0.1:4567` (index.html + `/api/*` + SSE); with `web.host: lan` also on this machine's LAN address, behind an access token (`Web::Lan`, `Web::Token`). The hub is chi web's projection of the session list, pushed to every tab over `GET /api/events`. |
|
|
109
110
|
| Sessions | `Samagotchi::Session`, `SessionManager` | File `sessions/<uuid>.json` + sidecar `input/`/`output/`; retention 14d/500, `updated_at desc`, lazy sweep. |
|
|
110
111
|
|
|
@@ -161,10 +162,12 @@ Unchanged: `ContextProviders`' `{ruby}` (`RbConfig.ruby`: the home's ruby inside
|
|
|
161
162
|
project env below, so a `mise env` that sets GEM_HOME reaches it), `chi bundle
|
|
162
163
|
try/test/check` (`-I LIB_DIR`), hooks (in-process). The worker's boot string, `run_session_loop(id, state_dir:)` and
|
|
163
164
|
`SAMAGOTCHI_BOOT_FALLBACK` stay the cross-version contract (`spec/worker_contract_spec.rb`): the home only adds the
|
|
164
|
-
prelude in front.
|
|
165
|
+
prelude in front. The string names `SessionManager.run_session_loop`, which only forwards to
|
|
166
|
+
`WorkerBoot.run_session_loop`, the worker's main; the string switches to `WorkerBoot` one release later, and the
|
|
167
|
+
forwarder goes the release after that. An older chi that wakes a session doesn't read home.json and starts its worker as before.
|
|
165
168
|
|
|
166
169
|
**The tools a worker runs** follow the project, not the boot, and only they do: a spawned worker
|
|
167
|
-
(`WORKER_PROCESS_ENV`; never an in-process loop) calls `ProjectEnv.compute` in `run_session_loop`, after the owner
|
|
170
|
+
(`WORKER_PROCESS_ENV`; never an in-process loop) calls `ProjectEnv.compute` in `WorkerBoot.run_session_loop`, after the owner
|
|
168
171
|
lock and before `Worker.new`, and installs the result (`ProjectEnv.install!`; a frozen `ProjectEnv::Overlay`,
|
|
169
172
|
`{key => value or nil}`). Its ENV is never written: chi's own process (LLM calls, `HostKeys`, Net::HTTP proxies,
|
|
170
173
|
Config, Paths, hooks, plugins) keeps the spawner's env. The overlay is the session folder's `mise env -C DIR --json`
|
|
@@ -499,6 +502,8 @@ verbatim) and the fields its class is built from, so a remote client raises the
|
|
|
499
502
|
`scratch` (`ArchiveRefused`: `session_id`, `reason`, `busy_id`), a restart's `held`/`not_running`/`unsupported`/
|
|
500
503
|
`failed` (`RestartRefused`: `session_id`, `reason`, `version`), a continue's `continued`/`open_children`/`folder_gone`
|
|
501
504
|
(`SessionContinue::Refused`: `session_id`, `reason`, `ids`) and `ambiguous_id` (`Session::AmbiguousId`: `ids`).
|
|
505
|
+
A session an id names none of is `404 not_found` with `Session::NotFound`'s words (`no session X`, `#session_not_found`):
|
|
506
|
+
every lookup goes through `Session.resolve!` (an id or a unique prefix), and every surface shows that one message.
|
|
502
507
|
|
|
503
508
|
## Model loops and adapters
|
|
504
509
|
|
|
@@ -519,7 +524,7 @@ on every read, never kept, since config.yml and a model listing can move it with
|
|
|
519
524
|
|
|
520
525
|
Both return an `LLM::ModelResult` and emit the same stream events; tool calls in
|
|
521
526
|
both go through `ToolRunner` (events, hooks, veto, output cap) and
|
|
522
|
-
`KernelLoop#dispatch_tool_call
|
|
527
|
+
`KernelLoop#dispatch_tool_call`, given the turn's `TurnContext` as an argument. Every format's built-in calls (Gemma, Qwen,
|
|
523
528
|
chat `tool_calls`) are built by one table, `Tools::BuiltinCalls`, from the
|
|
524
529
|
parsed `{name, args}` (derived from `TOOL_SCHEMAS`), so a call looks the same to
|
|
525
530
|
hooks and tools whichever model made it. Both loops' `generation_chunk` carries
|
|
@@ -608,8 +613,8 @@ A map of the parts the overview above doesn't name (paths under `lib/samagotchi/
|
|
|
608
613
|
|
|
609
614
|
| Component | Main file(s) | What it is |
|
|
610
615
|
|---|---|---|
|
|
611
|
-
| Worker | `worker.rb` (`worker_idle_exit.rb`, `worker_inbound.rb`, `worker_signals.rb`, `worker_wakes.rb`, `worker_task_wakes.rb`, `task_watch.rb`) | A session's background process: builds the `Engine` and `Bridge`, runs queued turns and the wake turns nobody typed (delegate reports, a background task that finished unseen: [Finish wake](internals/background-tasks.md#finish-wake), attached context), exits when idle. A spawned one traps TERM, HUP and INT (`WorkerSignals`, installed by `run_session_loop` when `SAMAGOTCHI_WORKER_PROCESS=1`): the running turn stops as a Stop with reason `signal`, is saved, and the worker leaves (`:signal`, exit 0; a new worker only for input already queued). A running turn is checkpointed at its iteration boundaries (`TurnCheckpoint`, the `interrupted_turn` mark), and the next worker settles a turn its predecessor died in (`TurnCheckpoint.settle`). The session is saved from the turn's thread, Bridge threads and a signal's thread; `Session#save` takes a per-session lock around its snapshot and write, so an older snapshot never lands over a newer one. |
|
|
612
|
-
| Config | `config.rb`, `config/restart_watch.rb` | Every setting as an `Entry`: env, config.yml and CLI layers ([configuration.md](configuration.md)); the notice a worker or chi web gets when config.yml changes a setting it reads only at its start. |
|
|
616
|
+
| Worker | `worker.rb` (`worker_boot.rb`, `worker_idle_exit.rb`, `worker_inbound.rb`, `worker_signals.rb`, `worker_wakes.rb`, `worker_task_wakes.rb`, `task_watch.rb`) | A session's background process: builds the `Engine` and `Bridge`, runs queued turns and the wake turns nobody typed (delegate reports, a background task that finished unseen: [Finish wake](internals/background-tasks.md#finish-wake), attached context), exits when idle. A spawned one traps TERM, HUP and INT (`WorkerSignals`, installed by `WorkerBoot.run_session_loop` when `SAMAGOTCHI_WORKER_PROCESS=1`): the running turn stops as a Stop with reason `signal`, is saved, and the worker leaves (`:signal`, exit 0; a new worker only for input already queued). A running turn is checkpointed at its iteration boundaries (`TurnCheckpoint`, the `interrupted_turn` mark), and the next worker settles a turn its predecessor died in (`TurnCheckpoint.settle`). The session is saved from the turn's thread, Bridge threads and a signal's thread; `Session#save` takes a per-session lock around its snapshot and write, so an older snapshot never lands over a newer one. |
|
|
617
|
+
| Config | `config.rb`, `config/restart_watch.rb` | Every setting as an `Entry`: env, config.yml and CLI layers ([configuration.md](configuration.md)); the notice a worker or chi web gets when config.yml changes a setting it reads only at its start. With `log.rb` it is the bottom layer: nothing it references reaches back to it, so `hosts:` and `models:` entries parse next to their types (`HostConfig.all`, `ModelSettings.all`). |
|
|
613
618
|
| Paths | `paths.rb` (`Paths`) | The XDG base dirs chi's files live under, read from the env on every call: `Paths.state_home` (`$XDG_STATE_HOME`, else `~/.local/state`) and `Paths.config_home` (`$XDG_CONFIG_HOME`, else `~/.config`), both defaults under `Dir.home`; a blank variable counts as unset, a relative one is made absolute from the current directory. `Paths.tilde` shows a path with `~` for the home folder. `SessionManager` hands a spawned worker the spawner's `XDG_STATE_HOME` / `XDG_CONFIG_HOME`, when set, made absolute, so a relative one isn't read from the session's folder. |
|
|
614
619
|
| MemoryBundle | `memory_bundle.rb`, `memory_bundle/{installer,builder,installed_bundle,plugin_ref,bundle_hook}.rb` (`Installer`, `Builder`, `InstalledBundle`, `PluginRef`, `BundleHook`) | Installing, building and reading bundles of memories, hooks and plugins. |
|
|
615
620
|
| Bundle authoring | `bundle_command.rb` (`BundleCommand`), `bundle_command/{scaffold,check,test_run}.rb`, `bundle_command/try/{run,sandbox,trace}.rb`, `testing.rb` + `testing/` (the test kit) | `chi bundle new`, `check`, `test` and `try`, and the kit a bundle's tests load it with ([bundle-authoring.md](bundle-authoring.md), [internals/bundles.md](internals/bundles.md)). |
|
|
@@ -636,7 +641,7 @@ A map of the parts the overview above doesn't name (paths under `lib/samagotchi/
|
|
|
636
641
|
| Participants | `participants.rb` (`Participants`, the `participants.json` sidecar), `share_command.rb` (`ShareCommand`, `chi share`), `session_participants.rb`, `participants_watch.rb`, `grants.rb` (`Grants`), `participant_exposure.rb` (`ParticipantExposure`), `web/principal.rb` (`Web::Principal`), `web/participant_access.rb` (`Web::ParticipantAccess`: the participant's gate and routes), `web/participants_admin.rb` (`Web::ParticipantsAdmin`: the owner's invite, list, revoke, cap and Apply routes), `web/participant_review.rb` + `web/participant_view.rb` (`Web::ParticipantReview`, `Web::ParticipantView`), `redact.rb` (`Redact`, `Redact::Viewer`: the redaction every string a participant gets passes, also the Engine's Verify quote check), `web/participant_stream_filter.rb`, `guardrails/review_boundary.rb` + `guardrails/review_paths.rb` | The people or agents an owner invites to review one session through chi web: their grants and gate, what they read, their read-only review turns ([internals/participants.md](internals/participants.md), [guardrails.md](guardrails.md)). |
|
|
637
642
|
| Analytics | `analytics_file.rb` (`AnalyticsFile`), `session_metrics/totals.rb` (`SessionMetrics::Totals`), `session_metrics/model_segment.rb` (`SessionMetrics::ModelSegment`) | A session's `analytics.json` (`SessionMetrics#persist`); the sums over its turn records (`Totals`: tokens, cost, speeds, kept as running counters) and their split per model after a `/model` switch (`ModelSegment`: a run of turns on one model, the `model_segments` rows); `session_metrics/cost.rb` (`SessionMetrics::Cost`): the spend `ctx.cost` reads; `session_metrics/usage.rb` (`SessionMetrics::Usage`): the work `ctx.usage` reads. `session_metrics/side_totals.rb` (`SessionMetrics::SideTotals`) and `side_usage.rb` (`SideUsage`): the side requests' sums, apart from the turns'. |
|
|
638
643
|
| Images / vision | `image_store.rb` (`ImageStore`), `vision_support.rb`, `vision_context.rb` | Stored prompt images and whether a model takes them. |
|
|
639
|
-
| Toolkits | `toolkit.rb` (`Toolkit`), `toolkit_binding.rb` (`ToolkitBinding`, the Engine's seam), `toolkit_command.rb` (`/toolkit`), `tools/registry.rb` (`Registry#toolkit`,
|
|
644
|
+
| Toolkits | `toolkit.rb` (`Toolkit`), `toolkit_binding.rb` (`ToolkitBinding`, the Engine's seam), `toolkit_command.rb` (`/toolkit`), `tools/registry.rb` (`Registry#toolkit`), `tools/tool_surface.rb` (`ToolSurface#left_out`, read by the prompt and `/toolkit`), `web/public/toolkit_chip.js` | Which registered tools a session's prompts declare: saved in the session, resolved at a turn's start (`Engine#apply_toolkit!`), named in the prompt's not-loaded line, a kit's prompt text after the appended files; `chi.toolkit` and `ctx.use_toolkit` for plugins ([configuration.md](configuration.md#toolkits)). |
|
|
640
645
|
| Tool index | `tools/tool_index.rb` (`Tools::ToolIndex`), `tools/deferred_tools.rb` | `find_tools` and `call_tool`: the tools a session knows but doesn't declare one by one (an mcp bundle's servers through `chi.tool_source`, the built-ins its toolkit leaves out), searched and called by name ([plugins.md](plugins.md)). On `api: anthropic` they also go out deferred, a hit loads its matches and the model calls them by name ([internals/anthropic.md](internals/anthropic.md)). |
|
|
641
646
|
| Tool output cut | `tool_output_cut.rb` (`ToolOutputCut`), `tool_output_files.rb` (`ToolOutputFiles`) | A tool's output over `max_tool_output_chars` (a `memory_read`'s: `memory.read_max_chars`, 0 = none, plus a guard at half a known window), cut by the tool's policy; an execute's whole output saved in the session's `tool_output/` folder ([internals/tool-output-limits.md](internals/tool-output-limits.md)). |
|
|
642
647
|
| Steer delivery | `steer.rb` (`Steer`), `delivery.rb` (`Delivery`), `steer_cut.rb` (`SteerCut`), `generation_phase.rb`, `waiting_steer.rb`, `steer_cut_after.rb` (`SteerCutAfter`), `cut_policy.rb` (`CutPolicy`) | A message for a running turn: at the next boundary, cutting a thinking-only generation, or queued for the turn's end ([internals/engine.md](internals/engine.md)). |
|
data/docs/bundles.md
CHANGED
|
@@ -1358,3 +1358,24 @@ bundles:
|
|
|
1358
1358
|
timeout: 120 # seconds the side request may take (a number)
|
|
1359
1359
|
max_tokens: 300 # the side answer's limit
|
|
1360
1360
|
```
|
|
1361
|
+
|
|
1362
|
+
## The inline-widgets bundle
|
|
1363
|
+
|
|
1364
|
+
`chi bundle install inline-widgets` (or the `dev` profile) installs the bundle shipped with chi. It is written only against
|
|
1365
|
+
this API (`lib/samagotchi/bundles/inline-widgets/plugin.rb`) and has no settings, commands or memories: it adds two
|
|
1366
|
+
[prompt sections](plugins.md#chiprompt_sectionname--ctx---and-chiprompt_changed) that tell the model chi web draws
|
|
1367
|
+
```` ```chi-ui ```` blocks ([the blocks](internals/inline-widgets.md)).
|
|
1368
|
+
|
|
1369
|
+
- **picks**: when an answer leaves you two or more things to decide (review findings, a plan's open questions), a row
|
|
1370
|
+
per item with its options as buttons, the recommended one picked to start with, a note per row, and **Fill reply**,
|
|
1371
|
+
which puts your picks in the composer. Nothing is sent until you send it.
|
|
1372
|
+
- **walk**: a scenario you step through: who does what, what you see, what happens behind it, with a fork's cases to
|
|
1373
|
+
choose from.
|
|
1374
|
+
- **Where it draws**: chi web, in the answers. The terminal shows the block's YAML, and a block chi can't read stays
|
|
1375
|
+
YAML with a short note under it.
|
|
1376
|
+
- **Where the prompt has none**: a delegate child (its parent reads the report, nobody sees it drawn) and a one-shot
|
|
1377
|
+
`chi -p … --non-interactive`. `/stats` lists the sections a session's prompt holds: `picks (inline-widgets), walk
|
|
1378
|
+
(inline-widgets)`.
|
|
1379
|
+
- **Cost**: about 2,900 characters in the stable part of the prompt, the same at every build, so the prompt cache keeps.
|
|
1380
|
+
- **Uninstall**: `chi bundle uninstall inline-widgets` takes the sections out of new sessions' prompts (a session you
|
|
1381
|
+
have open needs `chi sessions restart ID`); blocks already in a history still draw, since the drawing is chi web's own.
|
data/docs/cli.md
CHANGED
|
@@ -158,7 +158,7 @@ The loop for a bundle you're writing (the whole path: [bundle-authoring.md](bund
|
|
|
158
158
|
bundle chi doesn't ship), `clash` (warn: a name chi ships, or one installed from elsewhere; the sandboxed install
|
|
159
159
|
then forces), `install` (each Installer warning, a `needs` one as warn, and each plugin or hook load failure at
|
|
160
160
|
the source `file:line`; skipped while a placeholder sha is unfilled), `registered` (info: each command, tool,
|
|
161
|
-
hook with its priority, init, toolkit, tool source and
|
|
161
|
+
hook with its priority, init, toolkit, tool source, peer source and prompt section), `hook-event` (warn: a `chi.on` event chi
|
|
162
162
|
never fires), `settings` (warn: a `--set` the manifest's `settings:` rules out, as config.yml's `bundles:` is told), `api` (warn: a `ctx.*` / `chi.*` call or a keyword this chi's API lacks, read from the source with
|
|
163
163
|
Prism against the API's own classes, on a path that never runs too; written on a local `ctx` / `chi` itself, so a
|
|
164
164
|
`s = ctx.sessions` variable isn't followed; a name the plugin guards with `respond_to?` is left), `boundary` (warn: a `Samagotchi::` name outside "Stable for bundles"; a shipped bundle's listed
|
data/docs/guardrails.md
CHANGED
|
@@ -410,7 +410,7 @@ under the owner's guardrails, as the owner's own turns do: the rules, the
|
|
|
410
410
|
protected paths and every approval the owner already granted apply, and an ask
|
|
411
411
|
goes to the owner. It is a pair turn only when all three hold
|
|
412
412
|
(`ParticipantMode.for_turn`, decided once at the turn's start:
|
|
413
|
-
`GuardrailWiring#
|
|
413
|
+
`GuardrailWiring#begin_turn`, into the turn's `TurnContext#participant_mode`): the session has no `review:` key, its worker
|
|
414
414
|
names the `pair_turns` feature, and the participant's grant was issued with
|
|
415
415
|
`mode: pair`, which chi share and the web's Invite stamp only when the warning
|
|
416
416
|
they showed said their turns act. A grant from before, or one issued while an
|
|
@@ -690,7 +690,7 @@ runs with the owner's rules or System 1's auto-allows. The mode is decided once,
|
|
|
690
690
|
at the start, from their grant's mode there (`ParticipantMode.live_for`) and
|
|
691
691
|
saved on the child (`verify_fresh.mode`): `review` keeps every turn of it
|
|
692
692
|
inside `ReviewBoundary` (read only), `pair` inside `PairBoundary`.
|
|
693
|
-
`GuardrailWiring#
|
|
693
|
+
`GuardrailWiring#begin_turn` reads the saved mode and never looks it up again,
|
|
694
694
|
and every turn of the child carries the participant as its author, whoever
|
|
695
695
|
started it, so the boundary can't fall away for a turn the owner typed into it
|
|
696
696
|
or for an author lookup that finds nobody (the child has no
|
data/docs/hooks.md
CHANGED
|
@@ -711,7 +711,7 @@ Notes:
|
|
|
711
711
|
- Ordering: bundle hooks fire by `(priority, bundle_name, hook_name)` (lower priority first), then plain `config.yml` hooks in registration order.
|
|
712
712
|
- Settings: a hook class with `initialize(settings = {})` gets the bundle's section of `config.yml` `bundles:` (see [Settings](#settings)).
|
|
713
713
|
- A bundle can also ship a `plugin.rb` whose `chi.on(event)` blocks are bundle hooks too, next to commands and tools; see [Plugins](plugins.md). There `ctx.notify`, `ctx.steer` and the other `ctx` helpers act as this page's `event[:notify]`… do for the event the block runs for.
|
|
714
|
-
- Shipped bundles (each but web-search in a profile: `core` or `dev`, see [Bundle profiles](memory.md#bundle-profiles-core-and-dev)): `chi bundle install guardrails` (rules, see [Guardrails](guardrails.md#the-guardrails-bundle)) and `chi bundle install known-names` (a hook, see [Guardrails](guardrails.md#the-known-names-bundle)), `chi bundle install source-links` (a hook: announces source refs, see [The source-links bundle](#the-source-links-bundle)), `chi bundle install btw` (a plugin: `/btw`, see [Bundles](bundles.md#the-btw-bundle)), `chi bundle install mcp` (a plugin: tools from MCP servers, see [Bundles](bundles.md#the-mcp-bundle)) `chi bundle install loop-guard` (a plugin: breaks tool-call loops, see [Bundles](bundles.md#the-loop-guard-bundle)), `chi bundle install check-in` (a plugin: checks on a long turn, see [Bundles](bundles.md#the-check-in-bundle)), `chi bundle install slow-commands` (a plugin: commands that ran past the execute limit are run as tasks next time, see [Bundles](bundles.md#the-slow-commands-bundle)), `chi bundle install agents-md` (a plugin: a nested AGENTS.md is steered into the conversation on the first touch under its directory, see [Bundles](bundles.md#the-agents-md-bundle)), `chi bundle install cost-cap` (a plugin: a per-session $ cap, `/cap`, see [Bundles](bundles.md#the-cost-cap-bundle)), `chi bundle install work-cap` (a plugin: a per-session cap on tool calls and active minutes, `/workcap`, see [Bundles](bundles.md#the-work-cap-bundle)), `chi bundle install ruby` (a plugin: an RSpec run with no examples at all, a hint, see [Bundles](bundles.md#the-ruby-bundle)) `chi bundle install skills` (a plugin: `/skill`, versions of skills, see [Bundles](bundles.md#the-skills-bundle)), `chi bundle install github-pr` (attached context: the branch's open PR, see [Bundles](bundles.md#the-github-pr-bundle)), `chi bundle install coordinator` (a plugin: parallel work in worktrees and child sessions, see [Bundles](bundles.md#the-coordinator-bundle)), `chi bundle install claude-peer` / `codex-peer` (a plugin: talk to a Claude Code or Codex session, see [Bundles](bundles.md#the-claude-peer-bundle)), `chi bundle install model-notes` (memories: reviewed model notes, see [Bundles](bundles.md#the-model-notes-bundle)) and `chi bundle install web-search` (a plugin: a `web_search` tool through your SearXNG, in no profile, see [Bundles](bundles.md#the-web-search-bundle)).
|
|
714
|
+
- Shipped bundles (each but web-search in a profile: `core` or `dev`, see [Bundle profiles](memory.md#bundle-profiles-core-and-dev)): `chi bundle install guardrails` (rules, see [Guardrails](guardrails.md#the-guardrails-bundle)) and `chi bundle install known-names` (a hook, see [Guardrails](guardrails.md#the-known-names-bundle)), `chi bundle install source-links` (a hook: announces source refs, see [The source-links bundle](#the-source-links-bundle)), `chi bundle install btw` (a plugin: `/btw`, see [Bundles](bundles.md#the-btw-bundle)), `chi bundle install mcp` (a plugin: tools from MCP servers, see [Bundles](bundles.md#the-mcp-bundle)) `chi bundle install loop-guard` (a plugin: breaks tool-call loops, see [Bundles](bundles.md#the-loop-guard-bundle)), `chi bundle install check-in` (a plugin: checks on a long turn, see [Bundles](bundles.md#the-check-in-bundle)), `chi bundle install slow-commands` (a plugin: commands that ran past the execute limit are run as tasks next time, see [Bundles](bundles.md#the-slow-commands-bundle)), `chi bundle install agents-md` (a plugin: a nested AGENTS.md is steered into the conversation on the first touch under its directory, see [Bundles](bundles.md#the-agents-md-bundle)), `chi bundle install cost-cap` (a plugin: a per-session $ cap, `/cap`, see [Bundles](bundles.md#the-cost-cap-bundle)), `chi bundle install work-cap` (a plugin: a per-session cap on tool calls and active minutes, `/workcap`, see [Bundles](bundles.md#the-work-cap-bundle)), `chi bundle install ruby` (a plugin: an RSpec run with no examples at all, a hint, see [Bundles](bundles.md#the-ruby-bundle)) `chi bundle install skills` (a plugin: `/skill`, versions of skills, see [Bundles](bundles.md#the-skills-bundle)), `chi bundle install github-pr` (attached context: the branch's open PR, see [Bundles](bundles.md#the-github-pr-bundle)), `chi bundle install coordinator` (a plugin: parallel work in worktrees and child sessions, see [Bundles](bundles.md#the-coordinator-bundle)), `chi bundle install claude-peer` / `codex-peer` (a plugin: talk to a Claude Code or Codex session, see [Bundles](bundles.md#the-claude-peer-bundle)), `chi bundle install model-notes` (memories: reviewed model notes, see [Bundles](bundles.md#the-model-notes-bundle)), `chi bundle install decision-card` (a plugin: a long answer's question as a card, see [Bundles](bundles.md#the-decision-card-bundle)), `chi bundle install inline-widgets` (a plugin: prompt sections that teach the `chi-ui` blocks chi web draws, see [Bundles](bundles.md#the-inline-widgets-bundle)) and `chi bundle install web-search` (a plugin: a `web_search` tool through your SearXNG, in no profile, see [Bundles](bundles.md#the-web-search-bundle)).
|
|
715
715
|
- Installing a bundle executes its hook code at `Engine` startup. Only install bundles you trust, as you would a gem. Hooks are **not** executed at install time (copy-only); they are `module_eval`'d at `Engine.new` inside per-bundle `Samagotchi::Bundles::<name>` namespaces (no top-level `require` collisions). Keep hook files side-effect-free at load time; do work in `#call` — top-level side effects (require, IO, `at_exit`, global assignment) run once per `Engine.new` (class redefinition is idempotent).
|
|
716
716
|
|
|
717
717
|
Lifecycle:
|
data/docs/internals/anthropic.md
CHANGED
|
@@ -36,7 +36,7 @@ Paths are under `lib/samagotchi/llm/`.
|
|
|
36
36
|
| `anthropic_wire.rb` | `AnthropicWire`: ChatLoop's wire messages as Messages' `system` and `messages`, the two breakpoints, tool ids and names |
|
|
37
37
|
| `anthropic_assembly.rb` | `AnthropicAssembly`: a response from a whole body (`.from_message`) or stream events (`#add`), its usage in the OpenAI shape |
|
|
38
38
|
| `dialect.rb` | `Dialect` (`STANDARD`, `FIREWORKS`): what a provider's `/v1/messages` does differently |
|
|
39
|
-
| `../tools/deferred_tools.rb` | `Tools::DeferredTools.list`: the tools a request declares deferred (Deferred tools) |
|
|
39
|
+
| `../tools/deferred_tools.rb` | `Tools::DeferredTools.list`: the tools a request declares deferred, from the turn's `ToolSurface` (Deferred tools) |
|
|
40
40
|
| `prompt_cache.rb` | `PromptCache.control`: the `cache_control` a breakpoint carries (`cache.ttl`) |
|
|
41
41
|
| `chat_loop.rb` | `ChatLoop#replay_blocks`, `#reasoning_history`'s floor, `Run#with_thinking` (saves `anthropic_content`), `#settle_dropped_thinking!` |
|
|
42
42
|
|
|
@@ -222,10 +222,10 @@ ones: the model sees their names only when something loads them, and the API acc
|
|
|
222
222
|
`AnthropicMessages#loads_tools?(model)` says whether a request does this: the dialect's `tool_loading`, unless the
|
|
223
223
|
host refused it for that model.
|
|
224
224
|
|
|
225
|
-
`ChatLoop#tool_definitions(conversation, model:)` appends them (`
|
|
225
|
+
`ChatLoop#tool_definitions(conversation, model:)` appends them (`ToolSurface#deferred_for`) only on such an
|
|
226
226
|
adapter, and only with at least one tool declared (Messages wants one). The list, per request:
|
|
227
227
|
|
|
228
|
-
1. the built-ins and plugin tools the toolkit reaches (`
|
|
228
|
+
1. the built-ins and plugin tools the toolkit reaches (`ToolSurface#index_only`), in registry order;
|
|
229
229
|
2. the tool index's source tools while `call_tool` is declared (`ToolIndex#deferrable`, via
|
|
230
230
|
`Registry::Index#deferrable`): callable, the only tool with its acts_as, a name Messages takes, no registered
|
|
231
231
|
tool's name; by acts_as (`mcp_<server>_<tool>`), sorted by name;
|
|
@@ -247,7 +247,7 @@ load nothing). `KernelLoop#dispatch` passes them on (`dispatched[:loaded]`), `To
|
|
|
247
247
|
result's `loaded:` names among them as a tool_result holding only
|
|
248
248
|
`{"type": "tool_reference", "tool_name": …}` blocks (Messages takes no other content beside a reference), followed by
|
|
249
249
|
a sibling text block: `Loaded: a, b. Call them directly by these names.`, then the result's text without its
|
|
250
|
-
`Call one with call_tool(…)` line (`
|
|
250
|
+
`Call one with call_tool(…)` line (`Tools::IndexHint::CALL_HINT`; the saved result keeps it). With that line and a trailing
|
|
251
251
|
"(call_tool works too)", Sonnet and Haiku 5.5 went through `call_tool` 2/2 live; without, 5/5 called the tool by
|
|
252
252
|
name. A result whose names aren't deferred here (declared since, or no tool loading) goes as plain text. The sibling
|
|
253
253
|
text is never marked; when breakpoint #2 falls on such a tool_result, it goes on its last reference.
|
|
@@ -270,7 +270,7 @@ sets `:tool_changes` for the model: the retry and every later request drop the s
|
|
|
270
270
|
|
|
271
271
|
A direct call of a deferred tool runs whether something loaded it or not (the API doesn't check): the Engine sets
|
|
272
272
|
`TurnSettings#loads_tools` from the turn's final model (after the before_turn hooks), and then `ToolRunner#run` and
|
|
273
|
-
`KernelLoop#dispatch` take a reachable built-in or plugin tool by its own name (`
|
|
273
|
+
`KernelLoop#dispatch` take a reachable built-in or plugin tool by its own name (`ToolSurface#entry_for`) through the normal gate, and wrap
|
|
274
274
|
an MCP tool's acts_as into the `call_tool` call it stands for (`ToolIndex#wrap`): `call_tool`'s row, rules and
|
|
275
275
|
approvals. A reload rebuilds that wrapped call from the saved one (`BuiltinCalls.wrap_saved`). Each such call is
|
|
276
276
|
logged (`tool_direct_deferred`, with `loaded:` whether the conversation had loaded it). On `api: openai` and the
|
|
@@ -144,8 +144,11 @@ source's why. `task_p < TASK_MIN` (0.5) leaves the candidate unjudged; `due?` de
|
|
|
144
144
|
lines (never twice at one owner-prompt count; one re-ask after `reask_after_turns`; then done). No answer writes
|
|
145
145
|
nothing, so the next owner prompt asks again.
|
|
146
146
|
|
|
147
|
-
The driver is the
|
|
148
|
-
|
|
147
|
+
The driver is the turn stage `TurnStages::ContextJudge` (`turn_stages/context_judge.rb`), not the judge:
|
|
148
|
+
`Engine#prepare_turn` calls its `start(turn, recorder:)` after the toolkit suggestion settled and before `apply_toolkit!` (an owner
|
|
149
|
+
turn's start; skipped for participants, review sessions and a Continue), and `Engine#judge_late_candidates` (a proposal
|
|
150
|
+
after the prompts) gives its `late_candidates` the session, the owner's messages, the recorder and the sessions dir
|
|
151
|
+
(none of it read with no session or in a review session); both make one pass (docs/internals/engine.md, "Turn stages").
|
|
149
152
|
It first logs status changes (`ContextCandidatesLog.look`), returns at `mode: off`, builds the due `Job`s, and hands
|
|
150
153
|
them to `SideJudgments` (`:context` kind: one thread, one batch per session at a time), asked at once on any host,
|
|
151
154
|
the model's own server too.
|
|
@@ -153,10 +156,10 @@ the model's own server too.
|
|
|
153
156
|
`ContextCandidateChoice.after_judged` acts on `fields["would"]` in `on` mode only: *attach* → `judge_attach` (a
|
|
154
157
|
session source with `JUDGE_WHY`, no probability in the model-visible why), *offer* → one card (`offer_card`, buttons
|
|
155
158
|
`/context attach NAME` and `/context decline NAME`, guarded by a `carded` log line). It re-checks that the candidate
|
|
156
|
-
is still proposed, since the user may have chosen while it was asked. Cards are shown through the
|
|
157
|
-
|
|
158
|
-
`/context attach|decline` command's body (`SessionCommands`), shared by the
|
|
159
|
-
session. An attach only writes the session folder: its note comes with the next between-turn delivery, never into a
|
|
159
|
+
is still proposed, since the user may have chosen while it was asked. Cards are shown through the stage's choice
|
|
160
|
+
lambda, which holds them while a turn runs; `run_turn`'s ensure shows them after `release_turn`
|
|
161
|
+
(`show_cards_after_turn`). `choose` is the `/context attach|decline` command's body (`SessionCommands`), shared by the
|
|
162
|
+
card's buttons; it refuses in a review session. An attach only writes the session folder: its note comes with the next between-turn delivery, never into a
|
|
160
163
|
running turn.
|
|
161
164
|
|
|
162
165
|
`ContextCandidatesLog` is `context_candidates.jsonl` beside the sessions folder (a `SideJudgments.log`: 0600, one
|
|
@@ -44,7 +44,7 @@ Behavior:
|
|
|
44
44
|
- `execute` and `task_create` both spawn with chi's own Ruby/Bundler setup scrubbed (`TaskRuntime.sanitized_spawn_env`): `RUBYOPT` loses its `-r…bundler/setup` flags (others stay) and `RUBYLIB` and what `bundle exec` sets (`BundlerEnv::VARS`: `BUNDLE_GEMFILE`, `BUNDLE_LOCKFILE`, `BUNDLE_BIN_PATH`, `BUNDLER_VERSION`, `BUNDLER_SETUP`) are unset, so a project's `ruby -e` or `bundle exec` uses its own Gemfile, or none, when chi runs under `bundle exec`. RubyGems requires what `BUNDLER_SETUP` names at boot, whatever `RUBYOPT` says. A project's own settings (`BUNDLE_PATH`, `BUNDLE_WITHOUT`) stay. `task_create` refuses those keys in the model's `env`, its error saying to write `KEY=value cmd` in the command instead; `execute`'s `env` comes from chi's callers (`Builtins`, `!cmd`), not the model, and is set over the scrub. An `execute` handed over at its limit keeps the process it spawned, so the task runs with the same env.
|
|
45
45
|
- `execute` and `task_create` export chi's own markers into the command, set over the model's `env` (which can't set them: `Error: env key is reserved`): `SAMAGOTCHI_PARENT_SESSION` (the session's id, `chi` without one; a chi started there answers as a parent agent), `SAMAGOTCHI_SESSION_MODEL` (the resolved ref the session runs on, read at each call so it follows `/model`; unset when unknown) `SAMAGOTCHI_SESSION_THINKING` (the session's own thinking level; unset when it has none) and `SAMAGOTCHI_SESSION_REASONING_HISTORY` (its own reasoning_history level, the same way). `chi self` reads the last three for its model, thinking level and reasoning history. The four are `ChildEnv::SESSION_MARKERS` (`TaskRuntime::MARKER_ENV_KEYS`), which a spawned worker unsets (`ChildEnv.unset`, merged into its spawn env). A session's worker never inherits them from whoever started it (a `chi send` run by another session's `execute`): its other commands (a user's `!cmd`, an MCP server, a context command) have none.
|
|
46
46
|
- They also pass on a set `XDG_STATE_HOME` / `XDG_CONFIG_HOME` made absolute (`Builtins.xdg_absolute`, via `Paths`), so a chi the command runs in another `cwd` (`chi send`) reads this chi's state and config. These aren't reserved: an XDG dir the model sets in `task_create`'s `env` stays its own.
|
|
47
|
-
- Every runner starts from the session's project env, `ProjectEnv.tools_env`: the overlay a spawned worker computed once at boot (`
|
|
47
|
+
- Every runner starts from the session's project env, `ProjectEnv.tools_env`: the overlay a spawned worker computed once at boot (`WorkerBoot.apply_project_env` → `ProjectEnv.compute` → `ProjectEnv.install!`; its folder's `mise env`, and the chi shim's dir first on PATH so `chi` is the chi home's), less `ProjectEnv::TOOLS_DROP` (`RUBYOPT`, `RUBYLIB`, Bundler's: the scrub above sets those). Outside a worker (`ProjectEnv::NONE`) it is `{}`. The sites: `execute` and `task_create` (`Tools::Builtins#project_env`, under the markers and the model's `env`; a participant's turn gets `{}`), the user's `!cmd` (`SessionCommands#shell`), and through `ProjectEnv.spawn_env` (the scrub above, then `tools_env`: what `execute` spawns with, for the runners that don't go through it) a context source's command (`ContextFetch#env_for`) and an MCP server, under the server's own keys (`bundles/mcp/plugin.rb` `server_env`, from mcp 0.7.4; no participant rule: the server is the session's). chi's own process env is never changed, and the project env never enters the prompt. User docs: [Project env](../sessions.md#project-env); the launch side: [How chi launches itself](../architecture.md#how-chi-launches-itself).
|
|
48
48
|
|
|
49
49
|
## Finish wake
|
|
50
50
|
|
|
@@ -16,7 +16,14 @@ model. The TUI is untouched: it shows a fence as source.
|
|
|
16
16
|
who draws what: `GET /api/block_renderers`, `:owner`. `GET /api/block_renderers/:bundle/:file` serves a file, `:owner`:
|
|
17
17
|
the URL's names go through `BlockRenderers.script_path` (membership in a listed renderer's `load` before any path is
|
|
18
18
|
made), then `Provenance.sha_matches?`; a changed file is 409 `renderer_changed`. ETag + `no-cache`, as static files.
|
|
19
|
-
3. `
|
|
19
|
+
3. `block_watch.js` (`createBlockWatch`, made by `block_host.js`'s `createBlockHost`, wired in `app.js`; `participant.js`
|
|
20
|
+
isn't) finds and watches the blocks; `block_host.js` is its frame drawer (`createFrameDrawer`). The watcher asks an
|
|
21
|
+
ordered list of drawers, core ones first (`inline_widgets.js` for `chi-ui`: [inline-widgets.md](inline-widgets.md)), then the frame drawer, which waits for `/api/block_renderers`;
|
|
22
|
+
the first that `claims` the block's language draws it, and a language none claims is left alone. The contract
|
|
23
|
+
(`claims`, `needsDraw`, `draw`, its `reconsider`, `sessionChanged`) is in the module's header. The shared DOM
|
|
24
|
+
helpers live there too: `failBlock` and its `.block-note` (a click copies it), `holdingView`, `rejoin`, the
|
|
25
|
+
toggle's listener; frames, the cache, hang marks, size checks, the zoom and the theme redraw stay in
|
|
26
|
+
`block_host.js`. One `MutationObserver` per turn root,
|
|
20
27
|
filtered to `TEXTS` (`text_roots.js`), so cards, the asking slot, question replies and delegate reports never draw, and
|
|
21
28
|
every path that adds a block to a root is seen the same way. One `IntersectionObserver` per scroller, with an explicit `root`
|
|
22
29
|
(with `root: null`, `rootMargin` doesn't pass an `overflow: auto` in between). Closed `<details>` fire on open. **A
|