samagotchi 0.100.1 → 0.102.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 +50 -1
- data/bin/chi +14 -10
- data/docs/architecture.md +10 -2
- data/docs/cli.md +100 -5
- data/docs/configuration.md +26 -4
- data/docs/internals/bundles.md +1 -1
- data/docs/internals/engine.md +1 -0
- data/docs/internals/llm-context-forget.md +14 -0
- data/docs/internals/prompt-caching.md +8 -1
- data/docs/internals/working-set.md +205 -0
- data/docs/plugins.md +6 -3
- data/docs/sessions.md +28 -11
- data/docs/testing.md +8 -1
- data/lib/samagotchi/bridge/turn_accumulator.rb +16 -0
- data/lib/samagotchi/bridge.rb +9 -3
- data/lib/samagotchi/bundle_command/check.rb +5 -1
- data/lib/samagotchi/bundle_command/try/command.rb +6 -6
- data/lib/samagotchi/bundle_command/try/sandbox.rb +3 -3
- data/lib/samagotchi/bundle_command.rb +4 -4
- data/lib/samagotchi/bundles/system/manifest.yml +1 -1
- data/lib/samagotchi/commands/registry.rb +12 -1
- data/lib/samagotchi/config.rb +92 -53
- data/lib/samagotchi/engine.rb +153 -4
- data/lib/samagotchi/host_keys.rb +35 -18
- data/lib/samagotchi/idle_scheduler.rb +16 -1
- data/lib/samagotchi/llm_context_edit.rb +32 -10
- data/lib/samagotchi/llm_context_forget.rb +12 -3
- data/lib/samagotchi/llm_context_view.rb +19 -7
- data/lib/samagotchi/memory_bundle/installer.rb +2 -0
- data/lib/samagotchi/memory_bundle/manifest.rb +13 -2
- data/lib/samagotchi/message_parts.rb +8 -3
- data/lib/samagotchi/plugin/context.rb +2 -2
- data/lib/samagotchi/prompt.rb +1 -1
- data/lib/samagotchi/recap_command.rb +68 -0
- data/lib/samagotchi/recap_setup.rb +27 -14
- data/lib/samagotchi/send_command.rb +14 -11
- data/lib/samagotchi/session.rb +19 -12
- data/lib/samagotchi/session_commands.rb +44 -2
- data/lib/samagotchi/session_config.rb +411 -0
- data/lib/samagotchi/session_setup.rb +9 -9
- data/lib/samagotchi/sessions_command.rb +6 -2
- data/lib/samagotchi/terminal_ui/attach_launcher.rb +5 -5
- data/lib/samagotchi/terminal_ui/attached_loop.rb +2 -1
- data/lib/samagotchi/terminal_ui/formatting.rb +10 -3
- data/lib/samagotchi/terminal_ui.rb +8 -6
- data/lib/samagotchi/testing/bundle.rb +3 -2
- data/lib/samagotchi/testing/fake_executable.rb +6 -16
- data/lib/samagotchi/testing/fake_executable_launcher +6 -0
- data/lib/samagotchi/tool_response.rb +10 -6
- data/lib/samagotchi/tool_runner.rb +25 -6
- data/lib/samagotchi/version.rb +1 -1
- data/lib/samagotchi/web/app.rb +76 -11
- data/lib/samagotchi/web/public/app.js +35 -3
- data/lib/samagotchi/web/public/chip_popover.js +56 -17
- data/lib/samagotchi/web/public/commands.js +8 -2
- data/lib/samagotchi/web/public/data.js +7 -0
- data/lib/samagotchi/web/public/index.html +145 -1
- data/lib/samagotchi/web/public/info_bar.js +16 -4
- data/lib/samagotchi/web/public/info_bar_model.js +7 -3
- data/lib/samagotchi/web/public/refs.js +10 -1
- data/lib/samagotchi/web/public/stage_model.js +6 -5
- data/lib/samagotchi/web/public/stage_view.js +34 -2
- data/lib/samagotchi/web/public/stream_handlers.js +10 -1
- data/lib/samagotchi/web/public/turn_html.js +5 -0
- data/lib/samagotchi/web/public/turn_view.js +16 -4
- data/lib/samagotchi/web/public/working_set.js +612 -0
- data/lib/samagotchi/web/public/working_set_rail.js +278 -0
- data/lib/samagotchi/web/public/working_set_view.js +541 -0
- data/lib/samagotchi/web/server.rb +6 -4
- data/lib/samagotchi/worker.rb +9 -6
- data/lib/samagotchi/working_set.rb +238 -0
- data/lib/samagotchi/working_set_command.rb +119 -0
- data/lib/samagotchi/working_set_steer.rb +250 -0
- metadata +11 -2
- data/lib/samagotchi/bundle_session_settings.rb +0 -251
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: '084d47c40205bd43fa1126dd3169a0792cc6faee949899bf6b62d84a559d1501'
|
|
4
|
+
data.tar.gz: 23dde4e086c819fc43349cb20afed56121fb51bfb3b54b9be6e90fd8a332003b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 763b8db4ab722ec994871d8d5e4e1238beda7ae846c9cf8bf5f9dc0f2c8d545eb767b7d82afcf35a8cb096f2f30461a8a793068c5359d5c926a7209e626c91b9
|
|
7
|
+
data.tar.gz: abb0665762926a27e66133b5326cf8b18658e5404047d9f1ce414c6455ac3ddffa15667c00ab6a6ad929a9d15d451f667ad11b702d08bccb9fa9053161415a5b
|
data/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,53 @@ and commands may change between minor versions. How releases are made:
|
|
|
8
8
|
|
|
9
9
|
## [Unreleased]
|
|
10
10
|
|
|
11
|
+
## [0.102.0] - 2026-10-23
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
|
|
15
|
+
- `/working-set` lists the session's working set as the model has it: each file, memory and URL its turns read,
|
|
16
|
+
edited or fetched, with its state (`stale`, `forgotten`, `dropped`) and its size as sent. `/working-set drop KEY…`
|
|
17
|
+
takes an item out of what the model is sent (its reads go as a stub saying you dropped it, under any LLM context
|
|
18
|
+
strategy); `/working-set undrop KEY…` sends it whole again. A change applies from the next turn. In the web's
|
|
19
|
+
working set list (still experimental, `web.working_set: true`), rows offer `drop` / `undrop`; mid-turn they wait
|
|
20
|
+
for the turn's end, with an `undo`. See [docs/cli.md](docs/cli.md).
|
|
21
|
+
- `--set` takes chi's own session settings too: `--set recap.enabled=false` or `--set recap.sentences=3` for this
|
|
22
|
+
session, over config.yml. A bad value or a key no session sets is an error (exit 2). See
|
|
23
|
+
[docs/configuration.md](docs/configuration.md#per-session-settings).
|
|
24
|
+
- `/recap on|off|default` turns the idle recap on or off for this session, at once and in any UI (mid-turn too);
|
|
25
|
+
saved with the session.
|
|
26
|
+
|
|
27
|
+
### Changed
|
|
28
|
+
|
|
29
|
+
- `POST /api/sessions`: the field `bundle_settings` is now `settings` (it takes core keys too). No alias.
|
|
30
|
+
- An attached TUI started before this release treats `/recap off` as the plain `/recap`; restart it.
|
|
31
|
+
|
|
32
|
+
### Fixed
|
|
33
|
+
|
|
34
|
+
- The web's working set no longer keeps the last item when the set is emptied, and a reply to an older request can
|
|
35
|
+
no longer overwrite a newer one.
|
|
36
|
+
|
|
37
|
+
## [0.101.0] - 2026-10-22
|
|
38
|
+
|
|
39
|
+
### Added
|
|
40
|
+
|
|
41
|
+
- Web (experimental, off by default): the stage view's **working set**, which shows what defines the model's
|
|
42
|
+
context: the files it read or edited, the memories, the fetched URLs and the preloaded and muted memories. It
|
|
43
|
+
shows when each one came in, folded into a few lines beside the stage. It replaces the mem chip with
|
|
44
|
+
`● set N`, adds a footprint line under each finished turn, and opens a list whose step tags jump to the call.
|
|
45
|
+
Items say whether the model still has them: **stale** (faded) when the file changed after the model last saw it,
|
|
46
|
+
through `execute`, your editor or anything else (the model's own edits don't count); **forgotten** (struck)
|
|
47
|
+
when the LLM context strategy no longer sends any of it. Each row shows its size in tokens. Turn it on with
|
|
48
|
+
`web.working_set: true`, `chi web --web-working-set` or `?working_set=1`. See
|
|
49
|
+
[docs/cli.md](docs/cli.md#the-working-set).
|
|
50
|
+
|
|
51
|
+
### Fixed
|
|
52
|
+
|
|
53
|
+
- macOS: reading a host's API key from the Keychain can no longer hang chi past its 5 s deadline when starting
|
|
54
|
+
`security` stalls (a first run scanned by XProtect): chi warns and goes on without the key.
|
|
55
|
+
|
|
56
|
+
Update with `chi update`.
|
|
57
|
+
|
|
11
58
|
## [0.100.1] - 2026-10-22
|
|
12
59
|
|
|
13
60
|
### Fixed
|
|
@@ -3807,7 +3854,9 @@ and long-lived sessions.
|
|
|
3807
3854
|
- A macOS desktop helper (`chi desktop install`): a "Send to chi" Service and a
|
|
3808
3855
|
hotkey panel that send selected text or the clipboard to your sessions.
|
|
3809
3856
|
|
|
3810
|
-
[Unreleased]: https://github.com/dm1try/samagotchi/compare/v0.
|
|
3857
|
+
[Unreleased]: https://github.com/dm1try/samagotchi/compare/v0.102.0...HEAD
|
|
3858
|
+
[0.102.0]: https://github.com/dm1try/samagotchi/compare/v0.101.0...v0.102.0
|
|
3859
|
+
[0.101.0]: https://github.com/dm1try/samagotchi/compare/v0.100.1...v0.101.0
|
|
3811
3860
|
[0.100.1]: https://github.com/dm1try/samagotchi/compare/v0.100.0...v0.100.1
|
|
3812
3861
|
[0.100.0]: https://github.com/dm1try/samagotchi/compare/v0.99.0...v0.100.0
|
|
3813
3862
|
[0.99.0]: https://github.com/dm1try/samagotchi/compare/v0.98.0...v0.99.0
|
data/bin/chi
CHANGED
|
@@ -133,9 +133,11 @@ parser = OptionParser.new do |opts|
|
|
|
133
133
|
# --no-tool is taken out of ARGV before parse! (OptionParser would read it
|
|
134
134
|
# as --tool's negation); this is its help line.
|
|
135
135
|
opts.separator " --no-tool NAME Leave this tool out of the toolkit (repeatable; a comma list too)"
|
|
136
|
-
opts.on("--set
|
|
137
|
-
|
|
138
|
-
|
|
136
|
+
opts.on("--set KEY=VALUE", "A setting for this session, saved in it (repeatable): a core key a session may set " \
|
|
137
|
+
"(recap.enabled, recap.sentences; typed by the key, over CLI, env and config.yml), or BUNDLE.KEY over " \
|
|
138
|
+
"config.yml's bundles: (a key the bundle's manifest lists in session_settings:; numbers and booleans " \
|
|
139
|
+
"(true, off, no) are typed, the rest is text). A wrong key or value is refused: " \
|
|
140
|
+
"--set recap.enabled=false, --set cost-cap.cap=3") do |v|
|
|
139
141
|
(options[:sets] ||= []) << v
|
|
140
142
|
end
|
|
141
143
|
opts.on("--parent-answers LEVEL", "What a parent agent may answer on this session's questions: " \
|
|
@@ -333,6 +335,7 @@ if options[:web]
|
|
|
333
335
|
view = Samagotchi::Config.get("web.view")
|
|
334
336
|
exit Samagotchi::Web::Server.launch(port: port, scope: options[:scope] || "project", open_browser: options[:web_open],
|
|
335
337
|
markdown: markdown, view: view, new_token: options[:new_token],
|
|
338
|
+
working_set: Samagotchi::Config.get("web.working_set"),
|
|
336
339
|
annotate_presets: Samagotchi::Config.get("web.annotate_presets"),
|
|
337
340
|
editor: Samagotchi::Config.get("web.editor"))
|
|
338
341
|
end
|
|
@@ -434,13 +437,14 @@ if options[:toolkit] || options[:tools] || options[:no_tools]
|
|
|
434
437
|
remove: options[:no_tools])
|
|
435
438
|
end
|
|
436
439
|
|
|
437
|
-
# --set BUNDLE.KEY=VALUE: a new session's
|
|
438
|
-
# against
|
|
440
|
+
# --set KEY=VALUE / BUNDLE.KEY=VALUE: a new session's own settings, checked
|
|
441
|
+
# here (a core key against its Config entry, a bundle's against the installed
|
|
442
|
+
# bundles), so a typo isn't saved.
|
|
439
443
|
if options[:sets]
|
|
440
|
-
require "samagotchi/
|
|
444
|
+
require "samagotchi/session_config"
|
|
441
445
|
begin
|
|
442
|
-
options[:
|
|
443
|
-
rescue Samagotchi::
|
|
446
|
+
options[:settings] = Samagotchi::SessionConfig.from_flags(options[:sets])
|
|
447
|
+
rescue Samagotchi::SessionConfig::Error => e
|
|
444
448
|
warn "Error: #{e.message}"
|
|
445
449
|
exit 2
|
|
446
450
|
end
|
|
@@ -499,7 +503,7 @@ if launch == :attached
|
|
|
499
503
|
appended_prompt_files: options[:appended_prompt_files] || [],
|
|
500
504
|
toolkit: options[:toolkit_value],
|
|
501
505
|
toolkit_flags: options[:toolkit_flags] || [],
|
|
502
|
-
|
|
506
|
+
settings: options[:settings],
|
|
503
507
|
parent_answers: options[:parent_answers])
|
|
504
508
|
rescue Samagotchi::TerminalUI::AttachLauncher::Error => e
|
|
505
509
|
warn "Error: #{e.message}"
|
|
@@ -522,7 +526,7 @@ begin
|
|
|
522
526
|
appended_prompt_files: options[:appended_prompt_files] || [],
|
|
523
527
|
toolkit: options[:toolkit_value],
|
|
524
528
|
toolkit_flags: options[:toolkit_flags] || [],
|
|
525
|
-
|
|
529
|
+
settings: options[:settings],
|
|
526
530
|
parent_answers: options[:parent_answers],
|
|
527
531
|
non_interactive: options[:non_interactive],
|
|
528
532
|
model_name: options[:model],
|
data/docs/architecture.md
CHANGED
|
@@ -311,7 +311,8 @@ process that already owns the `Engine`); every worker starts it, and it exposes:
|
|
|
311
311
|
refused connection is `503 not_live`.
|
|
312
312
|
- `POST /session/:id/cancel` — cancel the running turn; `202`, or `409` when none runs.
|
|
313
313
|
- `POST /session/:id/recap` — `/recap` in an attached TUI: `200 {enabled, saved, request,
|
|
314
|
-
min_user_turns}` (`{enabled: false}` without recaps
|
|
314
|
+
min_user_turns}` (`{enabled: false, session_off}` without recaps; `session_off` when the session's own
|
|
315
|
+
`/recap off` turned it off); a new recap is asked for at once and
|
|
315
316
|
arrives as `:recap_ready`. Answers mid-turn too.
|
|
316
317
|
- `POST /session/:id/answer` — answer the pending question; `200`, `409` when another client
|
|
317
318
|
answered first or it is gone, `400` for an invalid selection. With `client_id: "cli:answer"`
|
|
@@ -445,6 +446,13 @@ The page's frequent reads of `GET /api/sessions/:id` stay light too:
|
|
|
445
446
|
`turn_count`, when the page's merge came up short.
|
|
446
447
|
- `?cards=1`: the cards, from `/tail`; the session file is only stat'ed for the 404.
|
|
447
448
|
|
|
449
|
+
The stage view's working set (`web.working_set`) has its own read, `GET /api/sessions/:id/working_set`: the
|
|
450
|
+
`WorkingSet` projection (`{items, at, running}`: each file, memory and URL live, stale or forgotten, with its tokens)
|
|
451
|
+
of the worker's `/snapshot` messages, else the session file, under the session's LLM context strategy; while a turn
|
|
452
|
+
runs, the snapshot's `working_set` (the running turn's last event, which the messages lag) when it has one. Its live form
|
|
453
|
+
is the `:working_set_updated` event, which always wins over a GET's answer it overtook. The page overlays it on the
|
|
454
|
+
set it builds from its tool rows ([internals/working-set.md](internals/working-set.md)).
|
|
455
|
+
|
|
448
456
|
A worker without `/tail` (an older chi; `404 not_found`) is read through `/snapshot` in the same
|
|
449
457
|
shape; any other failure (no worker, a 500, a timeout) reads the disk, trimmed to the newest
|
|
450
458
|
turn's records.
|
|
@@ -603,7 +611,7 @@ A map of the parts the overview above doesn't name (paths under `lib/samagotchi/
|
|
|
603
611
|
| 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. |
|
|
604
612
|
| 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. |
|
|
605
613
|
| 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)). |
|
|
606
|
-
|
|
|
614
|
+
| Session config (`--set`) | `session_config.rb` (`SessionConfig`, `SessionConfig::Settings`) | A session's own settings as one value (`Session#settings`, `SessionSetup#settings`): `core`, the `--set KEY=VALUE` values of the core keys marked `session: true` (`Config::Entry`), typed by `Config.coerce!` and read first through `Config.get(key, session:)` (`RecapSetup`; `Engine#session=` rebuilds the recap job, `IdleScheduler#replace_job`), file key `config_settings`; `bundles`, the `--set BUNDLE.KEY=VALUE` values, checked against the manifest's `session_settings:`, laid over `bundles: <name>:` in `ctx.settings` ([plugins.md](plugins.md)), file key `bundle_settings`. `SessionConfig.clash` refuses a bundle setting named like a core one (install, `chi bundle check`). See [configuration.md](configuration.md#per-session-settings). |
|
|
607
615
|
| Plugin API | `plugin/api.rb` (`Plugin::Api`), `plugin/tool_spec.rb` (`Plugin::ToolSpec`: a checked tool declaration, how it is registered), `plugin/loader.rb`, `plugin/context.rb` (`ctx`), `plugin/http.rb` + `plugin/http_transport.rb` (`ctx.http`), `plugin/card.rb` (`Plugin::Card`) | What a bundle's plugin registers: tools, commands, annotation actions, hooks, services, toolkits, peer sources; what its handlers get as `ctx` ([plugins.md](plugins.md)). |
|
|
608
616
|
| 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)). |
|
|
609
617
|
| Shipped bundles | `bundles/` (`mcp`, `github-pr`, `loop-guard`, `skills`, `source-links`, …) | Bundles that ship with chi. |
|
data/docs/cli.md
CHANGED
|
@@ -15,7 +15,8 @@
|
|
|
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, the stage's asking text and a resolved question card's reply
|
|
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
|
|
18
|
+
- `chi web --web-working-set` — the stage view's working set (experimental, off by default; `--no-web-working-set` turns a config's `web.working_set: true` off): what each turn brought into the model's context, in the stage and under each finished turn; `?working_set=1|0` on the page URL overrides it (see [The working set](#the-working-set))
|
|
19
|
+
- `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, and its own settings (`--set`; a `settings:` line), from a live worker's `GET stats`, else its saved `analytics.json` (`--format json` one object, with `settings`), 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
20
|
- `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
21
|
- `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
22
|
- `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 — to an idle session whose last turn already ended, that ended turn's reply or end comes back; `--wait --turn T ID` with no message waits for exactly turn T, whether running, queued or last ended; `--format json` includes its `turn_id` when known, for waiting again after exit 3 or 4; 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))
|
|
@@ -281,7 +282,7 @@ controls exit behavior (`--non-interactive`); `--resume` composes with both.
|
|
|
281
282
|
| `--thinking LEVEL` | This session's own thinking level: `off`, `low`, `medium` or `high`, saved in the session and first in the order (`default` unsets it). On `--resume` or `--attach` it is set at once, through a `/thinking` on an attached worker. With `chi web` it is instead the default for the sessions its workers run, below a session's own (as env `SAMAGOTCHI_THINKING_LEVEL` is). See "Thinking" in configuration.md. |
|
|
282
283
|
| `--toolkit NAME`, `--tool NAME`, `--no-tool NAME` | A new session's toolkit, the tools its prompts declare: `full` (every built-in), `lean`, `child`, one of config's `toolkit.kits` or a bundle's (without `--toolkit`: config's `toolkit.default`), with tools declared on top of it (`--tool`) or left out (`--no-tool`); both repeatable, a comma list too. Saved in the session as given; a respawned worker, a fork and a continue keep it. Ignored with `--attach`/`--resume` (one line, as `--memory`); `/toolkit` changes it. Not on `chi web` (config's `toolkit.default` covers its sessions). See [Toolkits](configuration.md#toolkits). |
|
|
283
284
|
| `--parent-answers LEVEL` | A new session's own `guardrails.parent_answers` (`hard`, `standard` or `soft`): what a parent agent may answer on its questions. It may only tighten config.yml's: the stricter of the two applies, and a looser one is saved as given with a warning (`--parent-answers soft is looser than config.yml's guardrails.parent_answers: standard; standard applies`). Saved in the session; a respawned worker, a fork and a continue keep it, a `delegate` child takes its parent's. Ignored with `--attach`/`--resume` (one line, as `--toolkit`); refused with `chi web`. Only you loosen it: `/parent-answers` in the terminal or the web. See [Guardrails](guardrails.md#answers-from-a-parent-agent). |
|
|
284
|
-
| `--set
|
|
285
|
+
| `--set KEY=VALUE` | A setting for a new session (repeatable; a later one of the same key wins). A core key a session may set (`recap.enabled`, `recap.sentences`) is typed by the key and goes first, over the CLI, env and config.yml: `--set recap.enabled=false` turns the idle recap off for this session; a value it doesn't take (`recap.enabled=maybe`) or a key no session sets (`guardrails.mode`) is an error, exit 2 (see [Per-session settings](configuration.md#per-session-settings)). Any other name is a bundle's `BUNDLE.KEY`, laid over config.yml's `bundles: <bundle>:` in what the bundle's plugin reads (`ctx.settings`): `--set cost-cap.cap=3`. The value is typed simply: an integer (`3`, `-1`) or a decimal (`2.5`, `.5`, `1e1`) is a number, `true`, `yes` and `on` are true, `false`, `no` and `off` are false (any case, as in config.yml), anything else stays the text as given (`010`, `0x10`, `3:30`, `y`, `null`), and so does every value of a key the manifest types `string`. For cost-cap, `0`, a negative number or `off` is no cap. Only a key the installed bundle's manifest lists in `session_settings:` is taken, with a value of the type it gives the key: a bundle that isn't installed (or whose plugin doesn't load), a key it doesn't list (a record installed before the bundle listed it says to run `chi update` or `chi bundle upgrade NAME`), a value of another type (`--set cost-cap.cap=five`), or another shape (`--set foo`, `--set a.b.c=1`) is an error naming what it takes, exit 2, nothing started. Saved in the session; a respawned worker, a fork and a continue keep it, a delegate child doesn't. Ignored with `--attach`/`--resume` (one line, as `--toolkit`); refused with `chi web`. See [Per-session settings](plugins.md#per-session-settings). |
|
|
285
286
|
| `--profile NAME` | Prompt profile (`qwen36` or `gemma4`) for every model in this run, over config and the server's template (same as `--model-profile`, env `SAMAGOTCHI_MODEL_PROFILE`). See "Prompt profile" in configuration.md. |
|
|
286
287
|
| `--memory NAME` | Preload a memory entry into the system prompt (repeatable; a comma list too). Merged under the config.yml `memories:` baseline. Works attached: the list is stored on the session, so its worker builds the same prompt on every respawn. |
|
|
287
288
|
| `--append-system-prompt FILE` | Put `FILE`'s text into the system prompt, after AGENTS.md and before the memory indexes (repeatable; relative to the shell's directory). Added after the config.yml `append_system_prompt:` list. A missing or unreadable file is an error, exit 1. Saved in the session, so a respawned worker, a fork and a continue keep it; ignored with `--attach`/`--resume` (one line, as `--memory`). See [Appended prompt files](configuration.md#appended-prompt-files). |
|
|
@@ -499,7 +500,8 @@ a terminal, headed by `<id8> <status> <model>`: a live worker answers its
|
|
|
499
500
|
Bridge's `GET stats`, else the snapshot is rebuilt from the session's saved
|
|
500
501
|
`analytics.json` (never starting a worker; a worker that does not answer in
|
|
501
502
|
time falls back to the disk and the line says so). `--format json` prints one
|
|
502
|
-
object `{session_id, status, live, metrics}
|
|
503
|
+
object `{session_id, status, live, metrics, settings}` (`settings`: the session's own `--set` values, flat as
|
|
504
|
+
`--set` names them, `{}` for none); a session with no
|
|
503
505
|
`analytics.json` yet reports `metrics: null` (`(no metrics yet)` in text) and
|
|
504
506
|
exits 0. An unknown or ambiguous id exits 1 with `chi sessions stop`'s
|
|
505
507
|
wording. See [Sessions](sessions.md#cli).
|
|
@@ -601,6 +603,25 @@ the same values on its `llm context:` line. The web's info bar shows them as the
|
|
|
601
603
|
through `/llm-context`. See "LLM context: a session's own strategy" in
|
|
602
604
|
[configuration.md](configuration.md).
|
|
603
605
|
|
|
606
|
+
`/working-set` lists the session's working set as the model has it (see [The
|
|
607
|
+
working set](#the-working-set)): each file, memory and URL its turns read,
|
|
608
|
+
edited or fetched, with its state (`stale`, `forgotten`, `dropped`) and what it
|
|
609
|
+
costs as sent, then the changes the next turn starts with. `/working-set drop
|
|
610
|
+
KEY…` takes an item out of what the model is sent: every read of it still sent
|
|
611
|
+
goes as a stub, `(dropped by the user) — read it again if the task needs it`,
|
|
612
|
+
whatever the LLM context strategy (none too), and stays dropped across a
|
|
613
|
+
strategy switch. KEY is a path (absolute or the session folder's), `memory:NAME`
|
|
614
|
+
or a URL. `/working-set undrop KEY…` sends it whole again. A change applies
|
|
615
|
+
from the next turn's first request, which also carries one line telling the
|
|
616
|
+
model what you dropped or brought back (so it doesn't read it again by reflex);
|
|
617
|
+
the reply says what it frees and the tail the server reads again (a drop changes
|
|
618
|
+
history, so the prompt cache breaks there once). An undrop before that request
|
|
619
|
+
undoes the drop for free. Refused, with why: an item only edited or written
|
|
620
|
+
(nothing of it to drop), one not in the set, an older session's output chi
|
|
621
|
+
can't name. The model can't undo a drop (`forget_outputs` refuses it).
|
|
622
|
+
`/working-set` alone answers mid-turn too; `drop`/`undrop` sent while a turn
|
|
623
|
+
runs wait for the turn's end.
|
|
624
|
+
|
|
604
625
|
`/thinking` shows the thinking level the next turn runs at and where it came
|
|
605
626
|
from (`session`, `--thinking` / `SAMAGOTCHI_THINKING_LEVEL`, `models: <key>`,
|
|
606
627
|
`hosts.<name>`, `thinking.level`). `/thinking off|low|medium|high` sets the
|
|
@@ -740,7 +761,7 @@ REPL alike:
|
|
|
740
761
|
`cutting in…`, then `steered`. A phone shows the short form (`↳ after this
|
|
741
762
|
thinking · 0:42`) with `cut in` and `queue` chips.
|
|
742
763
|
- Commands answer, wait or are refused, by what they do:
|
|
743
|
-
- At once, beside the turn: `/stats`, `/recap
|
|
764
|
+
- At once, beside the turn: `/stats`, `/recap` (and `/recap on|off|default`), `/help`, `/context`, a
|
|
744
765
|
plugin's anytime command (`/btw`), and the commands that only show
|
|
745
766
|
something: `/models` (with a filter too), and `/model`, `/llm-context`,
|
|
746
767
|
`/thinking`, `/reasoning-history` and `/guardrails` alone.
|
|
@@ -956,6 +977,71 @@ steps saved before that have none, so they show no thinking. An `edit` or
|
|
|
956
977
|
made (up to 120 lines or 8 KB), live and after a reload (see
|
|
957
978
|
[Guardrails](guardrails.md#ask) for the diff an approval shows first).
|
|
958
979
|
|
|
980
|
+
### The working set
|
|
981
|
+
|
|
982
|
+
`web.working_set: true` (or `chi web --web-working-set`,
|
|
983
|
+
`SAMAGOTCHI_WEB_WORKING_SET=true`; `?working_set=1` or `?working_set=0` on the
|
|
984
|
+
page URL for one page load) shows, in the stage view, what a turn brought into
|
|
985
|
+
the model's context: the files it read, edited or wrote, the memories it read
|
|
986
|
+
or wrote and the URLs it fetched. Off by default while it is tried out; the
|
|
987
|
+
turn view ignores it.
|
|
988
|
+
|
|
989
|
+
- **The rail**, on the right of the stage's live slots: the running turn's set
|
|
990
|
+
in four lines, folded as it grows (files under one folder become
|
|
991
|
+
`…/web/public/ · 9 files ✎2`, memories `◆ 3 memories`, else `N files · K
|
|
992
|
+
dirs`), with the newest entries marked for a few seconds and the context
|
|
993
|
+
ring once its fill is known. It never changes the stage's height. Its `–`
|
|
994
|
+
folds it to one line (`SET 17 + ◆ name`), kept per browser; a click opens the
|
|
995
|
+
list. In a stage narrower than 760 px it is one line under the last calls;
|
|
996
|
+
on a phone it isn't shown.
|
|
997
|
+
- **The footprint**, one line under each finished turn's block, live and after
|
|
998
|
+
a reload: `touched …/web/public/ · 4 files · ◆ 2 memories s2–10 · +1 url ·
|
|
999
|
+
edited 1`. A step tag (`s2`) goes to that call's row; the rest opens the
|
|
1000
|
+
turn's list. A turn that touched nothing has none.
|
|
1001
|
+
- **The `set N` chip** in the session bar, in place of the `mem N` chip (whose
|
|
1002
|
+
tooltip goes too): the session's whole set, preloaded (`--memory`) and muted
|
|
1003
|
+
(`--mute`) memories included; its dot lights when the set changed since you
|
|
1004
|
+
last opened it.
|
|
1005
|
+
- **The list** the three open (a bottom sheet on a phone): this turn or the
|
|
1006
|
+
whole session, files grouped by folder (a group opens in place), memories
|
|
1007
|
+
(used, preloaded, muted) and URLs, each with what was done to it (`read ×2`,
|
|
1008
|
+
`read, edited`, `preloaded`) and a step tag (`s3`, `t2·s3` in the session's
|
|
1009
|
+
scope, `prompt` for a preloaded memory) that goes to the call. A file opens
|
|
1010
|
+
as its row's title does, a URL in a new tab. A row (on hover or keyboard
|
|
1011
|
+
focus) and a folded group offer `drop`, which runs `/working-set drop` (see
|
|
1012
|
+
`/working-set` above); a dropped row offers `undrop`. Between turns it
|
|
1013
|
+
applies at once; while a turn runs it waits for the turn's end: the row is
|
|
1014
|
+
dashed with `drops next turn` and an `undo`, and the list's foot counts the
|
|
1015
|
+
pending changes (`undo all`), in every tab and after a reload. On a phone a
|
|
1016
|
+
tap on a row opens its actions under it. `drop` is greyed, with why on
|
|
1017
|
+
hover, for an item only edited, a memory only preloaded, or one already
|
|
1018
|
+
forgotten.
|
|
1019
|
+
|
|
1020
|
+
Only `read`, `edit`, `write`, `memory_read`, `memory_write` and `web_fetch`
|
|
1021
|
+
calls that succeeded count; files an `execute` touched don't.
|
|
1022
|
+
|
|
1023
|
+
What the model still has of each item comes from chi, not the page, so it is
|
|
1024
|
+
the same live, after a reload and in every tab:
|
|
1025
|
+
- **stale** (faded): the file changed since the model last read, edited or
|
|
1026
|
+
wrote it, whatever changed it (a later `execute` such as `sed` or `git
|
|
1027
|
+
checkout`, your editor, another session). The model's own successful edit or
|
|
1028
|
+
write doesn't make a file stale. Chi checks at each request and when you
|
|
1029
|
+
open the list, so a file changed while the session sat idle shows stale on
|
|
1030
|
+
opening it. A turn saved before chi kept that record shows its files live.
|
|
1031
|
+
- **dropped** (struck): you dropped it (`/working-set drop`, the list's
|
|
1032
|
+
`drop`); its reads are sent as stubs under every strategy until you undrop
|
|
1033
|
+
it.
|
|
1034
|
+
- **forgotten** (struck): nothing of the item's content is still sent to the
|
|
1035
|
+
model under the session's current LLM context strategy (`forget_outputs`
|
|
1036
|
+
forgot every read of it; see
|
|
1037
|
+
[the forget layer](configuration.md#llm-context-the-forget-layer)). Lines a
|
|
1038
|
+
forget kept count as still sent. Under `/llm-context strategy none` nothing
|
|
1039
|
+
is cut, so a forgotten item is live again from the next request.
|
|
1040
|
+
|
|
1041
|
+
The list says `stale`, `forgotten` or `dropped` in words with each row, and how many
|
|
1042
|
+
tokens its content costs as sent (`~1.2k`); a folded group shows its forgotten
|
|
1043
|
+
members as `✂n`, and a footprint adds `n forgotten`.
|
|
1044
|
+
|
|
959
1045
|
### Web annotate presets
|
|
960
1046
|
|
|
961
1047
|
Selecting text in an answer, a thinking block, a tool row or one of your
|
|
@@ -1065,7 +1151,16 @@ working on, what came of it and what is still open, not a turn-by-turn log.
|
|
|
1065
1151
|
after it (`recap (before the last 2 turns)>`). One written while you sit at
|
|
1066
1152
|
the prompt prints there.
|
|
1067
1153
|
- `/recap` shows the saved one and asks for a new one when the chat moved on
|
|
1068
|
-
(`writing a recap…`, then the recap when it comes).
|
|
1154
|
+
(`writing a recap…`, then the recap when it comes). The web answers the bare
|
|
1155
|
+
`/recap` with a note (the recap shows there by itself).
|
|
1156
|
+
- `/recap off` and `/recap on` turn the recap off or on for this session, at
|
|
1157
|
+
once and in any UI (the web composer too, and mid-turn); `/recap default`
|
|
1158
|
+
goes back to config.yml's. The reply says both: `recap: off (this session;
|
|
1159
|
+
config.yml: on)`. It is the session's own `recap.enabled`, as `--set
|
|
1160
|
+
recap.enabled=false` gives it (see [Per-session
|
|
1161
|
+
settings](configuration.md#per-session-settings)): saved with the session,
|
|
1162
|
+
so a respawned worker keeps it, and it beats config.yml (`/recap on` under
|
|
1163
|
+
`recap: false` turns it on here). With it off, `/recap` says so.
|
|
1069
1164
|
- One written while a continue offer waits (the last turn ran out of steps)
|
|
1070
1165
|
says that turn stopped before the task was finished. Answering `no` counts
|
|
1071
1166
|
as activity, so the next recap no longer says so.
|
data/docs/configuration.md
CHANGED
|
@@ -119,7 +119,8 @@ own subsystems: `hosts:` (below), `models:` (see "Prompt profile" and
|
|
|
119
119
|
`guardrails:` (see [Guardrails](guardrails.md)), `bundles:` (a bundle's
|
|
120
120
|
settings for its hooks, see [Hooks: Settings](hooks.md#settings); a session's own
|
|
121
121
|
`--set BUNDLE.KEY=VALUE`, for a key the bundle's manifest lists in `session_settings:`, lays over them, see
|
|
122
|
-
[Per-session settings](plugins.md#per-session-settings)
|
|
122
|
+
[Per-session settings](plugins.md#per-session-settings); `--set KEY=VALUE` does the same for a few core keys,
|
|
123
|
+
see "Per-session settings" below),
|
|
123
124
|
`memories:` and `append_system_prompt:` (see "Appended prompt files"). Their entry names (host names, model ids, aliases) are yours to
|
|
124
125
|
choose. The `memories:` list is the persistent baseline for preloaded memory entries —
|
|
125
126
|
the same name shape as `--memory` (bare name or `scope/name`), merged under
|
|
@@ -160,7 +161,7 @@ or `chi web` restart.
|
|
|
160
161
|
| `context.every_seconds` | Next context poll | The poller checks it for each source that has no explicit interval. |
|
|
161
162
|
| `guardrails.*` | Next tool call or approval | Guardrail rules and disable lists are reloaded when the config file changes; rule settings take effect on that evaluation. `guardrails.parent_answers` is checked when a parent answers a question. |
|
|
162
163
|
| `hooks`, `bundles` | Worker start | Hooks, plugins and their bundle settings load with the engine. |
|
|
163
|
-
| `recap.*` | Worker start | The engine builds its recap job
|
|
164
|
+
| `recap.*` | Worker start | The engine builds its recap job at start, and again when it binds a session with its own `recap.enabled` or `recap.sentences` (`--set`, see "Per-session settings") and when `/recap on\|off\|default` changes the session's own value. |
|
|
164
165
|
| `session.shared` | Next `chi` invocation | It selects attached-worker or in-process mode for that invocation. |
|
|
165
166
|
| `session.idle_exit_minutes`, `session.keep_empty`, `session.max_children`, `session.delegate_reports`, `session.task_wakes`, `session.max_wakes` | Worker start or next matching lifecycle decision | Existing workers keep their idle-exit timer; the other values are read for the next corresponding decision. |
|
|
166
167
|
| `session.retention_*`, `session.max_count`, `session.keep_status`, `session.sweep_interval_hours` | Next retention sweep | `chi web` sweeps on its configured schedule and on `GET /api/sessions`; `chi sessions prune` uses the values for that invocation. The sweep interval is checked on the next hub tick. |
|
|
@@ -172,6 +173,26 @@ or `chi web` restart.
|
|
|
172
173
|
| `kitty.*`, `tmux.*` | `chi desktop upgrade` or desktop update | These settings are copied into the desktop helper's launch file. |
|
|
173
174
|
| `model.profile`, `reasoning_history` | Not from config.yml | These are CLI/environment settings; `models:` and `hosts:` provide their model- and host-specific forms. |
|
|
174
175
|
|
|
176
|
+
### Per-session settings
|
|
177
|
+
|
|
178
|
+
A few core keys can be set for one session: `chi --set KEY=VALUE` (or `chi send --new --set KEY=VALUE`, or
|
|
179
|
+
`POST /api/sessions` `settings`) at its creation, and `recap.enabled` later too with `/recap on`, `/recap off` or `/recap default`
|
|
180
|
+
(at once; `default` removes the session's own value, see [Session recap](cli.md#session-recap)). The value is saved in the session file (`config_settings`), so a
|
|
181
|
+
worker respawn, a continue and a fork keep it; a delegate child starts without it, on config.yml's. It goes first:
|
|
182
|
+
|
|
183
|
+
session (--set) → CLI → environment → config.yml → default
|
|
184
|
+
|
|
185
|
+
- `recap.enabled`: `true` or `false` (also `yes`/`on`/`1`, `no`/`off`/`0`); `true` turns the recap on for the
|
|
186
|
+
session even under `recap: false`.
|
|
187
|
+
- `recap.sentences`: `N` or `N-M` (1–10).
|
|
188
|
+
|
|
189
|
+
A value is typed by its key and checked when given: `--set recap.enabled=maybe` is refused (`recap.enabled takes
|
|
190
|
+
true or false, not "maybe"`), and so is a key no session sets (`--set guardrails.mode=strict`: not a session
|
|
191
|
+
setting). The same `--set` takes a bundle's `BUNDLE.KEY` (see [Per-session settings](plugins.md#per-session-settings));
|
|
192
|
+
a name that is a core key is always the core one, and a bundle can't offer a setting whose `NAME.KEY` is one.
|
|
193
|
+
`/stats` lists a session's own values (`settings: recap.enabled=false · cost-cap.cap=3`), and `chi sessions stats
|
|
194
|
+
--format json` has them as `settings`.
|
|
195
|
+
|
|
175
196
|
### Environment variables
|
|
176
197
|
|
|
177
198
|
Every setting has an environment variable (except the ones the table marks
|
|
@@ -1589,14 +1610,14 @@ column says so, a `--kebab-name` flag. The maps (`hosts:`, `models:`,
|
|
|
1589
1610
|
| `server.open_timeout` | `10` | yes | Connection timeout, seconds. |
|
|
1590
1611
|
| `server.read_timeout` | `600` | yes | Read timeout, seconds. |
|
|
1591
1612
|
| `server.first_token_timeout` | 120 remote, off local | | Seconds to the first token; `0` = off. `hosts.<name>.first_token_timeout` wins. |
|
|
1592
|
-
| `recap.enabled` | on | | `false` (or `recap: false`) turns the idle recap off. |
|
|
1613
|
+
| `recap.enabled` | on | | `false` (or `recap: false`) turns the idle recap off. Per session too: `--set recap.enabled=false`, or `/recap off` in the session (see "Per-session settings"). |
|
|
1593
1614
|
| `recap.model` | session's | yes | Model that writes the recap: an id, alias or `host:model` (the host then picks where to ask; a bare id goes where a bare `--model` goes). |
|
|
1594
1615
|
| `recap.host_ref` | session's | yes | A `hosts:` name to ask (`host:` is accepted too, also a host name, not a model ref). |
|
|
1595
1616
|
| `recap.base_url` | none | yes | An OpenAI API base to ask instead (`http://h:8081/v1`). |
|
|
1596
1617
|
| `recap.inactivity` | `180` | yes | Idle seconds before a recap. |
|
|
1597
1618
|
| `recap.timeout` | `30` | yes | Seconds a recap request may take. |
|
|
1598
1619
|
| `recap.min_user_turns` | `2` | yes | Prompts a session needs before it gets a recap. |
|
|
1599
|
-
| `recap.sentences` | `2-4` | yes | Recap length, `N` or `N-M` (1–10). |
|
|
1620
|
+
| `recap.sentences` | `2-4` | yes | Recap length, `N` or `N-M` (1–10). Per session too: `--set recap.sentences=3`. |
|
|
1600
1621
|
| `broadcast.active_hours` | `8` | | `chi broadcast` reaches a session a worker or a chi REPL runs, or whose last turn ended within this many hours. See [Broadcast](broadcast.md). |
|
|
1601
1622
|
| `broadcast.ticket_pattern` | `\b[A-Z][A-Z0-9]+-\d+\b` | | A Ruby regex for ticket ids; one in the note and in a session's branch (any case) or prompts delivers the broadcast there. See [Broadcast](broadcast.md). |
|
|
1602
1623
|
| `broadcast.triage_model` | recap's | | The model that judges a recipient no tag matched (a model ref, as `recap.model`); unset: the recap's model, else `default.model`. A ~9B dense instruct model or larger; 4B-class ones say yes to nearly everything. See [Broadcast](broadcast.md#triage). |
|
|
@@ -1689,6 +1710,7 @@ column says so, a `--kebab-name` flag. The maps (`hosts:`, `models:`,
|
|
|
1689
1710
|
| `web.host` | `127.0.0.1` | yes | `127.0.0.1`, `::1` or `localhost`; `lan` (this machine's private IPv4 address) or one of its IPv4 addresses also opens `chi web` to the network, with an access token (`chi web --new-token` replaces it). Anything else binds `127.0.0.1` with a warning. See [CLI: chi web on your phone](cli.md#chi-web-on-your-phone). |
|
|
1690
1711
|
| `web.markdown` | `false` | yes | Render answers as Markdown in `chi web`. |
|
|
1691
1712
|
| `web.view` | `stage` | yes | How `chi web` draws a turn: `stage` (the running turn pinned above the composer) or `turn` (one block per turn in the history). See [CLI](cli.md#web-views). |
|
|
1713
|
+
| `web.working_set` | `false` | yes | The stage view's working set (experimental): the files, memories and URLs a turn brought into the model's context, in a rail in the stage, a footprint line under each finished turn and a `set N` chip in place of the mem chip. `?working_set=1` or `?working_set=0` on the page URL overrides it for that page load; the turn view ignores it. See [CLI: the working set](cli.md#the-working-set). |
|
|
1692
1714
|
| `web.annotate_presets` | `Agreed\|Could you please elaborate?` | yes | Quick replies next to Annotate in `chi web`, `\|`-separated (a YAML list works too); `""` in the file or on the CLI leaves only Annotate (an empty env value means the default). See [CLI](cli.md#web-annotate-presets). |
|
|
1693
1715
|
| `web.editor` | `vscode` | yes | What a file ref in `chi web` (a file tool row's title, a diff line) opens, for a viewer on this machine: a preset (`vscode`, `vscode-insiders`, `cursor`, `zed`) or a URL template with `{path}` and an optional `{line}`; `none` turns refs off. See [Opening files from chi web](#opening-files-from-chi-web). |
|
|
1694
1716
|
| `history.file` | state dir | | Prompt history path, shared by the TUI and the web composer. |
|
data/docs/internals/bundles.md
CHANGED
|
@@ -32,7 +32,7 @@ user-facing side (what a bundle owns, profiles, needs) is in [memory.md](../memo
|
|
|
32
32
|
| `SourceIdentity` (source.rb) | what a source is, for comparing two installs of one name: `shipped:<dir>` (any gem or checkout), `git:<url>` (no `#ref`, trailing `/` or `.git`), `path:<realpath>`; nil when it can't place one |
|
|
33
33
|
| `PreparedSource` (source.rb) | one source normalized once (dir, owned, git commit): `BundleCommand` reads the bundle's name from its `manifest.yml` (the name for every kind of source, a git URL too) and hands it to the Installer (`prepared:`), so a source is cloned or extracted once per command |
|
|
34
34
|
| `MemoryFiles` | which top-level `*.md` files of a bundle are its memories (`.select`: the `files:` list, else all but README/LICENSE and the like), `.unshipped` (listed, not shipped) and `.symlinks` (skipped: a symlink is never a memory) |
|
|
35
|
-
| `Manifest` | parses/validates `manifest.yml` (`name:` is the bundle's name and a directory under `.bundles/`, so a path such as `../x`, `a/b`, `.` or `..` is refused: `name: … is not a bundle name`; YAML that doesn't parse or isn't a mapping is a `ValidationError` too; files, hooks as `BundleHook`, plugin, scripts, needs, requires_chi, includes, context_providers, session_settings: the keys a session's `chi --set` may give, a list or a mapping of them to types (`SESSION_SETTING_TYPES`), recorded at install in `manifest.json` (`session_settings`, `session_setting_types`) for `
|
|
35
|
+
| `Manifest` | parses/validates `manifest.yml` (`name:` is the bundle's name and a directory under `.bundles/`, so a path such as `../x`, `a/b`, `.` or `..` is refused: `name: … is not a bundle name`; YAML that doesn't parse or isn't a mapping is a `ValidationError` too; files, hooks as `BundleHook`, plugin, scripts, needs, requires_chi, includes, context_providers, session_settings: the keys a session's `chi --set` may give, a list or a mapping of them to types (`SESSION_SETTING_TYPES`), recorded at install in `manifest.json` (`session_settings`, `session_setting_types`) for `SessionConfig` to check) and writes it (`Manifest.write`, for Builder). It ignores `requires_chi_next`, a shipped bundle's release-time marker (`script/release/release_tools.rb`, docs/releasing.md) |
|
|
36
36
|
| `Installer` | one install/upgrade/dry run of one bundle (below) |
|
|
37
37
|
| `AssetInstaller` | the parts that live in `.bundles/<name>/`: hooks, guardrail rules, plugin, scripts; returns `AssetInstaller::Installed` (the paths the record keeps) |
|
|
38
38
|
| `Merger` | 3-way classification per file: `install`, `fast_forward`, `keep`, `noop`, `conflict` |
|
data/docs/internals/engine.md
CHANGED
|
@@ -509,6 +509,7 @@ Turn events (the main ones; `Events` in `events.rb` keeps the shared sets):
|
|
|
509
509
|
| `:question_requested` / `:question_answered` / `:question_cancelled` | `QuestionDesk`: a question is asked (an approval, `ask_user_question`, a hook's or plugin's `ask_user`, the step-limit Continue), answered, or withdrawn | `{pending_question}` / `{id, answer}` / `{id, reason}` |
|
|
510
510
|
| `:plugin_init_wait` | a turn waits for plugin init tasks that provide tools (`PluginTasks`) | `{tasks: [{bundle, id, label}]}` |
|
|
511
511
|
| `:used_memories_updated` | a memory was read, and after the loop | `{used_memory_names, read_names?}` |
|
|
512
|
+
| `:working_set_updated` | after `:generation_started` (the running turn's conversation, the turn's strategy) and once in `end_turn` before the end event (the kept messages), only when the set differs from the last one emitted for the session and is not empty, except one empty event when the last one had items (a rollback emptied the set): a tool-free turn emits none (`Engine#emit_working_set`); between turns `Engine#announce_working_set` announces it under the next turn's strategy (after a `/working-set` op, held behind the command's `command_ran`) | `{items: [{kind, key, state (live\|stale\|forgotten\|dropped), tokens, ops, count, first_id}], at}` (`WorkingSet`, internals/working-set.md) |
|
|
512
513
|
| `:hook_notice` | a hook's or plugin's notify during a turn | `{hook, text, level}` (announced with `between_turns: true` outside a turn) |
|
|
513
514
|
| `:guardrail_warning` | a guardrails line during a turn | `{message}` |
|
|
514
515
|
| `:turn_completed` | normal end | Engine event `{result, turn_summary, display_pending}`; the Bridge's SSE frame omits `result` (answer remains in `turn_summary.output`) |
|
|
@@ -35,6 +35,20 @@ lets the model forget its own tool outputs. The pieces:
|
|
|
35
35
|
- **Restore** takes the forget off the entry (`LLMContextEdit.remove`, a new edits Hash); the next request sends the
|
|
36
36
|
output again, outside the apply rule (the result says the tail the server reads again, and `ContextStatus#edited!`
|
|
37
37
|
restarts the estimate). A read whose stub was sent isn't restored; a staged one is.
|
|
38
|
+
- **Which edits are sent** is one predicate, `LLMContextView#sends?(edit)`: applied, and its kind one of the view's
|
|
39
|
+
layers or `:drop`. The view stubs by it and `WorkingSet` decides "still sent" by it. The view's layers are
|
|
40
|
+
`LLMContextStrategy::LAYERS` (`stale`, `forget`), the strategy's words, not `LLMContextEdit::KINDS`: whatever a
|
|
41
|
+
caller passes as the strategy, an edit kind no strategy names never becomes a layer that `apply_llm_context!` would
|
|
42
|
+
hand to `LLMContextApply.run!`. Under none the view has no layers and, unless an entry holds a drop
|
|
43
|
+
(`LLMContextEdit.drop_on?`, one scan), `#messages` returns the Array it was given.
|
|
44
|
+
- **The user's layer, always on**: an edit of kind `:drop` (`by: "user"`, the working set's drop:
|
|
45
|
+
[working-set.md](working-set.md#steering-drop-and-undrop)) is sent under every strategy, none included, as
|
|
46
|
+
`(dropped by the user) — read it again if the task needs it` after the output's lead. It is saved applied by the
|
|
47
|
+
op itself, between turns, so the apply rule never holds it and no `[#id]` is added under none. One edit per id: a
|
|
48
|
+
drop on an output that holds another edit keeps that edit's saved Hash in its `was:`, and an undrop puts it back.
|
|
49
|
+
`LLMContextApply.measure`/`.weigh` and `#restored_line` build their views from the same class, so a drop counts in
|
|
50
|
+
them under none too. The model can't take a drop off: forget_outputs refuses to forget or restore a dropped
|
|
51
|
+
output, in `WorkingSetSteer::Refused`'s words ("dropped by the user").
|
|
38
52
|
- **Stubs** (`LLMContextView`): `(forgotten) <note>` on the first output of a call's forgets in a row, `(forgotten
|
|
39
53
|
with tN: see its note)` on the rest (a run of the same note, author and stamp, no other output between them),
|
|
40
54
|
` [restore: tN]` on a non-read with a stored id, then each kept range under `lines A-B kept:`. The entry keeps its
|
|
@@ -56,7 +56,7 @@ right-hand column happens.
|
|
|
56
56
|
│ ◄── remote Claude / Messages: breakpoint #2 on the last │ the image cut moving
|
|
57
57
|
│ non-system message (Messages: its last user block) │ a batch, history
|
|
58
58
|
├──────────────────────────────────────────────────────────────────────────┤ sanitizing (thinking
|
|
59
|
-
│ tail notes reminders, turn notes, steers
|
|
59
|
+
│ tail notes reminders, turn notes, steers, the working-set note │ stripped per spec)
|
|
60
60
|
│ new prompt this turn's user message │
|
|
61
61
|
└──────────────────────────────────────────────────────────────────────────┘
|
|
62
62
|
```
|
|
@@ -108,6 +108,13 @@ right-hand column happens.
|
|
|
108
108
|
loaded name stays deferred, a stub once its source is gone), so the request after a load reads the whole prefix;
|
|
109
109
|
the loaded definitions and the new result are the fresh part. A plugin's
|
|
110
110
|
`ctx.load_tools` only appends (a system `tool_addition` after the user message, never a change to `tools`).
|
|
111
|
+
- A user's working-set drop (`/working-set drop`, [working-set.md](working-set.md#steering-drop-and-undrop)) changes
|
|
112
|
+
an earlier entry: it is saved between turns, so the next turn's first request is the first to send the stub and
|
|
113
|
+
the cache breaks there once, from the dropped output's entry on (the command's reply says that tail; an undrop
|
|
114
|
+
after the drop was sent breaks it once more). It is sent under every strategy, so it is the one edit that rewrites
|
|
115
|
+
history under `none`; without a drop, `none` sends the stored Array as it is. Its `working_set` note (what the user
|
|
116
|
+
dropped or brought back) is a tail system message after the history, one per turn with ops, escaped as context
|
|
117
|
+
notes are (`Prompt::ESCAPED_KINDS`). The turn-end warm-up never warms a drop sent after the turn: it misses once.
|
|
111
118
|
- Side requests (idle recap, `/btw`) go through `IdleClient` with their own short system prompt. On a current
|
|
112
119
|
llama.cpp they don't evict the session (see the server settings below); chi never pins them to a slot.
|
|
113
120
|
|