samagotchi 0.67.0 → 0.68.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.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +21 -1
  3. data/docs/architecture.md +6 -3
  4. data/docs/internals/engine.md +58 -9
  5. data/docs/sessions.md +1 -1
  6. data/docs/testing.md +1 -1
  7. data/lib/samagotchi/bundles/system/manifest.yml +1 -1
  8. data/lib/samagotchi/effective_model.rb +283 -0
  9. data/lib/samagotchi/engine.rb +211 -358
  10. data/lib/samagotchi/level_setting_command.rb +99 -0
  11. data/lib/samagotchi/llm_context_strategy.rb +5 -10
  12. data/lib/samagotchi/reasoning_history_command.rb +29 -90
  13. data/lib/samagotchi/session.rb +22 -8
  14. data/lib/samagotchi/session_setting.rb +86 -0
  15. data/lib/samagotchi/thinking_command.rb +24 -76
  16. data/lib/samagotchi/thinking_notices.rb +169 -0
  17. data/lib/samagotchi/version.rb +1 -1
  18. data/lib/samagotchi/web/app.rb +55 -84
  19. data/lib/samagotchi/web/public/app.js +74 -505
  20. data/lib/samagotchi/web/public/bubbles.js +291 -0
  21. data/lib/samagotchi/web/public/cards_place.js +184 -0
  22. data/lib/samagotchi/web/public/chip_popover.js +111 -0
  23. data/lib/samagotchi/web/public/command_list.js +12 -10
  24. data/lib/samagotchi/web/public/index.html +15 -7
  25. data/lib/samagotchi/web/public/info_bar.js +3 -3
  26. data/lib/samagotchi/web/public/info_bar_model.js +110 -0
  27. data/lib/samagotchi/web/public/init_row.js +21 -10
  28. data/lib/samagotchi/web/public/level_chip.js +29 -80
  29. data/lib/samagotchi/web/public/lists_view.js +64 -9
  30. data/lib/samagotchi/web/public/llm_context_chip.js +36 -105
  31. data/lib/samagotchi/web/public/model_picker.js +26 -22
  32. data/lib/samagotchi/web/public/ref_scan.js +1 -7
  33. data/lib/samagotchi/web/public/refs.js +13 -0
  34. data/lib/samagotchi/web/public/stage_frame.js +179 -0
  35. data/lib/samagotchi/web/public/stage_model.js +33 -0
  36. data/lib/samagotchi/web/public/stage_slots.js +130 -0
  37. data/lib/samagotchi/web/public/stage_view.js +56 -335
  38. data/lib/samagotchi/web/public/stage_watch.js +65 -0
  39. data/lib/samagotchi/web/public/vendor/directive-helpers.js +8 -0
  40. data/lib/samagotchi/web/public/vendor/directives/repeat.js +9 -0
  41. data/lib/samagotchi/worker.rb +11 -16
  42. metadata +14 -1
@@ -0,0 +1,65 @@
1
+ // The stage view's in-use watch (stage_view.js): the stage is in use while
2
+ // the pointer is over it (tracked on the stage itself: :hover goes stale
3
+ // when children change), after a touch or wheel in the last 4 s (phones
4
+ // have no hover), with keyboard focus or a selection in it. While an ended
5
+ // turn waits for its hand-off it ticks every WATCH_MS: the stage wears
6
+ // `in-use`, and the stage's +onTick+ (stage_model.js handOffDue) says when
7
+ // the hand-off is due, with the quiet clock this watch keeps.
8
+ import { inUseFrom } from "./stage_model.js";
9
+
10
+ const WATCH_MS = 200;
11
+
12
+ // +watching()+: the stage still holds an ended turn (else a tick stops the
13
+ // watch). +onTick({ inUse, quietSinceMs, nowMs })+ returns { due,
14
+ // quietSinceMs }; +onDue()+ hands off.
15
+ export function createInUseWatch({ stage, watching, onTick, onDue }) {
16
+ let watchTimer = null;
17
+ let quietSince = null;
18
+ let pointerIn = false;
19
+ let lastTouch = 0;
20
+
21
+ stage.addEventListener("pointerenter", (e) => { if (e.pointerType === "mouse") pointerIn = true; });
22
+ stage.addEventListener("pointermove", (e) => { if (e.pointerType === "mouse") pointerIn = true; });
23
+ stage.addEventListener("pointerleave", () => { pointerIn = false; });
24
+ // Scrolling needs the pointer over it, a touch or keyboard focus; the
25
+ // stage's own scrolls (follow, the answer's top) are no use.
26
+ for (const type of ["touchstart", "touchmove", "wheel"]) {
27
+ stage.addEventListener(type, () => { lastTouch = Date.now(); }, { passive: true, capture: true });
28
+ }
29
+
30
+ function inUse(nowMs) {
31
+ const active = document.activeElement;
32
+ const sel = window.getSelection();
33
+ return inUseFrom({
34
+ pointerIn,
35
+ lastTouchMs: lastTouch,
36
+ // A clicked button keeps the focus in Chrome: only keyboard focus and
37
+ // a field being typed in count.
38
+ focusInside: !!active && stage.contains(active) && active.matches(":focus-visible"),
39
+ selectionInside: !!sel && !sel.isCollapsed && stage.contains(sel.anchorNode),
40
+ nowMs,
41
+ });
42
+ }
43
+
44
+ function stopWatch() {
45
+ clearInterval(watchTimer);
46
+ watchTimer = null;
47
+ quietSince = null;
48
+ stage.classList.remove("in-use");
49
+ }
50
+
51
+ function startWatch() {
52
+ stopWatch();
53
+ watchTimer = setInterval(() => {
54
+ if (!watching()) return stopWatch();
55
+ const nowMs = Date.now();
56
+ const busy = inUse(nowMs);
57
+ stage.classList.toggle("in-use", busy);
58
+ const r = onTick({ inUse: busy, quietSinceMs: quietSince, nowMs });
59
+ quietSince = r.quietSinceMs;
60
+ if (r.due) onDue();
61
+ }, WATCH_MS);
62
+ }
63
+
64
+ return { start: startWatch, stop: stopWatch };
65
+ }
@@ -0,0 +1,8 @@
1
+ // lit-html 3.3.3 (npm tarball lit-html-3.3.3.tgz, directive-helpers.js: the minified production build,
2
+ // unmodified but for this line and the dropped sourceMappingURL). BSD-3-Clause.
3
+ import{_$LH as o}from"./lit-html.js";
4
+ /**
5
+ * @license
6
+ * Copyright 2020 Google LLC
7
+ * SPDX-License-Identifier: BSD-3-Clause
8
+ */const{I:t}=o,i=o=>o,n=o=>null===o||"object"!=typeof o&&"function"!=typeof o,e={HTML:1,SVG:2,MATHML:3},l=(o,t)=>void 0===t?void 0!==o?._$litType$:o?._$litType$===t,d=o=>null!=o?._$litType$?.h,c=o=>void 0!==o?._$litDirective$,f=o=>o?._$litDirective$,r=o=>void 0===o.strings,s=()=>document.createComment(""),v=(o,n,e)=>{const l=o._$AA.parentNode,d=void 0===n?o._$AB:n._$AA;if(void 0===e){const i=l.insertBefore(s(),d),n=l.insertBefore(s(),d);e=new t(i,n,o,o.options)}else{const t=e._$AB.nextSibling,n=e._$AM,c=n!==o;if(c){let t;e._$AQ?.(o),e._$AM=o,void 0!==e._$AP&&(t=o._$AU)!==n._$AU&&e._$AP(t)}if(t!==d||c){let o=e._$AA;for(;o!==t;){const t=i(o).nextSibling;i(l).insertBefore(o,d),o=t}}}return e},u=(o,t,i=o)=>(o._$AI(t,i),o),m={},p=(o,t=m)=>o._$AH=t,M=o=>o._$AH,h=o=>{o._$AR(),o._$AA.remove()},j=o=>{o._$AR()};export{e as TemplateResultType,j as clearPart,M as getCommittedValue,f as getDirectiveClass,v as insertPart,d as isCompiledTemplateResult,c as isDirectiveResult,n as isPrimitive,r as isSingleExpression,l as isTemplateResult,h as removePart,u as setChildPartValue,p as setCommittedValue};
@@ -0,0 +1,9 @@
1
+ // lit-html 3.3.3 (npm tarball lit-html-3.3.3.tgz, directives/repeat.js: the minified production build,
2
+ // unmodified but for this line and the dropped sourceMappingURL). BSD-3-Clause.
3
+ import{noChange as e}from"../lit-html.js";import{directive as s,Directive as t,PartType as r}from"../directive.js";import{getCommittedValue as l,setChildPartValue as o,insertPart as i,removePart as n,setCommittedValue as f}from"../directive-helpers.js";
4
+ /**
5
+ * @license
6
+ * Copyright 2017 Google LLC
7
+ * SPDX-License-Identifier: BSD-3-Clause
8
+ */
9
+ const u=(e,s,t)=>{const r=new Map;for(let l=s;l<=t;l++)r.set(e[l],l);return r},c=s(class extends t{constructor(e){if(super(e),e.type!==r.CHILD)throw Error("repeat() can only be used in text expressions")}dt(e,s,t){let r;void 0===t?t=s:void 0!==s&&(r=s);const l=[],o=[];let i=0;for(const s of e)l[i]=r?r(s,i):i,o[i]=t(s,i),i++;return{values:o,keys:l}}render(e,s,t){return this.dt(e,s,t).values}update(s,[t,r,c]){const d=l(s),{values:p,keys:a}=this.dt(t,r,c);if(!Array.isArray(d))return this.ut=a,p;const h=this.ut??=[],v=[];let m,y,x=0,j=d.length-1,k=0,w=p.length-1;for(;x<=j&&k<=w;)if(null===d[x])x++;else if(null===d[j])j--;else if(h[x]===a[k])v[k]=o(d[x],p[k]),x++,k++;else if(h[j]===a[w])v[w]=o(d[j],p[w]),j--,w--;else if(h[x]===a[w])v[w]=o(d[x],p[w]),i(s,v[w+1],d[x]),x++,w--;else if(h[j]===a[k])v[k]=o(d[j],p[k]),i(s,d[x],d[j]),j--,k++;else if(void 0===m&&(m=u(a,k,w),y=u(h,x,j)),m.has(h[x]))if(m.has(h[j])){const e=y.get(a[k]),t=void 0!==e?d[e]:null;if(null===t){const e=i(s,d[x]);o(e,p[k]),v[k]=e}else v[k]=o(t,p[k]),i(s,d[x],t),d[e]=null;k++}else n(d[j]),j--;else n(d[x]),x++;for(;k<=w;){const e=i(s,v[w+1]);o(e,p[k]),v[k++]=e}for(;x<=j;){const e=d[x++];null!==e&&n(e)}return this.ut=a,f(s,v),e}});export{c as repeat};
@@ -22,6 +22,7 @@ require_relative "llm/errors"
22
22
  require_relative "continue_offer"
23
23
  require_relative "iteration_limit"
24
24
  require_relative "session_commands"
25
+ require_relative "session_setting"
25
26
  require_relative "queued_command"
26
27
  require_relative "model_profile"
27
28
  require_relative "child_reports"
@@ -153,9 +154,6 @@ module Samagotchi
153
154
  # The running turn has ended (its end event) and its after_turn hooks
154
155
  # run: a signal's grace waits for them (#signalled).
155
156
  @turn_ending = false
156
- # The worker's own saves and a signal's (#signal_grace_expired), one
157
- # at a time.
158
- @save_mutex = Mutex.new
159
157
  end
160
158
 
161
159
  # Whether the session was empty as the worker left it, so the caller
@@ -460,7 +458,7 @@ module Samagotchi
460
458
  return unless mark
461
459
 
462
460
  Log.info(:worker, "interrupted_turn_settled", turn_id: mark.id, iteration: mark.iteration, at: mark.at)
463
- save_or_log(:interrupted_turn) { @session.save(state_dir: @state_dir) }
461
+ save_or_log(:interrupted_turn) { save_session }
464
462
  end
465
463
 
466
464
  # A question saved by a worker that died while it waited (an
@@ -473,7 +471,7 @@ module Samagotchi
473
471
  return unless id
474
472
 
475
473
  Log.info(:worker, "dead_question_dropped", id: id)
476
- save_or_log(:dead_question) { @session.save(state_dir: @state_dir) }
474
+ save_or_log(:dead_question) { save_session }
477
475
  end
478
476
 
479
477
  # The attached context's notes (WorkerInbound#absorb_context), and the
@@ -873,15 +871,10 @@ module Samagotchi
873
871
  event[:anytime] = true if anytime
874
872
  # Its line was shown at its command_queued (waits: turn_end).
875
873
  event[:queued] = true if command.waits_for_turn_end?
876
- # /llm-context or /model: what the next turn runs under now (the web's chip).
877
- event[:llm_context] = @engine.llm_context_summary if changed.intersect?(%i[llm_context model])
878
- # /thinking or /model: the level the next turn runs at (the web's chip).
879
- event[:thinking] = @engine.thinking_explained&.summary if changed.intersect?(%i[thinking model])
880
- # /reasoning-history or /model: the level the next turn runs under
881
- # (the web's chip); nil on a native host, which ignores it.
882
- event[:reasoning_history] = @engine.reasoning_history_explained&.summary if changed.intersect?(%i[reasoning_history model])
883
- # /toolkit: what the next turn declares (the web's chip; nil on full).
884
- event[:toolkit] = @engine.toolkit_summary if changed.include?(:toolkit)
874
+ # The chips the command moved (SessionSetting#changed_by): what the next
875
+ # turn runs under now (/llm-context, /thinking, /reasoning-history,
876
+ # /toolkit, and /model for the model's).
877
+ SessionSetting::ALL.each { |setting| event[setting.key] = setting.summary(@engine) if setting.changed_by?(changed) }
885
878
  event[:confirm] = confirm.to_h if confirm
886
879
  event[:output_truncated] = true if text.length > COMMAND_OUTPUT_LIMIT
887
880
  @engine.announce(event)
@@ -910,7 +903,7 @@ module Samagotchi
910
903
  # the new parent beside it (Session::PARENT_FILE): this turn's
911
904
  # status, its rings and every save from here on say so.
912
905
  @session.parent_id = Session.parent_override(@session_id, state_dir: @state_dir) || @session.parent_id
913
- @session.save(state_dir: @state_dir)
906
+ save_session
914
907
  result = @engine.run_turn(@session, prompt, pending_input: pending_input_drain, **turn_args)
915
908
  rescue StandardError => e
916
909
  error = e
@@ -1238,8 +1231,10 @@ module Samagotchi
1238
1231
  # Save the session, a stopped one too: a stop is the marker file
1239
1232
  # (Session.mark_stopped), which every load reads over the saved status,
1240
1233
  # so this save can't hide it, and the turn the stop canceled is kept.
1234
+ # Session#save serializes it with every other save of @session (Bridge
1235
+ # threads, the turn's checkpoints, a signal's thread).
1241
1236
  def save_session
1242
- @save_mutex.synchronize { @session.save(state_dir: @state_dir) }
1237
+ @session.save(state_dir: @state_dir)
1243
1238
  end
1244
1239
 
1245
1240
  def signalled? = !@signals.signal.nil?
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: samagotchi
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.67.0
4
+ version: 0.68.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dmitry Dedov
@@ -275,6 +275,7 @@ files:
275
275
  - lib/samagotchi/desktop/macos/Tmux.swift
276
276
  - lib/samagotchi/desktop_command.rb
277
277
  - lib/samagotchi/edit_preview.rb
278
+ - lib/samagotchi/effective_model.rb
278
279
  - lib/samagotchi/empty_answer_retry.rb
279
280
  - lib/samagotchi/engine.rb
280
281
  - lib/samagotchi/engine_peers.rb
@@ -330,6 +331,7 @@ files:
330
331
  - lib/samagotchi/kernel_loop.rb
331
332
  - lib/samagotchi/last_turn.rb
332
333
  - lib/samagotchi/launch_mode.rb
334
+ - lib/samagotchi/level_setting_command.rb
333
335
  - lib/samagotchi/live_versions.rb
334
336
  - lib/samagotchi/llm/adapter_common.rb
335
337
  - lib/samagotchi/llm/adapters.rb
@@ -459,6 +461,7 @@ files:
459
461
  - lib/samagotchi/session_metrics.rb
460
462
  - lib/samagotchi/session_observer.rb
461
463
  - lib/samagotchi/session_retention.rb
464
+ - lib/samagotchi/session_setting.rb
462
465
  - lib/samagotchi/session_setup.rb
463
466
  - lib/samagotchi/sessions_command.rb
464
467
  - lib/samagotchi/setting_explained.rb
@@ -492,6 +495,7 @@ files:
492
495
  - lib/samagotchi/text_diff.rb
493
496
  - lib/samagotchi/thinking.rb
494
497
  - lib/samagotchi/thinking_command.rb
498
+ - lib/samagotchi/thinking_notices.rb
495
499
  - lib/samagotchi/thinking_tails.rb
496
500
  - lib/samagotchi/thinking_ticker.rb
497
501
  - lib/samagotchi/thought_stream_splitter.rb
@@ -569,8 +573,11 @@ files:
569
573
  - lib/samagotchi/web/public/annotations.js
570
574
  - lib/samagotchi/web/public/answer_refs.js
571
575
  - lib/samagotchi/web/public/app.js
576
+ - lib/samagotchi/web/public/bubbles.js
572
577
  - lib/samagotchi/web/public/card.js
578
+ - lib/samagotchi/web/public/cards_place.js
573
579
  - lib/samagotchi/web/public/chains.js
580
+ - lib/samagotchi/web/public/chip_popover.js
574
581
  - lib/samagotchi/web/public/chunk_router.js
575
582
  - lib/samagotchi/web/public/command_complete.js
576
583
  - lib/samagotchi/web/public/command_list.js
@@ -591,6 +598,7 @@ files:
591
598
  - lib/samagotchi/web/public/images.js
592
599
  - lib/samagotchi/web/public/index.html
593
600
  - lib/samagotchi/web/public/info_bar.js
601
+ - lib/samagotchi/web/public/info_bar_model.js
594
602
  - lib/samagotchi/web/public/init_row.js
595
603
  - lib/samagotchi/web/public/keep_focus.js
596
604
  - lib/samagotchi/web/public/kept_commands.js
@@ -620,8 +628,11 @@ files:
620
628
  - lib/samagotchi/web/public/session_title.js
621
629
  - lib/samagotchi/web/public/sessions_list.js
622
630
  - lib/samagotchi/web/public/shown_texts.js
631
+ - lib/samagotchi/web/public/stage_frame.js
623
632
  - lib/samagotchi/web/public/stage_model.js
633
+ - lib/samagotchi/web/public/stage_slots.js
624
634
  - lib/samagotchi/web/public/stage_view.js
635
+ - lib/samagotchi/web/public/stage_watch.js
625
636
  - lib/samagotchi/web/public/stream_handlers.js
626
637
  - lib/samagotchi/web/public/strip.js
627
638
  - lib/samagotchi/web/public/tally.js
@@ -635,7 +646,9 @@ files:
635
646
  - lib/samagotchi/web/public/turn_model.js
636
647
  - lib/samagotchi/web/public/turn_view.js
637
648
  - lib/samagotchi/web/public/update_notice.js
649
+ - lib/samagotchi/web/public/vendor/directive-helpers.js
638
650
  - lib/samagotchi/web/public/vendor/directive.js
651
+ - lib/samagotchi/web/public/vendor/directives/repeat.js
639
652
  - lib/samagotchi/web/public/vendor/directives/unsafe-html.js
640
653
  - lib/samagotchi/web/public/vendor/lit-html.js
641
654
  - lib/samagotchi/web/qr.rb