samagotchi 0.70.0 → 0.72.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 +83 -1
- data/docs/architecture.md +16 -10
- data/docs/cli.md +7 -4
- data/docs/configuration.md +24 -14
- data/docs/hooks.md +1 -1
- data/docs/internals/anthropic.md +1 -1
- data/docs/internals/background-tasks.md +2 -2
- data/docs/internals/engine.md +38 -13
- data/docs/internals/llm-context-live.md +1 -1
- data/docs/internals/prompt-caching.md +6 -0
- data/docs/plugins.md +18 -7
- data/docs/sessions.md +4 -2
- data/docs/testing.md +12 -3
- data/lib/samagotchi/bootstrap/config_writer.rb +2 -3
- data/lib/samagotchi/bridge/turn_accumulator.rb +4 -1
- data/lib/samagotchi/bridge.rb +5 -2
- data/lib/samagotchi/broadcast/scope_card.rb +2 -2
- data/lib/samagotchi/bundles/claude-peer/manifest.yml +2 -7
- data/lib/samagotchi/bundles/claude-peer/plugin.rb +2 -2
- data/lib/samagotchi/bundles/codex-peer/manifest.yml +2 -6
- data/lib/samagotchi/bundles/codex-peer/plugin.rb +2 -2
- data/lib/samagotchi/bundles/coordinator/manifest.yml +8 -6
- data/lib/samagotchi/bundles/coordinator/plugin.rb +10 -0
- data/lib/samagotchi/bundles/coordinator/skill_coordinator.md +2 -1
- data/lib/samagotchi/bundles/system/config_modification_protocol.md +1 -1
- data/lib/samagotchi/bundles/system/manifest.yml +2 -2
- data/lib/samagotchi/config.rb +7 -25
- data/lib/samagotchi/context_note.rb +2 -6
- data/lib/samagotchi/effective_model.rb +1 -1
- data/lib/samagotchi/engine.rb +91 -213
- data/lib/samagotchi/engine_peers.rb +2 -0
- data/lib/samagotchi/event_routes.rb +83 -0
- data/lib/samagotchi/hook_routes.rb +16 -37
- data/lib/samagotchi/host_config.rb +1 -1
- data/lib/samagotchi/host_keys.rb +0 -2
- data/lib/samagotchi/paths.rb +13 -0
- data/lib/samagotchi/plugin/api.rb +11 -5
- data/lib/samagotchi/plugin/peer.rb +5 -8
- data/lib/samagotchi/prompt_files.rb +2 -4
- data/lib/samagotchi/session.rb +2 -1
- data/lib/samagotchi/session_manager.rb +6 -16
- data/lib/samagotchi/session_model_settings.rb +227 -0
- data/lib/samagotchi/session_setup.rb +2 -1
- data/lib/samagotchi/sessions_command.rb +12 -3
- data/lib/samagotchi/system_prompt.rb +18 -13
- data/lib/samagotchi/terminal_ui/attached_loop.rb +36 -15
- data/lib/samagotchi/terminal_ui/formatting.rb +4 -0
- data/lib/samagotchi/tool_activity.rb +20 -1
- data/lib/samagotchi/tool_declarations.rb +4 -0
- data/lib/samagotchi/tool_output_cut.rb +11 -2
- data/lib/samagotchi/toolkit.rb +60 -22
- data/lib/samagotchi/toolkit_binding.rb +7 -5
- data/lib/samagotchi/toolkit_command.rb +28 -5
- data/lib/samagotchi/tools/builtins.rb +2 -1
- data/lib/samagotchi/tools/delegate.rb +32 -6
- data/lib/samagotchi/tools/list_sessions.rb +2 -2
- data/lib/samagotchi/tools/peers.rb +5 -2
- data/lib/samagotchi/tools/register_reminder.rb +1 -0
- data/lib/samagotchi/tools/registry.rb +13 -2
- data/lib/samagotchi/tools/task_wait.rb +4 -6
- data/lib/samagotchi/tools/tool_index.rb +15 -4
- data/lib/samagotchi/turn_note.rb +4 -1
- data/lib/samagotchi/version.rb +1 -1
- data/lib/samagotchi/web/app.rb +18 -17
- data/lib/samagotchi/web/message_parts.rb +1 -1
- data/lib/samagotchi/web/public/answer_refs.js +1 -0
- data/lib/samagotchi/web/public/app.js +20 -18
- data/lib/samagotchi/web/public/bubbles.js +1 -1
- data/lib/samagotchi/web/public/cards_place.js +6 -10
- data/lib/samagotchi/web/public/chains.js +1 -1
- data/lib/samagotchi/web/public/chip_popover.js +3 -1
- data/lib/samagotchi/web/public/composer.js +13 -6
- data/lib/samagotchi/web/public/context_chips.js +25 -12
- data/lib/samagotchi/web/public/data.js +5 -1
- data/lib/samagotchi/web/public/format.js +5 -0
- data/lib/samagotchi/web/public/index.html +1 -0
- data/lib/samagotchi/web/public/sessions_list.js +2 -3
- data/lib/samagotchi/web/public/stage_frame.js +1 -1
- data/lib/samagotchi/web/public/stage_view.js +8 -2
- data/lib/samagotchi/web/public/stream_handlers.js +6 -3
- data/lib/samagotchi/web/public/timing.js +1 -1
- data/lib/samagotchi/web/public/toolkit_chip.js +3 -1
- data/lib/samagotchi/web/public/turn_html.js +55 -3
- data/lib/samagotchi/web/session_hub.rb +8 -0
- metadata +3 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 6421f740a2683f0dcf3d24b92fba7bba62bed9edb92ddfd532ce69c74e14e0e8
|
|
4
|
+
data.tar.gz: 23841684a58d0a3efedddcd0fb0caef4d1403c61a88268ad79f6b28a9d8f00ab
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 91ccf28b2be3f0bfff968c5d0448b0c1748ef90c505f1195ec655ae93784e48975409e54a56e18d7f78605812770d4ec9eeae336208da1a95ddbab2aa057f3da
|
|
7
|
+
data.tar.gz: c5f8e40dfea68d7d6d706970106cbbdc5caf8e9571b92d771dc2928d6a3358704aafcd6b3a047f96ccfbe285b28ee2bc98de81505f10a342cc8b6efc228b0b9c
|
data/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,86 @@ and commands may change between minor versions. How releases are made:
|
|
|
8
8
|
|
|
9
9
|
## [Unreleased]
|
|
10
10
|
|
|
11
|
+
## [0.72.0] - 2026-10-16
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
|
|
15
|
+
- A toolkit can carry a prompt text (`toolkit.kits.<name>.prompt:`, `chi.toolkit … prompt:`): the sessions on it
|
|
16
|
+
get it in their system prompt, others don't; `/toolkit`, `/stats` and the web's tools chip show it. `delegate`
|
|
17
|
+
can start a child on a named toolkit (`toolkit:`). The coordinator bundle (0.5.0) declares a `coding` toolkit
|
|
18
|
+
(`child`'s tools plus "Be concise in your responses" and "Show file paths clearly when working with files"),
|
|
19
|
+
and its skill starts build and fix children on it.
|
|
20
|
+
|
|
21
|
+
### Removed
|
|
22
|
+
|
|
23
|
+
- `SAMAGOTCHI_HOSTS_JSON`: chi no longer reads it (workers stopped inheriting it in 0.64.0). Hosts come only from
|
|
24
|
+
config.yml's `hosts:`; one still exported in your shell is ignored.
|
|
25
|
+
|
|
26
|
+
### Fixed
|
|
27
|
+
|
|
28
|
+
- Attached TUI: a turn of images alone sent from the web names each image once while you watch it start (or join
|
|
29
|
+
it running), not twice.
|
|
30
|
+
- Attached TUI: joining a session shows a call the guardrails denied as `blocked`, as it showed live and as the
|
|
31
|
+
web shows it, instead of `error`.
|
|
32
|
+
- Web: an answer's file ref outside the session's folder is dropped from the end-of-turn re-read of a running
|
|
33
|
+
session too, as a reload drops it, instead of showing until the reload.
|
|
34
|
+
- Plugins: a turn no longer fails with "can't add a new key into hash during iteration" when a plugin's
|
|
35
|
+
`replace_tools` registers a tool while a page reads the session's settings (no MCP server loaded).
|
|
36
|
+
- `call_tool` given the bare name of a tool the session declares (`read`) answers at once that it's declared and
|
|
37
|
+
should be called directly, instead of first waiting for every MCP server still starting.
|
|
38
|
+
- Web: a `/model`, `!command` or chip change still in flight when you open another session no longer acts on
|
|
39
|
+
that one: it no longer marks it as held by a terminal, puts the failure in its history or follows its worker,
|
|
40
|
+
and a card's action button no longer follows it either; an after-turn hook's answer re-read no longer lands in it.
|
|
41
|
+
- Web: a stop the server refuses (the stop button in the session bar) now says why in a toast instead of nothing.
|
|
42
|
+
- Web: a failure the server explains (a refused `/model`, send, archive, attach…) shows its words alone, without an
|
|
43
|
+
HTTP status after them (`a terminal chi holds it`, not `… (409)`); the status shows only when the server gave no words.
|
|
44
|
+
- Web: opening another session right as a finished turn slides into the history no longer shows that turn in the
|
|
45
|
+
new session's history, and its "Loading…" line stays until the session is drawn.
|
|
46
|
+
- Web: opening a chip's popover (llm ctx, thinking, reasoning history, attached context) closes the one already
|
|
47
|
+
open, instead of leaving both open.
|
|
48
|
+
- The empty-answer retry note asks the model to continue the task (its next tool call) or answer if it is done,
|
|
49
|
+
instead of "answer the user's last message now, briefly", which made a mid-task model stop before its last steps.
|
|
50
|
+
|
|
51
|
+
Update with `chi update` (the system bundle 0.72.0, coordinator 0.5.0, claude-peer 0.4.1, codex-peer 0.3.1), then
|
|
52
|
+
restart `chi web`.
|
|
53
|
+
|
|
54
|
+
## [0.71.0] - 2026-10-15
|
|
55
|
+
|
|
56
|
+
### Changed
|
|
57
|
+
|
|
58
|
+
- Web: an `execute` row, and a `task_wait` row showing its log's last lines, now shows the end of its output (a
|
|
59
|
+
test run's summary, a failing exit line) instead of the start, without the success `exit: 0` line or a lone
|
|
60
|
+
`stdout:` label; the whole output stays on hover.
|
|
61
|
+
- `task_wait` on a task that finished now returns the last lines of its log too (`output_tail:`, `tail_lines` of
|
|
62
|
+
them, 10 by default), as a timed-out wait does: a test run's summary or an error is there without reading the
|
|
63
|
+
log; its web row shows them.
|
|
64
|
+
- Web: a page opened mid-turn (or reconnecting) gets each tool's output cut as a reload does (2000 characters),
|
|
65
|
+
so a joined row matches the reloaded one and the snapshot is smaller.
|
|
66
|
+
- Web: a tool row whose call the guardrails corrected shows its output without the `ran as: …` line inline (it
|
|
67
|
+
stays on hover).
|
|
68
|
+
|
|
69
|
+
### Fixed
|
|
70
|
+
|
|
71
|
+
- A command a signal ended (a segfault, an OOM kill: its result ends `exit: ` with no number) is read as finished:
|
|
72
|
+
a long output's cut keeps its exit line apart and tells the model not to rerun it (the saved file is the whole
|
|
73
|
+
output), and its web row shows the output's end as other failed commands' do.
|
|
74
|
+
- `chi sessions`: a `--days`, `--keep` or `--limit` that isn't a whole number (`--days=abc`) is now a usage error
|
|
75
|
+
(exit 2) instead of being read as 0, which turned `prune`'s age limit off; the usage now lists `clean --all`.
|
|
76
|
+
- `full` with `--no-tool call_tool` (or `find_tools`) and no MCP server no longer adds a "Not loaded in this
|
|
77
|
+
session" line to the system prompt nor a web toolkit chip: there call_tool reaches nothing, so nothing is left
|
|
78
|
+
out.
|
|
79
|
+
- A `toolkit.kits` entry with a key other than `base:`, `add:` and `remove:` (a typo, a `tools:` list) now warns
|
|
80
|
+
(once, as the toolkit's other config warnings) instead of being ignored silently; the kit still loads.
|
|
81
|
+
- Attached terminal: a session's reloaded tool rows read each result as the live row did: a command handed over
|
|
82
|
+
as a task is no longer shown failed because its output so far had `exit: 1`, and a failed `execute`
|
|
83
|
+
(`Error: …`) is no longer shown done.
|
|
84
|
+
- A `task_wait` row is marked stopped only by the wait's own status, not by a `status: stopped` line the task's
|
|
85
|
+
log printed.
|
|
86
|
+
- A `task_wait` whose task failed (exited non-zero, or without an exit code) is now marked failed in the web and
|
|
87
|
+
terminal rows and counted in the turn's "(N failed)", as a failing `execute` is.
|
|
88
|
+
|
|
89
|
+
Update with `chi update` (the system bundle 0.71.0), then restart `chi web`.
|
|
90
|
+
|
|
11
91
|
## [0.70.0] - 2026-10-15
|
|
12
92
|
|
|
13
93
|
### Added
|
|
@@ -3029,7 +3109,9 @@ and long-lived sessions.
|
|
|
3029
3109
|
- A macOS desktop helper (`chi desktop install`): a "Send to chi" Service and a
|
|
3030
3110
|
hotkey panel that send selected text or the clipboard to your sessions.
|
|
3031
3111
|
|
|
3032
|
-
[Unreleased]: https://github.com/dm1try/samagotchi/compare/v0.
|
|
3112
|
+
[Unreleased]: https://github.com/dm1try/samagotchi/compare/v0.72.0...HEAD
|
|
3113
|
+
[0.72.0]: https://github.com/dm1try/samagotchi/compare/v0.71.0...v0.72.0
|
|
3114
|
+
[0.71.0]: https://github.com/dm1try/samagotchi/compare/v0.70.0...v0.71.0
|
|
3033
3115
|
[0.70.0]: https://github.com/dm1try/samagotchi/compare/v0.69.0...v0.70.0
|
|
3034
3116
|
[0.69.0]: https://github.com/dm1try/samagotchi/compare/v0.68.0...v0.69.0
|
|
3035
3117
|
[0.68.0]: https://github.com/dm1try/samagotchi/compare/v0.67.0...v0.68.0
|
data/docs/architecture.md
CHANGED
|
@@ -44,7 +44,7 @@ A compact visual overview of the current architecture, then the core API in pros
|
|
|
44
44
|
│ execute · read · edit · write · memory_read/write · web_fetch · │
|
|
45
45
|
│ task_create/get/list/stop/wait · delegate · delegate_result · ask_user_question │
|
|
46
46
|
│ register_reminder/cancel_reminder/list_reminders · send_note · list_sessions · │
|
|
47
|
-
│ context_read · forget_outputs (+ bundle plugin tools)
|
|
47
|
+
│ context_read · forget_outputs · find_tools · call_tool (+ bundle plugin tools) │
|
|
48
48
|
│ offered by Tools::Registry (Builtins + bundles), filtered by the toolkit │
|
|
49
49
|
└──────────────────────────────────────────────────────────────────────────────────┘
|
|
50
50
|
│
|
|
@@ -101,7 +101,7 @@ terminal renders the events it gets over the Bridge.
|
|
|
101
101
|
| UI | `Samagotchi::TerminalUI` | REPL (Reline), rendering, REPL commands. Delegates all core work to an `Engine`. |
|
|
102
102
|
| 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). |
|
|
103
103
|
| 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. |
|
|
104
|
-
| 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, forget_outputs, plus runtime/output-guardrails. |
|
|
104
|
+
| 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, forget_outputs, find_tools/call_tool (the tool index), plus runtime/output-guardrails. |
|
|
105
105
|
| Bundles | `lib/samagotchi/memory_bundle/*`, `BundleCommand` | `chi bundle`: install/upgrade (3-way merge), build, uninstall; the install record under `.bundles/<name>/` that the hook, guardrail and plugin loaders read ([internals/bundles.md](internals/bundles.md)). |
|
|
106
106
|
| 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. |
|
|
107
107
|
| 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`. |
|
|
@@ -208,7 +208,8 @@ engine.session # current session (Engine owns create/resume)
|
|
|
208
208
|
The system prompt (`SystemPrompt#build`, assembled in `#system_prompt_with_index`) is the
|
|
209
209
|
base prompt, then the toolkit's "Not loaded in this session" line (only when the toolkit
|
|
210
210
|
leaves tools out), rg guidance, the identity, the model notes, the preloaded memories,
|
|
211
|
-
AGENTS.md (root → cwd), the appended files (`--append-system-prompt`), the
|
|
211
|
+
AGENTS.md (root → cwd), the appended files (`--append-system-prompt`), the toolkit's
|
|
212
|
+
kit prompt (a kit's `prompt:` text, only when it has one), the memory
|
|
212
213
|
indexes, and last **the model** (`Model: this session runs on <ref> (host …; model key …)` and a line telling
|
|
213
214
|
the model to answer "which model are you" from it, not from training), the working
|
|
214
215
|
directory and the session id and log (Gemma's native tool declarations still follow).
|
|
@@ -307,6 +308,7 @@ process that already owns the `Engine`); every worker starts it, and it exposes:
|
|
|
307
308
|
the messages itself, then streams from its `event_seq`). Read by the web's full show
|
|
308
309
|
(`GET /api/sessions/:id`, `?parts=1`) and the plugin's `list_sessions`; every message is copied.
|
|
309
310
|
- `GET /session/:id/tail` — the page's light re-read (`Bridge#tail_frame`): `session_state_snapshot`,
|
|
311
|
+
`working_directory` (the session's folder, which the web checks the answer's file refs against),
|
|
310
312
|
`answer` (the last message a UI shows as an answer, `AnswerTail`: the one message, copied alone),
|
|
311
313
|
`cards` (`CardStore#list`; a card an earlier worker showed during a turn comes back read-only, with no
|
|
312
314
|
actions: its turn no longer runs), `event_seq`, `event_id`, all taken in one event-log hold; no message
|
|
@@ -337,9 +339,11 @@ The page's frequent reads of `GET /api/sessions/:id` stay light too:
|
|
|
337
339
|
alone (no session file parsed, no `analytics.json`); `timing` carries the worker's recent records
|
|
338
340
|
and `turn_count` (finished turns). The page merges the records by id (`timing.js mergeTiming`) and
|
|
339
341
|
finishes the ended turn's own line by its `turn_id` (sent as `&turn_id=`, which also picks that
|
|
340
|
-
turn's answer). A
|
|
342
|
+
turn's answer). A tail read's timing is always the newest turn's; `recent=1` is accepted and not needed.
|
|
341
343
|
The page binds an answer's `display_refs` to its bubble (`answer_refs.js`: on a reload's render and on this
|
|
342
|
-
read's re-render) and pairs them with the bubble's links and text before the `path:line` scan.
|
|
344
|
+
read's re-render) and pairs them with the bubble's links and text before the `path:line` scan. A file ref outside the
|
|
345
|
+
session's folder is dropped, as a reload drops it: the folder `/tail` names, else (an older worker) the hub's
|
|
346
|
+
session list entry's.
|
|
343
347
|
A plugin tool's row refs (`refs`, `RowRefs`) ride its tool events and, on a reload, its part (saved as
|
|
344
348
|
`tool_refs`); `turn_view.js` binds them to the row's title (`refs.js bindRowRefs`: the first on the title,
|
|
345
349
|
the others in its menu).
|
|
@@ -349,7 +353,7 @@ The page's frequent reads of `GET /api/sessions/:id` stay light too:
|
|
|
349
353
|
|
|
350
354
|
A worker without `/tail` (an older chi; `404 not_found`) is read through `/snapshot` in the same
|
|
351
355
|
shape; any other failure (no worker, a 500, a timeout) reads the disk, trimmed to the newest
|
|
352
|
-
turn's records
|
|
356
|
+
turn's records.
|
|
353
357
|
|
|
354
358
|
Every route goes through `Bridge#dispatch`: an id other than the bridge's own session is
|
|
355
359
|
`404 unknown_session`, and a handler that raises answers `500 bridge_error` (logged as
|
|
@@ -490,7 +494,7 @@ server (`/props`), then the host's model list, then config.
|
|
|
490
494
|
**Keys.** A host's API key comes from the environment variable its
|
|
491
495
|
`api_key_env:` names, else, on macOS, the login Keychain's item for that name (`HostKeys`, read through
|
|
492
496
|
`/usr/bin/security` with a deadline; hits cached per process; `SAMAGOTCHI_KEYCHAIN=off` skips it); it never
|
|
493
|
-
reaches config.yml, `
|
|
497
|
+
reaches config.yml, `chi self`, logs or events.
|
|
494
498
|
|
|
495
499
|
## Other components
|
|
496
500
|
|
|
@@ -504,7 +508,7 @@ A map of the parts the overview above doesn't name (paths under `lib/samagotchi/
|
|
|
504
508
|
| Plugin API | `plugin/api.rb` (`Plugin::Api`), `plugin/tool_spec.rb` (`Plugin::ToolSpec`: a checked tool declaration, how it is registered), `plugin/loader.rb` | What a bundle's plugin registers: tools, commands, annotation actions, hooks, services, toolkits, peer sources ([plugins.md](plugins.md)). |
|
|
505
509
|
| Peer bundles' base | `plugin/peer.rb` (`Plugin::Peer`) | What claude-peer and codex-peer share (the send tool, the command, the cards, payloads); each bundle's subclass sets its strings and transport ([plugins.md](plugins.md#the-claude-peer-bundle)). |
|
|
506
510
|
| Shipped bundles | `bundles/` (`mcp`, `github-pr`, `loop-guard`, `skills`, `source-links`, …) | Bundles that ship with chi. |
|
|
507
|
-
| Hooks | `hooks/registry.rb` (`Hooks::Registry`), `hooks/loader.rb`, `hook_routes.rb` (`HookRoutes`) | Hook registration and dispatch; what a hook or plugin does beyond reading its event (notice, question, stop, steer) routed to the UIs ([hooks.md](hooks.md)). |
|
|
511
|
+
| Hooks | `hooks/registry.rb` (`Hooks::Registry`), `hooks/loader.rb`, `hook_routes.rb` (`HookRoutes`), `event_routes.rb` (`EventRoutes`) | Hook registration and dispatch; what a hook or plugin does beyond reading its event (notice, question, stop, steer) routed to the UIs (cards and notices through one set of routes) ([hooks.md](hooks.md)). |
|
|
508
512
|
| Guardrails | `guardrails.rb`, `guardrails/shell_lex.rb`, `guardrails/rules.rb`, `guardrail_wiring.rb` | The gate before every tool call: shell lexing, YAML rules, approvals ([guardrails.md](guardrails.md)). |
|
|
509
513
|
| Delegation | `tools/delegate.rb`, `tools/delegate_result.rb`, `tools/delegate_wait.rb`, `child_reports.rb`, `relay_desk.rb` | Child sessions a session starts and waits on, and their approval relay ([sessions.md](sessions.md#delegating)). |
|
|
510
514
|
| send / broadcast | `send_command.rb` (`SendCommand`), `broadcast_command.rb` (`BroadcastCommand`), `broadcast/` | `chi send` and `chi broadcast` ([broadcast.md](broadcast.md), [sub-agent.md](sub-agent.md)). |
|
|
@@ -514,11 +518,13 @@ A map of the parts the overview above doesn't name (paths under `lib/samagotchi/
|
|
|
514
518
|
| Session chains | `session_continue.rb` (`SessionContinue`), `session_chain.rb` (`SessionChain`) | A session that continues an earlier one. |
|
|
515
519
|
| Analytics | `analytics_file.rb` (`AnalyticsFile`) | A session's `analytics.json` (`SessionMetrics#persist`). |
|
|
516
520
|
| Images / vision | `image_store.rb` (`ImageStore`), `vision_support.rb`, `vision_context.rb` | Stored prompt images and whether a model takes them. |
|
|
517
|
-
| Toolkits | `toolkit.rb` (`Toolkit`), `toolkit_binding.rb` (`ToolkitBinding`, the Engine's seam), `toolkit_command.rb` (`/toolkit`), `tools/registry.rb` (`Registry#toolkit`, `#left_out_names`), `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; `chi.toolkit` and `ctx.use_toolkit` for plugins ([configuration.md](configuration.md#toolkits)). |
|
|
521
|
+
| Toolkits | `toolkit.rb` (`Toolkit`), `toolkit_binding.rb` (`ToolkitBinding`, the Engine's seam), `toolkit_command.rb` (`/toolkit`), `tools/registry.rb` (`Registry#toolkit`, `#left_out_names`), `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)). |
|
|
522
|
+
| Tool index | `tools/tool_index.rb` (`Tools::ToolIndex`) | `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)). |
|
|
523
|
+
| Tool output cut | `tool_output_cut.rb` (`ToolOutputCut`), `tool_output_files.rb` (`ToolOutputFiles`) | A tool's output over `max_tool_output_chars`, cut by the tool's policy; an execute's whole output saved in the session's `tool_output/` folder ([internals/tool-guardrails.md](internals/tool-guardrails.md)). |
|
|
518
524
|
| 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)). |
|
|
519
525
|
| Prompt files | `prompt_files.rb` (`PromptFiles`) | The AGENTS.md chain (root → cwd) and the appended files the system prompt carries. |
|
|
520
526
|
| Model settings | `effective_model.rb` (`EffectiveModel`, `ModelChoice`), `model_profile.rb` (`ModelProfile`), `model_settings.rb`, `sampling_settings.rb`, `model_catalog.rb` (`ModelCatalog`), `model_notes.rb` (`ModelNotes`) | The effective model's settings as one snapshot per read, a model's prompt format, its `models:` entry, its request parameters, the pickable model rows (`chi models`, `/api/models`), the notes its prompt loads. |
|
|
521
|
-
| Session settings | `session_setting.rb` (`SessionSetting`), `level_setting_command.rb` (`/thinking`, `/reasoning-history`), `llm_context_command.rb`, `toolkit_command.rb`, `thinking_notices.rb` (`ThinkingNotices`) | A session's own llm_context, thinking, reasoning_history and toolkit: their chips (session state, `/stats`, `:command_ran`, the web), the commands that set them, the thinking level's notices. |
|
|
527
|
+
| Session settings | `session_setting.rb` (`SessionSetting`), `session_model_settings.rb` (`SessionModelSettings`), `level_setting_command.rb` (`/thinking`, `/reasoning-history`), `llm_context_command.rb`, `toolkit_command.rb`, `thinking_notices.rb` (`ThinkingNotices`) | A session's own llm_context, thinking, reasoning_history and toolkit: their chips (session state, `/stats`, `:command_ran`, the web), the commands that set them, the thinking level's notices. |
|
|
522
528
|
| Dialects | `llm/dialect.rb` (`LLM::Dialect`) | What an `api: anthropic` provider's `/v1/messages` does differently (`dialect: fireworks`) ([internals/anthropic.md](internals/anthropic.md)). |
|
|
523
529
|
| Logging | `log.rb` (`Log`), `log_subscriber.rb` (`LogSubscriber`), `log_path.rb` (`LogPath`), `log_line.rb` | The debug log: tagged records, a session's event trail, where the file goes ([configuration.md](configuration.md#debug-log-file)). |
|
|
524
530
|
| Stores | `reminder_store.rb` (`ReminderStore`), `recap_store.rb` (`RecapStore`) | A session's reminders, and its idle recap (`recap.json`). |
|
data/docs/cli.md
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
- `chi web --web-host lan` — the Web UI on your home network too, for your phone: a link with an access token and its QR code (see [chi web on your phone](#chi-web-on-your-phone)); `chi web --new-token` replaces the token
|
|
16
16
|
- `chi web --web-markdown` — opt in to sanitized Markdown rendering for completed assistant messages
|
|
17
17
|
- `chi web --web-view turn` — draw turns with the turn view (each turn as one block of steps, the running one at the bottom of the history) instead of the default stage view (the running turn pinned above the composer); `?view=stage|turn` on the page URL overrides it (see [Web views](#web-views))
|
|
18
|
-
- `chi sessions list|stop|restart|archive|unarchive|delete|prune|clean|stats` — manage persisted sessions; `list` shows this git project's, `list --scope=all` every one, a delegated session with `↳ <parent>`, `list --archived` the archived ones too (see [Sessions](sessions.md)). `stats ID` prints a session's cost, tokens and progress (a live worker's `GET stats`, else its saved `analytics.json`; `--format json` one object) without running a model turn. A usage error (an unknown subcommand or flag, a flag missing its value, `stop`, `restart` or `delete` with no ids, a bad `list --format` or `--scope`) exits 2; an unknown or refused session exits 1
|
|
18
|
+
- `chi sessions list|stop|restart|archive|unarchive|delete|prune|clean|stats` — manage persisted sessions; `list` shows this git project's, `list --scope=all` every one, a delegated session with `↳ <parent>`, `list --archived` the archived ones too (see [Sessions](sessions.md)). `stats ID` prints a session's cost, tokens and progress (a live worker's `GET stats`, else its saved `analytics.json`; `--format json` one object) without running a model turn. A usage error (an unknown subcommand or flag, a flag missing its value, `stop`, `restart` or `delete` with no ids, a bad `list --format` or `--scope`, a `--days`, `--keep` or `--limit` that isn't a whole number) exits 2; an unknown or refused session exits 1
|
|
19
19
|
- `chi note [--source NAME] [-m TEXT] (ID|PREFIX)... | --all` — add a context note (TEXT or stdin) to sessions: background the model sees on its next turn; it starts no turn (see [Sessions: Context notes](sessions.md#context-notes))
|
|
20
20
|
- `chi context <add|push|ls|show|refresh|rm|mute|unmute> …` — attach live external text to sessions (a command chi runs every so often, or text pushed in); the model gets a short note when it changes and reads it with `context_read`; `chi context add <URL>` attaches a GitHub PR with the github-pr bundle (see [Attached context](context.md))
|
|
21
21
|
- `chi send [-m TEXT] [--image PATH]... [--cut | --queue] (ID|PREFIX)...` — send a message to sessions as if typed there: a turn starts (or a running one takes it at its next step; `--cut` asks it to cut long thinking for it; `--queue` runs it as a turn of its own after the running one, and `--queue --wait` waits for that turn's own answer); piped stdin goes above `-m` as quoted context, and `--image` attaches images (see [Sessions: Sending a message](sessions.md#sending-a-message)); `--new` starts a session with it instead (`--new --continues ID|last:ID` the next link of that session's chain, see [Session chains](sessions.md#session-chains)), and `--wait` prints the answer (`--wait ID` with no message waits for the next reply without sending; `--format json` prints one JSON object instead; exit 3 a question waits, its options on stderr; exit 4 `--timeout` passed with the turn still running; see [Starting a session](sessions.md#starting-a-session))
|
|
@@ -459,7 +459,7 @@ request (with the cached tokens, the cache writes, the re-prefilled tokens and t
|
|
|
459
459
|
reports them),
|
|
460
460
|
the decode speed, generation latency, cancellations, retries (the network's),
|
|
461
461
|
thinking cuts (generations a plugin such as loop-guard cut) and output cap hits
|
|
462
|
-
(generations that ended at the provider's cap), context used and window (the used figure is counted against the smaller of the window and the session's LLM context budget, and says so: `context used: 16000 tokens (25.0% of the 64000 budget)`), the memory indexes the session's prompt holds ([Memory](memory.md#the-indexs-size)), the model notes it carried (`model notes: model_notes_deepseek (system, 612 chars)`, none without any; [Memory](memory.md#model-notes)), the prompt profile and the model the server says it ran, and the
|
|
462
|
+
(generations that ended at the provider's cap), context used and window (the used figure is counted against the smaller of the window and the session's LLM context budget, and says so: `context used: 16000 tokens (25.0% of the 64000 budget)`), the memory indexes the session's prompt holds ([Memory](memory.md#the-indexs-size)), the model notes it carried (`model notes: model_notes_deepseek (system, 612 chars)`, none without any; [Memory](memory.md#model-notes)), the toolkit's prompt text (`kit prompt: coding (~20 tokens)`, only when its kit has one; [Toolkits](configuration.md#toolkits)), the prompt profile and the model the server says it ran, and the
|
|
463
463
|
cost when the provider reports one (OpenRouter's `usage.cost`), and the cost
|
|
464
464
|
estimated from a price under `hosts.<name>.models` when it reports none or 0,
|
|
465
465
|
marked `~` and naming the current model's host (`cost: $0.42 reported + ~$0.12 from hosts.gw.models prices (this session only)`;
|
|
@@ -520,7 +520,8 @@ line, the web as the `reasoning` chip. See "Reasoning history" in
|
|
|
520
520
|
tokens), the session's toolkit and the tools it leaves out: `reachable
|
|
521
521
|
(find_tools): …` (built-ins the model reaches with find_tools and call_tool)
|
|
522
522
|
and `removed: …` (only `/toolkit add` brings one back), or `not loaded: …` when
|
|
523
|
-
the toolkit removes call_tool
|
|
523
|
+
the toolkit removes call_tool, and its kit's prompt text when it has one (`prompt: <first line> (+N lines, ~T
|
|
524
|
+
tokens)`). `/toolkit remove TOOL` is hard: a tool the
|
|
524
525
|
toolkit left out reachable becomes unreachable (saved, and asked first once the
|
|
525
526
|
session has a model reply), also after an add. `/toolkit NAME` puts
|
|
526
527
|
the session on another toolkit (dropping its own adds and removes); `/toolkit
|
|
@@ -766,7 +767,9 @@ tool rows), the earlier ones stack above it collapsed to one line each
|
|
|
766
767
|
(their narration's first line, else their first call's title such as
|
|
767
768
|
`edit lib/a.rb`, and a call count), expandable for inspection. A tool row
|
|
768
769
|
says what the call did: a file's path relative to the session's folder, a
|
|
769
|
-
command without its leading `cd … &&` (the full parameters on hover).
|
|
770
|
+
command without its leading `cd … &&` (the full parameters on hover). Under it a done row shows its
|
|
771
|
+
output's first 300 characters; an `execute` and a `task_wait` with its log's tail show the last ones (a test
|
|
772
|
+
run's summary, a failing exit line), without the success `exit: 0` line; a gate-corrected call's `ran as:` line only on hover; all of it on hover. The live thinking is one line: the
|
|
770
773
|
newest complete sentence, changing at most once per 1.5 s. Click it for the
|
|
771
774
|
full text; a peek is per step (the next step's thinking starts closed
|
|
772
775
|
again). When a step ends its thinking closes to a plain `thinking` line
|
data/docs/configuration.md
CHANGED
|
@@ -107,9 +107,8 @@ Behavior:
|
|
|
107
107
|
edit at once). A worker gets the CLI flags of the chi that started it
|
|
108
108
|
through its environment.
|
|
109
109
|
- A worker reads `hosts:` from the file as it starts, as every other setting, so a delegate (or any session
|
|
110
|
-
started later) sees a host added after its parent started.
|
|
111
|
-
|
|
112
|
-
it (`SessionManager.spawn_options` unsets it).
|
|
110
|
+
started later) sees a host added after its parent started. Hosts come only from config.yml: no environment
|
|
111
|
+
variable sets them.
|
|
113
112
|
|
|
114
113
|
This lets you run `chi` without repeating common defaults such as model
|
|
115
114
|
and llama host/port on every invocation.
|
|
@@ -1330,6 +1329,7 @@ toolkit:
|
|
|
1330
1329
|
child: child # delegate children (unset: full)
|
|
1331
1330
|
kits: # your own, on a base
|
|
1332
1331
|
review: { base: lean, add: [web_fetch, delegate], remove: [memory_write] }
|
|
1332
|
+
terse: { base: lean, prompt: "- Be concise in your responses" }
|
|
1333
1333
|
```
|
|
1334
1334
|
|
|
1335
1335
|
| toolkit | declares |
|
|
@@ -1338,15 +1338,25 @@ toolkit:
|
|
|
1338
1338
|
| `lean` | `execute`, `read`, `write`, `edit`, `memory_read`, `memory_write`, `task_create`, `task_wait`, `task_get`, `task_list`, `task_stop`, `ask_user_question`, `web_fetch`, `context_read` |
|
|
1339
1339
|
| `child` | `lean` plus `send_note`, without `memory_write`, `delegate`, `delegate_result` |
|
|
1340
1340
|
| `coordinator` | `lean` plus `delegate`, `delegate_result`, `list_sessions` (declared by the coordinator bundle) |
|
|
1341
|
+
| `coding` | `child`, with the prompt text `- Be concise in your responses` / `- Show file paths clearly when working with files` (declared by the coordinator bundle, for build and fix children) |
|
|
1341
1342
|
|
|
1342
1343
|
- **Plugin tools** are declared in every toolkit unless its `remove:` names them, and so is `forget_outputs` under
|
|
1343
|
-
the `forget` layer. A `kits:` entry takes `base:` (default `full`), `add:` and `
|
|
1344
|
-
built-in's name. A bundle declares its own with `chi.toolkit` ([plugins](plugins.md#chitoolkitname-base-add--remove-)).
|
|
1344
|
+
the `forget` layer. A `kits:` entry takes `base:` (default `full`), `add:`, `remove:` and `prompt:` (any other
|
|
1345
|
+
key, a typo or a `tools:` list, is ignored with a warning); it can't reuse a built-in's name. A bundle declares its own with `chi.toolkit` ([plugins](plugins.md#chitoolkitname-base-add--remove--prompt-nil)).
|
|
1346
|
+
- **A kit's prompt text.** `prompt:` (text, several lines allowed) goes into the system prompt of the sessions on
|
|
1347
|
+
that kit, verbatim, with no header: after AGENTS.md and the appended files, before the memory indexes. A kit
|
|
1348
|
+
without one inherits its base's (`review: {base: terse, add: [web_fetch]}` stays concise); `prompt: ""` clears
|
|
1349
|
+
it; a session's own `--tool` / `/toolkit add` never touch it. Sessions on the same kit share it in the prompt
|
|
1350
|
+
cache; `full` and every kit without a prompt send the bytes they sent before. Keep it to a line or two that
|
|
1351
|
+
fits the kit's work (the coordinator bundle's `coding`: be concise): one that isn't text or is over 2000
|
|
1352
|
+
characters is left out with a warning, and long text belongs in `append_system_prompt:`. `/toolkit` shows it
|
|
1353
|
+
(`prompt: …`), `/stats` its kit and size (`kit prompt:`), the web's tools chip in its tooltip.
|
|
1345
1354
|
- **Saved at creation, never re-resolved from config.** A session stores its toolkit as named
|
|
1346
1355
|
(`"toolkit": {"name": "lean", "add": [], "remove": []}`) when it is created: `toolkit.default`, `toolkit.child`
|
|
1347
|
-
for a delegate child, or `chi --toolkit NAME` / `--tool` / `--no-tool` ([cli](cli.md)). Changing `toolkit.default`
|
|
1356
|
+
for a delegate child (or the kit its `delegate` call names), or `chi --toolkit NAME` / `--tool` / `--no-tool` ([cli](cli.md)). Changing `toolkit.default`
|
|
1348
1357
|
doesn't move existing sessions, not even when their worker is woken again; a session from before toolkits is on
|
|
1349
|
-
`full`. A continue and a fork keep the toolkit. `/toolkit` shows and changes it.
|
|
1358
|
+
`full`. A continue and a fork keep the toolkit. `/toolkit` shows and changes it. The prompt text is part of the
|
|
1359
|
+
kit, not of the session file: it follows the name.
|
|
1350
1360
|
- **Left out: reachable or removed.** A built-in missing from a kit's base list (`lean` has no `delegate`; a
|
|
1351
1361
|
`kits:` entry on `base: lean` or `child` inherits that) is left out softly: it is **reachable**. `find_tools` searches it as group `chi` (`chi/delegate`, with its inputSchema) beside
|
|
1352
1362
|
the MCP servers' tools, and `call_tool(tool: "chi/delegate", args: {…})` runs it as `delegate` itself, through the
|
|
@@ -1355,7 +1365,7 @@ toolkit:
|
|
|
1355
1365
|
call_tool can't reach it (`child` removes `memory_write`, `delegate` and `delegate_result`, so a child on it
|
|
1356
1366
|
starts no children). To keep a built-in away from the model, name it under `remove:`. `find_tools` and `call_tool`
|
|
1357
1367
|
are declared when a toolkit has a reachable built-in (or an MCP server is configured); `full` with no MCP server
|
|
1358
|
-
declares neither.
|
|
1368
|
+
declares neither, and removing them there (`--no-tool call_tool`) leaves nothing out: no prompt line, no chip.
|
|
1359
1369
|
- **The prompt line.** One line after the base prompt names them: `Not declared in this session (toolkit lean): ….
|
|
1360
1370
|
Search them with find_tools; call one with call_tool.`, then `Removed (toolkit child): memory_write, …. Only the
|
|
1361
1371
|
user can load one (/toolkit add <name>).` With `find_tools` removed, the first sentence ends `Call one with
|
|
@@ -1368,13 +1378,13 @@ toolkit:
|
|
|
1368
1378
|
loaded in this session (toolkit child) and can't be loaded from here; only the user can (/toolkit add
|
|
1369
1379
|
memory_write).` `/toolkit` lists both kinds, and the web's toolkit chip says them in its tooltip.
|
|
1370
1380
|
- **Applied at a turn's start.** A change (`/toolkit`, a plugin's `ctx.use_toolkit`) is saved at once and the next
|
|
1371
|
-
turn declares it; once the session has a model reply, `/toolkit` asks first
|
|
1372
|
-
cache").
|
|
1381
|
+
turn declares it, with its kit's prompt text; once the session has a model reply, `/toolkit` asks first
|
|
1382
|
+
("Changes that restart the prompt cache"), also for a kit with the same tools and another prompt text.
|
|
1373
1383
|
- **A name that doesn't resolve** (a typo, a bundle that was uninstalled) declares every tool for that process,
|
|
1374
1384
|
with one `toolkit>` warning at the first turn; the saved name stays, so the bundle's return brings it back.
|
|
1375
|
-
- **Versions.** A toolkit's definition can change with chi or a bundle, which
|
|
1376
|
-
|
|
1377
|
-
an edit to `toolkit.kits`: a session's worker reads the kits once when it starts, so a running session keeps its
|
|
1385
|
+
- **Versions.** A toolkit's definition (its tools and its prompt text) can change with chi or a bundle, which
|
|
1386
|
+
changes what saved sessions on it send after an upgrade: the next request reads the prompt again once, as a
|
|
1387
|
+
tool's schema change does. So can an edit to `toolkit.kits`: a session's worker reads the kits once when it starts, so a running session keeps its
|
|
1378
1388
|
tools and the edit reaches it at its next worker start (after an idle exit, `chi sessions restart`).
|
|
1379
1389
|
|
|
1380
1390
|
## LLM context: the forget layer
|
|
@@ -1586,7 +1596,7 @@ column says so, a `--kebab-name` flag. The maps (`hosts:`, `models:`,
|
|
|
1586
1596
|
| `context.wake` | `true` | yes | A source whose update says `wake: true` may start a turn in a live, idle session (one per source per 10 minutes, a peer source up to `context.peer_turns` in a row, within `session.max_wakes`); so may a session's pushed source's first push. `false`: updates wait as notes for the next turn. See [Waking](context.md#waking). |
|
|
1587
1597
|
| `context.peer_turns` | `3` | yes | Wake turns in a row a peer agent's answers may start (a peer bundle's outbox source, such as `codex-outbox`), with no message typed in the web or a TUI in between (`chi send` doesn't count); within `session.max_wakes`. Then answers wait as notes, and the UIs hear it once. An answer whose summary ends its verdicts with `VERDICT OK` wakes once to close the round, counted toward `session.max_wakes` only. `0`: a peer source wakes like any other. See [Waking](context.md#waking). |
|
|
1588
1598
|
| `toolkit.default` | `full` | | The toolkit a new session is stored on: the tools its prompts declare (`full`, `lean`, `child`, one of `toolkit.kits` or a bundle's). `chi --toolkit` picks one per session. See "Toolkits". |
|
|
1589
|
-
| `toolkit.child` | `full` | | A delegate child's toolkit. See "Toolkits". |
|
|
1599
|
+
| `toolkit.child` | `full` | | A delegate child's toolkit, unless its `delegate` call names one (`toolkit:`). See "Toolkits". |
|
|
1590
1600
|
| `thinking.turn_preamble` | `true` | yes | Ask a `qwen36` model to open its thinking with a short `TURN:` line (the step label). |
|
|
1591
1601
|
| `reasoning_history` | `turn` | | Which of its reasoning a chat host's model gets back: `drop`, `turn`, `all`; environment only (`SAMAGOTCHI_REASONING_HISTORY`), below a session's own level (`/reasoning-history`), above the `models:`/`hosts:` entries. See "Reasoning history". |
|
|
1592
1602
|
| `thinking.level` | `default` | `--thinking` | `off`, `low`, `medium`, `high` or `default` for every model; the flag and env outrank the `models:`/`hosts:` entries, the file's value doesn't; a session's own level outranks them all, and `--thinking` sets it on a session run (on `chi web` it sets this). See "Thinking". |
|
data/docs/hooks.md
CHANGED
|
@@ -526,7 +526,7 @@ stripped of surrounding whitespace, except file text, an edit's
|
|
|
526
526
|
| `list_sessions` | — | — | `cwd` |
|
|
527
527
|
| `send_note` | `text` | — | `session` |
|
|
528
528
|
| `context_read` | `name` | — | `offset`, `limit` |
|
|
529
|
-
| `delegate` | `task` | — | `model`, `session`, `cwd`, `wait`, `timeout` |
|
|
529
|
+
| `delegate` | `task` | — | `model`, `session`, `cwd`, `toolkit`, `wait`, `timeout` |
|
|
530
530
|
| `delegate_result` | — | — | `session`, `timeout` |
|
|
531
531
|
| `ask_user_question` | `question` | — | `question`, `options`, `header`, `multi_select`, `allow_freeform` |
|
|
532
532
|
| `forget_outputs` | `note` | — | `ids`, `note`, `keep`, `restore` |
|
data/docs/internals/anthropic.md
CHANGED
|
@@ -82,7 +82,7 @@ index: `message_start` (served model, usage), `content_block_start` (text, think
|
|
|
82
82
|
`content_block_delta` (`text_delta`, `thinking_delta`, `signature_delta`, `input_json_delta`), `message_delta`
|
|
83
83
|
(stop reason, `stop_details`, usage). `AnthropicMessages#chat_streamed` passes every event but `ping` to `on_delta`,
|
|
84
84
|
`message_start` and `message_delta` with the usage so far attached (`#with_usage`); a block's start or delta counts as shown for the first-token limit
|
|
85
|
-
(`.shows?`). A 200 whose body is a JSON error instead of a stream raises that error (
|
|
85
|
+
(`.shows?`). A 200 whose body is a JSON error instead of a stream raises that error (`LLM::AdapterCommon#raise_plain_error`, shared with the OpenAI adapter).
|
|
86
86
|
|
|
87
87
|
`#response` is a `ChatResponse`:
|
|
88
88
|
|
|
@@ -11,7 +11,7 @@ Samagotchi supports long-running commands in the background through five task to
|
|
|
11
11
|
Recommended workflow:
|
|
12
12
|
|
|
13
13
|
1. Create a task with `task_create`.
|
|
14
|
-
2. Use `task_wait` once.
|
|
14
|
+
2. Use `task_wait` once. Every wait returns the log's last `tail_lines` lines (10 by default): a finished task's (its summary, its error), a timed-out or pattern-matched one's progress. So there is no separate read just to see them.
|
|
15
15
|
3. For commands with a reliable completion marker, pass `done_pattern` to return when the recent log tail matches it.
|
|
16
16
|
4. Use `task_get` or `task_list` for nonblocking status checks, and `task_stop` if needed.
|
|
17
17
|
|
|
@@ -26,7 +26,7 @@ Behavior:
|
|
|
26
26
|
- The exit code: the command runs after an EXIT trap that writes the shell's status to the `exit_code` file (`TaskRuntime.wrapped_shell_command`, shared with `task_create`), so `exit N`, a `set -e` failure and a trailing `\` or `|` in the command all record what the shell exited with. A command that sets its own EXIT trap replaces it: `execute` still reports the shell's status, and a handed-over one gets its code from chi's waiter while that chi runs; a `task_create` task ends failed with no exit code.
|
|
27
27
|
- A stop of an `execute` (the user's Stop, the limit in kill mode) is done once the shell is reaped and nothing holds the logs: a child that ignores TERM after its shell died gets the KILL.
|
|
28
28
|
- A command still running at `execute.timeout_sec` is handed over as a task (`execute.on_timeout: task`, the default; `kill` stops it instead, and the `!cmd` bang always kills): the result starts `Still running at the 120s limit: moved to a background task, not killed.`, then `task_id: …` and the tails of both logs so far. A timeout during the 1.5 s background grace is a kill (the shell is gone, nothing to hand over). If the record can't be written, the command is killed. `TaskRuntime.adopt` writes a record for the process execute already started, with `handed_over_by: "execute"`. Its logs stay where execute wrote them, so the record's paths are absolute: `output_path` (stdout), `stderr_path` (stderr, a log of its own) and `exit_code_path`. `started_at` (and `created_at`) is the spawn time, not the hand-over's; `pid_started` is read at the hand-over, while execute's detach waiter is still running. From there it is an ordinary task: `task_wait`, `task_get`, `task_list` and `task_stop` treat it as any other. Its dir gets a `task` back-pointer file holding the record's absolute path. Once per process, the first `execute` sweeps `…/execute/`: a dir whose logs no process holds is removed when it has no back-pointer and is a day old (chi died mid-command), when its record is gone, or when it is 14 days old. The records live in each project's `tmp/tasks`, which the state dir can't list: hence the back-pointer.
|
|
29
|
-
- `task_wait` and `task_get` show `stderr_path` when the record has one;
|
|
29
|
+
- `task_wait` and `task_get` show `stderr_path` when the record has one; `task_wait`'s output tail is followed by a `stderr_tail:` of at most 10 lines when that log isn't empty. A `task_create` task has one log (stdout and stderr together) and no `stderr_path`. A `task_wait` result longer than `max_tool_output_chars` keeps its header and the tail's end, with a gap line naming `output_path`, where the whole log already is (and `stderr_path`, when the record has one) (`ToolOutputCut`'s `:head_tail_ref`; nothing is copied; see [Tool output guardrails](tool-guardrails.md#the-runners-cut-max_tool_output_chars)).
|
|
30
30
|
- Which tasks are a session's own (a cancelled turn's note, the turn-end note, a worker's idle exit, the web's stop-task button): the ids its `task_create` results and its handed-over executes name (`TaskRuntime.created_ids_in`, `created_id`). An execute's id is read only after its first line (`Execute::HANDED_OVER`, through `TaskRuntime.handed_over_id`; the web has a JS twin in `task_stop.js`), not from a `task_id:` line inside a run, which the command can print. (A command that prints the `---` separator chi joins a turn's results with, then a hand-over line, still fakes one: a known gap.) Either result may start with the `ran as: …` line of a gate-corrected call.
|
|
31
31
|
- `task_get` returns metadata and `output_path`; use `read` for output contents.
|
|
32
32
|
- `task_wait` accepts `timeout`, `tail_lines` (maximum 100), and `done_pattern` (a regular expression string).
|
data/docs/internals/engine.md
CHANGED
|
@@ -122,7 +122,7 @@ A worker's TERM, HUP or INT (WorkerSignals, trapped by a spawned worker only):
|
|
|
122
122
|
→ run_session_loop: exit 0, no discard; input queued behind the stopped turn wakes a new worker
|
|
123
123
|
|
|
124
124
|
The effective model doesn't resolve (a broken host config, HostRegistry#resolve raising):
|
|
125
|
-
→ the rescued readers give their fallback (
|
|
125
|
+
→ the rescued readers give their fallback (SessionModelSettings#model_setting) and log effective_model_unresolved;
|
|
126
126
|
a setting that fails on a resolved model gives its fallback and logs <setting>_unresolved
|
|
127
127
|
(sampling, thinking, reasoning_history, steer_cut_after, llm_context, window, price, served,
|
|
128
128
|
vision_adapter); served_probe_failed when asking the server for its served model fails;
|
|
@@ -226,7 +226,7 @@ The differences from the native loop:
|
|
|
226
226
|
merges (a person's line, a plugin's steer, a Continue's text) don't move it, as natively (nothing re-sanitizes
|
|
227
227
|
within a run): the request after a steer extends the one before. A step-limit Continue's Run starts where the run
|
|
228
228
|
it resumes did: `#complete`'s `reasoning_since:` (the Engine's `resume_from`, checked against the messages' length
|
|
229
|
-
in
|
|
229
|
+
in `Engine#resumed_run_start`), past a user entry added after that run's last reply (a `!cmd`'s output). Without
|
|
230
230
|
`since:` (`#reasoning_chars` from outside a Run) the boundary is the last query (a `role: "user"` or `turn_start`
|
|
231
231
|
entry). `Run#prompt_chars` counts it (`#reasoning_chars`).
|
|
232
232
|
- On an adapter that sends its blocks back (`#replays_content?`: `AnthropicMessages`), a model turn's saved blocks
|
|
@@ -312,10 +312,17 @@ One iteration with tool calls:
|
|
|
312
312
|
[Tool output guardrails](tool-guardrails.md#the-runners-cut-max_tool_output_chars). The model (both loops), the
|
|
313
313
|
event and the after_tool_call hook get that text.
|
|
314
314
|
- Emits `:tool_call_completed` {iteration, call_count, call_index, tool, output, output_truncated, output_file,
|
|
315
|
-
activity, images, diff, waited_ms, view, ref}, then fires `:after_tool_call` {iteration, tool, output,
|
|
315
|
+
activity, images, diff, waited_ms, view, ref, refs}, then fires `:after_tool_call` {iteration, tool, output,
|
|
316
|
+
status, call, elapsed_ms, result}.
|
|
316
317
|
`output_file` (the saved whole output) is also on the run hash; the session doesn't keep it (the cut text names it).
|
|
317
|
-
- The activity's status (`ToolActivity#tool_activity_status
|
|
318
|
-
|
|
318
|
+
- The activity's status (`ToolActivity#tool_activity_status`; a call the gate denied is `blocked`, set by
|
|
319
|
+
`ToolRunner#denied`): `stopped` for a call the turn's Stop (or a signal to chi, or the session's stop) left
|
|
320
|
+
unrun (`Tools::Execute::NOT_RUN_ON_STOP`, `NOT_RUN`) or an execute it killed (`STOPPED_BY_USER`, `STOPPED_BY`),
|
|
321
|
+
and for a `task_wait` whose header (before `output_tail:`) says `wait_result: canceled` or `status: stopped`;
|
|
322
|
+
`ok` for an execute handed over as a task (`#handed_over?`: its output tail may hold any `exit: N`); `error` for
|
|
323
|
+
any other `Error:` result, for a `task_wait` whose header says `status: failed`, and for an execute that exited
|
|
324
|
+
non-zero (a numberless `exit:` line, killed by a signal, counts), except a grep-family search that found nothing
|
|
325
|
+
(`ToolActivity.no_match?`:
|
|
319
326
|
exit 1, no stderr block, the last step is grep/egrep/fgrep/rg/ag/pgrep, no `&&` after a step that can fail
|
|
320
327
|
silently or sends output to /dev/null, no background `&`, no earlier exit/return or `set -e`; when unsure,
|
|
321
328
|
not a no-match). That one stays `ok` with `no_match: true` on the activity, which SessionMetrics keeps on the tool
|
|
@@ -358,7 +365,7 @@ read live, a model listing can move a bare id to another host, and another proce
|
|
|
358
365
|
what a resolve gives, all without a `/model`. Frozen, so any thread may hold one.
|
|
359
366
|
|
|
360
367
|
- The Engine's readers take one (`Engine#effective_model`); those whose fallback always covered the resolve go
|
|
361
|
-
through
|
|
368
|
+
through `SessionModelSettings#model_setting` (`session_model_settings.rb`: the Engine forwards its readers of the session's settings there). A turn takes one in `turn_settings` (before the hooks) and one in `generate` (after
|
|
362
369
|
them); `system_prompt`, `steer_cut_after` (at `:turn_started`) and the turn-end warm-up take their own;
|
|
363
370
|
`stats_snapshot` and `session_state_snapshot` take one each (the latter nil-tolerant).
|
|
364
371
|
- Never resolved (they hold on a broken resolve): `effective_model_ref`, `bare_model_name`,
|
|
@@ -490,17 +497,22 @@ hook registry (`@hooks.fire`), not on the sink or the observers. The other hook
|
|
|
490
497
|
```
|
|
491
498
|
Engine initialization (in this order, among other things):
|
|
492
499
|
@turn_state, @steer_cut (SteerCut: its GenerationPhase and WaitingSteer)
|
|
493
|
-
@host_registry, @model_choice (ModelChoice: the name and the name as typed); @client = effective_model.client
|
|
500
|
+
@host_registry, @model_choice (ModelChoice: the name and the name as typed); @model_settings (SessionModelSettings: the choice and the session read at use); @client = effective_model.client
|
|
494
501
|
@given_profile = profile or nil (resolved on first need, so building an Engine makes no network call)
|
|
495
|
-
|
|
496
|
-
@
|
|
497
|
-
@
|
|
502
|
+
MemoryBundle::SystemBundle.ensure! (the shipped system bundle installed; a failure is logged, not raised)
|
|
503
|
+
@event_routes (EventRoutes: where a card or a notice goes: held while the plugins load, an anytime command's, an init task's, a turn event, else announced or held)
|
|
504
|
+
@hook_routes (HookRoutes: notices (through @event_routes), hook questions, stop_turn/stop_generation, steer attribution)
|
|
505
|
+
@guardrail_wiring, @question_desk, @relay_desk (RelayDesk: a delegate's approval relay)
|
|
498
506
|
@extension_load = ExtensionLoad.new; @hooks = @extension_load.hooks (config.yml's, then the bundles')
|
|
499
|
-
@tools = Tools::Builtins.registry;
|
|
507
|
+
@tools = Tools::Builtins.registry; @command_registry (SessionCommands' built-ins); @plugin_tasks
|
|
508
|
+
@toolkit_binding (ToolkitBinding: the kits, the plugins' among them, and the turn-start apply)
|
|
509
|
+
@thinking_notices (ThinkingNotices); @tool_index = Tools::ToolIndex.new; @peer_sources = PeerSources.new
|
|
510
|
+
the bundles' plugins load (load_plugins → ExtensionLoad#load_plugins),
|
|
500
511
|
then (plugins or not) @tool_index.declare(@tools): find_tools + call_tool (source "index", not core),
|
|
501
512
|
declared per toolkit by Registry#declared? (a source registered at load, or a reachable built-in) and
|
|
502
513
|
sets call_tool's unwrap (Tools::ToolIndex: the chi group from Registry#reachable_names, the sources'
|
|
503
514
|
groups, search, call checks, the unwrap; a source runs the call with its own plugin Context)
|
|
515
|
+
@reminder_store = ReminderStore.new (the kernel gets it), @reminder_queue, @reminders
|
|
504
516
|
wire_kernel: @kernel = KernelLoop.new(client:, profile:, hooks:, reminder_store:, tools:)
|
|
505
517
|
@kernel.guardrail_gate = @guardrail_wiring.gate; @kernel.warmup = PromptWarmup.new
|
|
506
518
|
@hooks.runtime = @hook_routes.runtime (HookRoutes, built first: what a hook or plugin does reaches the UIs)
|
|
@@ -555,7 +567,9 @@ them across turns. `Web::App#messages_for_display` sends `display_refs` re-valid
|
|
|
555
567
|
- Order of a fire: bundle hooks (by priority, bundle, hook name), then config hooks, then turn-scoped hooks.
|
|
556
568
|
- A hook that raises is logged; it never breaks the turn.
|
|
557
569
|
- A notice from a hook goes to the running turn's sink and the observers. Outside a turn it is announced with
|
|
558
|
-
`between_turns: true`; while the plugins load it is held and announced after.
|
|
570
|
+
`between_turns: true`; while the plugins load it is held and announced after. `EventRoutes#route` decides it, the
|
|
571
|
+
same routes as a card's (`Engine#show_card`), with their own marks (`NOTICE_MARKS`, `CARD_MARKS`); a guardrails
|
|
572
|
+
line after load takes only the turn / between-turns routes (`#route_by_turn`).
|
|
559
573
|
- Plugin init tasks (`chi.init`, slow setup such as an MCP server's first start): a turn waits for the ones that
|
|
560
574
|
provide tools before it builds its messages, and a Stop or Ctrl-C ends the wait.
|
|
561
575
|
|
|
@@ -652,7 +666,8 @@ prompt starts with what the server has cached).
|
|
|
652
666
|
`[chat, thinking, layers]` (chat/native, the thinking level, the turn's LLM context layers), and is reset
|
|
653
667
|
only on a model switch, a tools change, a profile change or a toolkit change (`Engine#apply_toolkit!`). The
|
|
654
668
|
stable part (base prompt, the toolkit's not-loaded line, rg guidance, identity, model notes, preloaded memories,
|
|
655
|
-
AGENTS.md, appended files, memory indexes) comes before the volatile tail (model,
|
|
669
|
+
AGENTS.md, appended files, the toolkit's kit prompt, memory indexes) comes before the volatile tail (model,
|
|
670
|
+
working directory, session).
|
|
656
671
|
prompt-caching.md covers this in detail.
|
|
657
672
|
|
|
658
673
|
## Key files
|
|
@@ -667,6 +682,7 @@ Paths are under `lib/samagotchi/`.
|
|
|
667
682
|
| `generation_phase.rb`, `waiting_steer.rb` | Whether a steer may cut the running generation, and the steer that waits to |
|
|
668
683
|
| `effective_model.rb` | `EffectiveModel` (the effective model's settings, a snapshot per read; `.of_session`), `ModelChoice`, the fallbacks' log lines (`Unresolved`) |
|
|
669
684
|
| `session_setting.rb` | `SessionSetting`: the per-session settings' descriptors (own value, chips, the web's fallback) |
|
|
685
|
+
| `session_model_settings.rb` | `SessionModelSettings`: the session's settings on its effective model (its own thinking, reasoning_history and llm_context over the model's, the `/model` and `/stats` summaries, what a turn resolves, `#model_setting`'s fallbacks); the Engine forwards its readers there |
|
|
670
686
|
| `level_setting_command.rb`, `thinking_command.rb`, `reasoning_history_command.rb` | `/thinking` and `/reasoning-history` (`LevelSettingCommand` and its two Specs) |
|
|
671
687
|
| `thinking_notices.rb` | `ThinkingNotices`: the notices a turn's thinking level leads to |
|
|
672
688
|
| `steer_cut_after.rb`, `cut_policy.rb` | The model's cut wait (`SteerCutAfter.resolve`); the loops' cut path (`CutPolicy`) |
|
|
@@ -676,6 +692,7 @@ Paths are under `lib/samagotchi/`.
|
|
|
676
692
|
| `llm/adapters.rb` | `LLM::Adapters::BY_API`: which chat adapter a host's api gets |
|
|
677
693
|
| `llm/openai_chat.rb` | `LLM::OpenAIChat`, the `/v1/chat/completions` adapter |
|
|
678
694
|
| `llm/adapter_common.rb` | `LLM::AdapterCommon`: what both chat adapters share (the HTTP layer and its timeouts, the paged model list, the SSE line loop, JSON errors) |
|
|
695
|
+
| `llm/refusal_memo.rb` | `LLM::RefusalMemo`: what a host refused (for one model, or the whole host), remembered for its holder's life (an adapter, or the worker's ChatLoop) |
|
|
679
696
|
| `llm/anthropic_messages.rb`, `llm/anthropic_wire.rb`, `llm/anthropic_assembly.rb`, `llm/dialect.rb` | The `/v1/messages` adapter, its wire translation, its response, its dialects ([anthropic.md](anthropic.md)) |
|
|
680
697
|
| `llm/prompt_cache.rb` | Cache breakpoints on the OpenAI path, and the `cache_control` both adapters send |
|
|
681
698
|
| `llm/turn_settings.rb` | `LLM::TurnSettings`, what a turn runs under (vision, sampling, thinking, reasoning history, …) |
|
|
@@ -685,19 +702,27 @@ Paths are under `lib/samagotchi/`.
|
|
|
685
702
|
| `llm/native_backend.rb` | Wraps KernelLoop as a backend (`#complete` calls `#run`) |
|
|
686
703
|
| `llm/model_result.rb` | `LLM::ModelResult`, what a backend returns |
|
|
687
704
|
| `tool_runner.rb` | Per-call path (gate, start/complete events, output cap, images, diffs) |
|
|
705
|
+
| `tool_output_cut.rb`, `tool_output_files.rb` | `ToolOutputCut`: how a tool's output longer than `max_tool_output_chars` is cut, by the tool's policy (`POLICIES`; `:head` for a tool with none); `ToolOutputFiles`: the whole output of an execute cut that way, saved in the session's `tool_output/` folder ([tool-guardrails.md](tool-guardrails.md)) |
|
|
706
|
+
| `tool_row_fields.rb`, `row_refs.rb` | `ToolRowFields`: a tool row's fields beyond its params (`ACTIVITY_KEYS`, `EVENT_KEYS`), the same live and on a reload; `RowRefs`: a plugin tool's row refs (`refs:`), checked, capped and saved with the result |
|
|
688
707
|
| `tool_response.rb` | Per-batch dispatch and tool_response entries (joined for native, single for chat) |
|
|
689
708
|
| `empty_answer_retry.rb` | The empty-answer and cut retry budget |
|
|
690
709
|
| `prompt_warmup.rb` | The turn-end warm-up |
|
|
691
710
|
| `tools/registry.rb` | The tools a session offers: schemas, handlers, order |
|
|
711
|
+
| `tools/tool_index.rb` | `Tools::ToolIndex`: `find_tools` and `call_tool`, the tools a session knows but doesn't declare one by one (the sources' groups and the built-ins its toolkit leaves out), `#declare`, `#refresh!`, `#unwrap` |
|
|
712
|
+
| `plugin/tool_spec.rb` | `Plugin::ToolSpec`: a checked tool declaration (`chi.tool`, a tool set, `ToolSpec.build`), what `Registry#register` gets; `#per_call` |
|
|
692
713
|
| `system_prompt.rb` | System prompt construction (stable part, volatile tail) |
|
|
693
714
|
| `prompt_files.rb`, `model_notes.rb` | The AGENTS.md chain and appended files; the model notes the prompt loads |
|
|
694
715
|
| `toolkit.rb`, `toolkit_command.rb` | A session's toolkit (`Toolkit#resolve`, what `Registry` declares); `/toolkit` |
|
|
695
716
|
| `toolkit_binding.rb` | `ToolkitBinding`: the Engine's toolkit seam (the kits, `#explained`, `ctx.use_toolkit`, the turn-start `#apply!` behind `Engine#apply_toolkit!`) |
|
|
696
717
|
| `hooks/registry.rb` | Hook registry, fire order, `Hooks::Runtime` |
|
|
697
718
|
| `hook_routes.rb` | `HookRoutes`: the Engine's routes for a hook's or plugin's notice (`:hook_notice`, `fallback_for:`), question, stop and steer, and the guardrails' after-load line |
|
|
719
|
+
| `event_routes.rb` | `EventRoutes`: where a card (`Engine#show_card`), a notice (`HookRoutes#notify`) and a guardrails line (`#guardrail_notify`, turn or between turns only) go: held while the plugins load, an anytime command's, an init task's, a running turn's event, else announced or held for `holding_announcements` |
|
|
720
|
+
| `engine_peers.rb`, `peer_sources.rb` | `Engine::PeerView` (what the kernel's peer tools see of the Engine) and `Engine::RelayPeer` (a delegate's approval relay); `PeerSources`: the attached context sources a peer bundle declares as its peer's answers (`chi.peer_source`) |
|
|
698
721
|
| `extension_load.rb` | What an Engine loads at start: config.yml and bundle hooks, plugins, `bundles:` settings; events held while plugins load |
|
|
699
722
|
| `guardrail_wiring.rb`, `guardrails/gate.rb` | The gate's context and approvals; the verdict per call |
|
|
700
723
|
| `events.rb` | Event type sets shared by the Worker, the Bridge, the TUI and the web |
|
|
701
724
|
| `cancellation_controller.rb` | A turn's cancel signal, and a generation's child controller |
|
|
702
725
|
| `session.rb` | Session model (status, messages, persistence) |
|
|
726
|
+
| `turn_checkpoint.rb` | `TurnCheckpoint`: a worker's running turn saved at the loop's iteration boundaries (`Session#turn_checkpoint`), so a killed worker loses at most `INTERVAL` of it |
|
|
727
|
+
| `context_status.rb` | `ContextStatus`: one turn's context tracking (the status line's value, the `:context_status` event, the model's guidance line) ([context-telemetry.md](context-telemetry.md)) |
|
|
703
728
|
| `session_manager.rb` | Background session processes (workers) and their IPC |
|
|
@@ -51,7 +51,7 @@ Each task × arm × sample is a run in `ROOT/runs/<task>-<arm>-s<n>/`:
|
|
|
51
51
|
in `config/` (the model's host copied from `--hosts-config`, default the user's config.yml; `turn.max_iterations:
|
|
52
52
|
150`; `recap: false`; `llm_context.apply: payoff`, no `stale_edits`). State goes in `state/`, and it runs `chi
|
|
53
53
|
bundle install loop-guard`. Every chi and rspec command gets `SAMAGOTCHI_ENV=test`, the run's `XDG_STATE_HOME`
|
|
54
|
-
and `XDG_CONFIG_HOME
|
|
54
|
+
and `XDG_CONFIG_HOME` (the smoke-run isolation).
|
|
55
55
|
2. **run (Driver):** `chi send --new --wait --format json --dir repo --model M --llm-context <arm>
|
|
56
56
|
--llm-context-budget <N|off>` with the first turn, then each later turn into the same session. The arms are
|
|
57
57
|
`none`, `stale` and `stale_forget` (`stale,forget`). The tasks use two turns, because forget is offered at turn
|
|
@@ -39,6 +39,7 @@ right-hand column happens.
|
|
|
39
39
|
│ explicit (preloaded) memories │
|
|
40
40
|
│ AGENTS.md (root → cwd) │ (picked up by a new
|
|
41
41
|
│ appended files (append_system_prompt:, --append-system-prompt) │ process or a rebuild)
|
|
42
|
+
│ kit prompt (per toolkit: its kit's prompt: text, only when it has one) │
|
|
42
43
|
│ project + system memory indexes │
|
|
43
44
|
│ ◄── remote Claude / Messages: cache_control breakpoint #1 │
|
|
44
45
|
├──────────────────────────────────────────────────────────────────────────┤
|
|
@@ -71,6 +72,11 @@ right-hand column happens.
|
|
|
71
72
|
beside `apply_staged_tools!`, then `reset!`): the chat loop builds `tools:` per request, so a mid-turn change
|
|
72
73
|
would differ from the turn's prompt. Under `full` nothing is filtered and no line is added: the bytes are what
|
|
73
74
|
they were before toolkits.
|
|
75
|
+
- A kit's prompt text (`toolkit.kits.<name>.prompt:`, `chi.toolkit … prompt:`) sits after the appended files and
|
|
76
|
+
before the memory indexes (`SystemPrompt#kit_prompt_section`): one prefix per kit, never per-session text, so
|
|
77
|
+
sessions on the kit share it; a memory write (the indexes after it) doesn't move it. It is part of the
|
|
78
|
+
`Toolkit::Resolved` the Registry holds, so a switch that changes only the text is a toolkit change
|
|
79
|
+
(`apply_toolkit!` → `reset!`). `full` and kits without one send the bytes they sent before.
|
|
74
80
|
- find_tools' description is a function of the toolkit and the source groups **at load**: `ToolIndex#declare`
|
|
75
81
|
snapshots the MCP groups' lines (name, summary, callable count) and `ToolIndex#refresh!` (from
|
|
76
82
|
`ToolkitBinding#apply!`) rebuilds only the `chi` line, the built-ins the toolkit reaches. An MCP server that
|