samagotchi 0.110.0 → 0.111.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +39 -1
  3. data/docs/architecture.md +8 -5
  4. data/docs/cli.md +3 -0
  5. data/docs/configuration.md +44 -0
  6. data/docs/internals/engine.md +39 -10
  7. data/docs/internals/participants.md +1 -1
  8. data/docs/internals/remote-sessions.md +8 -4
  9. data/docs/internals/web-push.md +210 -0
  10. data/docs/internals/working-set.md +7 -6
  11. data/docs/sessions.md +1 -1
  12. data/lib/samagotchi/bundles/system/manifest.yml +1 -1
  13. data/lib/samagotchi/config.rb +4 -0
  14. data/lib/samagotchi/engine.rb +146 -490
  15. data/lib/samagotchi/engine_snapshots.rb +223 -0
  16. data/lib/samagotchi/event_fanout.rb +236 -0
  17. data/lib/samagotchi/model_binding.rb +138 -0
  18. data/lib/samagotchi/reply_wait/poll.rb +11 -10
  19. data/lib/samagotchi/reply_wait.rb +30 -3
  20. data/lib/samagotchi/send_command/wait_target.rb +10 -3
  21. data/lib/samagotchi/send_command.rb +2 -1
  22. data/lib/samagotchi/session.rb +12 -3
  23. data/lib/samagotchi/session_access/remote.rb +7 -2
  24. data/lib/samagotchi/session_access.rb +7 -3
  25. data/lib/samagotchi/session_manager.rb +5 -0
  26. data/lib/samagotchi/turn_endings.rb +137 -0
  27. data/lib/samagotchi/version.rb +1 -1
  28. data/lib/samagotchi/web/app.rb +27 -1377
  29. data/lib/samagotchi/web/grants.rb +3 -12
  30. data/lib/samagotchi/web/message_display.rb +274 -0
  31. data/lib/samagotchi/web/participant_access.rb +1 -1
  32. data/lib/samagotchi/web/private_files.rb +31 -0
  33. data/lib/samagotchi/web/public/app.js +30 -6
  34. data/lib/samagotchi/web/public/apple-touch-icon.png +0 -0
  35. data/lib/samagotchi/web/public/icons/chi-180.png +0 -0
  36. data/lib/samagotchi/web/public/icons/chi-192.png +0 -0
  37. data/lib/samagotchi/web/public/icons/chi-512.png +0 -0
  38. data/lib/samagotchi/web/public/index.html +4 -0
  39. data/lib/samagotchi/web/public/manifest.webmanifest +13 -0
  40. data/lib/samagotchi/web/public/notifications.js +178 -3
  41. data/lib/samagotchi/web/public/notify.js +1 -1
  42. data/lib/samagotchi/web/public/push.js +95 -0
  43. data/lib/samagotchi/web/public/stage_view.js +8 -0
  44. data/lib/samagotchi/web/public/sw.js +101 -0
  45. data/lib/samagotchi/web/public/turn_events.js +22 -0
  46. data/lib/samagotchi/web/push/attention.rb +105 -0
  47. data/lib/samagotchi/web/push/client.rb +103 -0
  48. data/lib/samagotchi/web/push/crypto.rb +126 -0
  49. data/lib/samagotchi/web/push/notifier.rb +230 -0
  50. data/lib/samagotchi/web/push/store.rb +295 -0
  51. data/lib/samagotchi/web/push.rb +73 -0
  52. data/lib/samagotchi/web/push_routes.rb +104 -0
  53. data/lib/samagotchi/web/server.rb +26 -2
  54. data/lib/samagotchi/web/session_access_routes.rb +19 -8
  55. data/lib/samagotchi/web/session_control.rb +441 -0
  56. data/lib/samagotchi/web/session_create.rb +384 -0
  57. data/lib/samagotchi/web/session_show.rb +411 -0
  58. data/lib/samagotchi/worker.rb +3 -2
  59. metadata +25 -1
@@ -99,9 +99,9 @@ when it has outputs and none is `sent`. An edit-only item, a failed run's file o
99
99
  ## Delivery
100
100
 
101
101
  **The event.** The Engine emits `{type: :working_set_updated, items:, at:}` (and `adds:` while the user's adds are
102
- pending: [Steering: add and unadd](#steering-add-and-unadd)) (`Engine#emit_working_set`):
103
- - after each `:generation_started`, in `build_stream_event_handler`, from the running turn's conversation
104
- (`Engine#live_conversation`, read on the turn's thread) under the turn's strategy
102
+ pending: [Steering: add and unadd](#steering-add-and-unadd)) (`Engine#emit_working_set`, `EventFanout`'s):
103
+ - after each `:generation_started`, in `build_stream_event_handler` (`EventFanout`), from the running turn's
104
+ conversation (`Engine#live_conversation`, read on the turn's thread) under the turn's strategy
105
105
  (`@kernel.turn_settings.llm_context`). Both loops start a generation after `apply_llm_context!`, so the set is
106
106
  what that request sends;
107
107
  - once in `Engine#end_turn`, after `replace_session_messages` and before the end event, from the kept messages (the
@@ -122,7 +122,7 @@ smaller set reaches the page then, not at the next request. It goes out whatever
122
122
  the Bridge (`ClientEvent.project`) passes it on unchanged, and the attached TUI ignores it.
123
123
 
124
124
  **The route.** `GET /api/sessions/:id/working_set` (`Web::App#handle_working_set`) answers the snapshot's `to_h`
125
- and `running`. With a live worker it builds from the worker's snapshot messages (as `handle_show` reads them, keys
125
+ and `running`. With a live worker it builds from the worker's snapshot messages (as `handle_show` (`Web::SessionShow`) reads them, keys
126
126
  symbolized) and the worker's llm ctx chip. Without one it builds from the session file and its saved chip
127
127
  (`SessionSetting::LLM_CONTEXT`). The folder is the session's `working_directory`. `running` is true when the
128
128
  snapshot has a turn in progress (`current_turn`).
@@ -206,8 +206,9 @@ projection), on both loops. It costs one model step; a model may skip it (the no
206
206
  - **The projection**: the pending adds are not items (nothing of them is sent), but the snapshot carries them:
207
207
  `WorkingSet.pending_adds` reads the pending note (`WorkingSet.pending_note_index` / `pending_ops`, which
208
208
  `WorkingSetSteer` delegates to) into `Snapshot#adds` (`WorkingSet::Add`: `kind`, `key`, `label`), and `to_h` adds
209
- `adds:` while any is pending. `Engine#emit_working_set` compares the items and the adds, so an add announces a new
210
- set and the next turn's first request (the note sent, no adds) emits again, which clears the page's pending add.
209
+ `adds:` while any is pending. `Engine#emit_working_set` (`EventFanout`, which keeps the last one emitted) compares
210
+ the items and the adds, so an add announces a new set and the next turn's first request (the note sent, no adds)
211
+ emits again, which clears the page's pending add.
211
212
  A running turn's set has none (the note was sent when it started), so the Bridge snapshot's `working_set` and the
212
213
  GET's `running` answer leave it out.
213
214
 
data/docs/sessions.md CHANGED
@@ -225,7 +225,7 @@ chi send --new --continues last:3fa2 -m "new day" # the next link of 3fa2's
225
225
  (`SAMAGOTCHI_THINKING_LEVEL=low chi send --new …`) only reaches the worker this call spawns: when the session's
226
226
  worker is woken later (by `chi web`, a delivery) without that env, the level is gone. Use `--thinking`.
227
227
  - `--new` prints `<full id> started` on stdout. With `--wait` that line (and the `sent` line for an existing session) goes to stderr, so stdout is exactly the answer: the reply of the turn the message started, in full. It is the worker's `output/` file, the same one `delegate` reads; a turn that ends with only tool calls and no text has none.
228
- - `--wait` takes one session: `--new` or one id. A session with a running turn is refused (`busy: a turn is running; --queue runs the message after it, chi send --wait ID waits for it, chi --attach ID shows it`, exit 1): the message would merge into it, and its reply would come back as the answer. To an idle session (or with `--new`) the wait is for the message's own turn (the ack's `enqueued_id`; one merged into a turn that started at that moment gets that turn's reply). `--queue --wait` is the way in: the message runs as a turn of its own after the running one, and the wait is for that turn alone (the ack's `enqueued_id` names its reply file and its `last_turn`), so the running turn's reply and end, and a question it asks meanwhile, are not the answer (it keeps waiting through them; its `--timeout` still applies); a question its own turn asks is (exit 3). Two queued waits each get their own turn's answer. A session waiting for an answer is still refused. `--format json` adds `delivery`: `queue`, or `next_step` when the running turn ended before the message went in (it then ran at once, and the answer is still its own).
228
+ - `--wait` takes one session: `--new` or one id. A session with a running turn is refused (`busy: a turn is running; --queue runs the message after it, chi send --wait ID waits for it, chi --attach ID shows it`, exit 1): the message would merge into it, and its reply would come back as the answer. To an idle session (or with `--new`) the wait is for the message's own turn (the ack's `enqueued_id`, or, for a `--new` that starts with the message, the id its create gives that first turn — `first_turn_id` in chi web's 201, `turn_id` in `--format json`; one merged into a turn that started at that moment gets that turn's reply). `--queue --wait` is the way in: the message runs as a turn of its own after the running one, and the wait is for that turn alone (the ack's `enqueued_id` names its reply file and its `last_turn`), so the running turn's reply and end, and a question it asks meanwhile, are not the answer (it keeps waiting through them; its `--timeout` still applies); a question its own turn asks is (exit 3). Two queued waits each get their own turn's answer. A session waiting for an answer is still refused. `--format json` adds `delivery`: `queue`, or `next_step` when the running turn ended before the message went in (it then ran at once, and the answer is still its own).
229
229
  - Exit codes with `--wait`: 0 answered; 3 the turn waits for an answer from you (a question, a hook's question, a guardrail approval, or the step-limit question: see [chi as a sub-agent](sub-agent.md#the-step-limit)), and the session keeps waiting: stderr gets the whole question (`waiting for an answer (approval): …`, its text, the numbered options, whether free text is allowed) and how to answer it (`chi answer ID --question QID --option N`, or `chi --attach ID`, the web); 4 `--timeout S` passed with the turn still running (it goes on; wait again); 1 the turn ended without a reply (canceled, failed or empty), the worker failed or vanished, or the session was stopped; 130 on Ctrl-C, which leaves the turn running (`still running: chi send --wait --turn T ID` for a turn whose id is known, else `chi send --wait ID waits again; chi --attach ID shows it`, as after a `--timeout`). There is no default timeout.
230
230
  - `--format json` (with `--wait`) prints one JSON object on stdout however the wait ends, for a script or a parent agent (see [chi as a sub-agent](sub-agent.md)): `{"status":"answered","session_id":…,"text":…}`; `{"status":"question",…,"question":{"id","kind","header","text","options","multi_select","allow_freeform","approval"},"answer_with":"chi answer ID --question QID --option N"}`, where `kind` is `question` (the model's), `hook` or `approval` (with the tool, command, cwd, rule, reason and offered scopes); `{"status":"running",…,"detail":…}` (exit 4, and on Ctrl-C); and `failed`, `canceled`, `removed` (a `--queue --wait` message taken back before it ran), `no_answer`, `error`, `worker_gone` or `stopped` with a `detail` line (exit 1); `failed` adds `error_kind` and `retryable`, `canceled` adds `cancel_reason` (`worker_stopped`: the turn waited for died with its worker and the next worker settled it) and `stopped_by`, when known. A failure before the wait (no such session, a busy one) is `error` too. A usage error (exit 2) prints no JSON.
231
231
  - `--wait ID` with no message (no `-m`, nothing piped) sends nothing: it waits for the session's next reply and prints and exits as above. With a turn running, that turn's reply (its `interrupted_turn` mark names it), not a turn's queued behind it; with the step-limit question standing, the reply of the turn its Continue runs; with an idle session whose last turn already ended, that ended turn is the answer: its reply, or its end when it left no reply — a turn that finished in the gap between waits is reported, not waited for. With none of those (or a worker whose `bridge.json` lacks `turn_ids`), the next reply of any turn. A running session is fine (that is the point), so after exit 3, 4 or 130 an agent waits again this way while the user answers in the web or `chi --attach`; the question pending when it starts doesn't count again. An idle session with no worker waits until something wakes one. With `--new`, or two ids, it is a usage error (exit 2).
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: samagotchi-system
3
- version: 0.110.0
3
+ version: 0.111.1
4
4
  scope: system
5
5
  description: Default system memories — identity, self map, config modification protocol, memory guide and the delegated-session rules
6
6
  files:
@@ -320,6 +320,10 @@ module Samagotchi
320
320
  Entry.new(key: "web.public_url", yaml_path: %w[web public_url], type: :string, default: nil, expose: %i[env config], lifecycle: :web_start),
321
321
  Entry.new(key: "web.proxy.identity_header", yaml_path: %w[web proxy identity_header], type: :string, default: nil, expose: %i[env config], lifecycle: :web_start),
322
322
  Entry.new(key: "web.proxy.owner", yaml_path: %w[web proxy owner], type: :string, default: nil, expose: %i[env config], lifecycle: :web_start),
323
+ # Phone notifications (Web::Push, docs/configuration.md "Phone notifications (Web Push)"): on with an https
324
+ # public URL once a device turned the bell on; contact is the VAPID sub (a mailto: or https URL; nil: the public origin).
325
+ Entry.new(key: "web.push.enabled", yaml_path: %w[web push enabled], type: :bool, default: true, expose: %i[env config], lifecycle: :web_start),
326
+ Entry.new(key: "web.push.contact", yaml_path: %w[web push contact], type: :string, default: nil, expose: %i[env config], lifecycle: :web_start),
323
327
 
324
328
  Entry.new(key: "no_interrupt", yaml_path: %w[no_interrupt], type: :bool, default: false, expose: %i[env config cli], lifecycle: :next_cli_run),
325
329
  Entry.new(key: "no_default_input", yaml_path: %w[no_default_input], type: :bool, default: false, expose: %i[env config cli], lifecycle: :next_cli_run),