samagotchi 0.154.1 → 0.156.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (185) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +29 -1
  3. data/bin/chi +1 -1
  4. data/docs/architecture.md +12 -7
  5. data/docs/bundles.md +21 -0
  6. data/docs/cli.md +1 -1
  7. data/docs/guardrails.md +2 -2
  8. data/docs/hooks.md +1 -1
  9. data/docs/internals/anthropic.md +5 -5
  10. data/docs/internals/attached-context.md +9 -6
  11. data/docs/internals/background-tasks.md +1 -1
  12. data/docs/internals/block-renderers.md +8 -1
  13. data/docs/internals/engine.md +642 -831
  14. data/docs/internals/inline-widgets.md +136 -0
  15. data/docs/internals/llm-context-forget.md +8 -3
  16. data/docs/internals/objectives.md +8 -6
  17. data/docs/internals/participants.md +5 -5
  18. data/docs/internals/prompt-caching.md +13 -6
  19. data/docs/internals/remote-sessions.md +3 -1
  20. data/docs/internals/web-frontend.md +1 -1
  21. data/docs/internals/working-set.md +2 -1
  22. data/docs/plugins.md +2 -0
  23. data/docs/releasing.md +1 -1
  24. data/docs/sessions.md +4 -4
  25. data/docs/system-one.md +3 -2
  26. data/docs/testing.md +1 -1
  27. data/lib/samagotchi/block_renderers.rb +5 -0
  28. data/lib/samagotchi/bootstrap/config_writer.rb +1 -1
  29. data/lib/samagotchi/broadcast_command.rb +3 -3
  30. data/lib/samagotchi/bundle_command/check.rb +1 -1
  31. data/lib/samagotchi/bundle_command/try/sandbox.rb +1 -1
  32. data/lib/samagotchi/bundles/dev/manifest.yml +3 -2
  33. data/lib/samagotchi/bundles/inline-widgets/manifest.yml +11 -0
  34. data/lib/samagotchi/bundles/inline-widgets/plugin.rb +76 -0
  35. data/lib/samagotchi/bundles/system/config_modification_protocol.md +2 -2
  36. data/lib/samagotchi/bundles/system/manifest.yml +2 -2
  37. data/lib/samagotchi/child_move.rb +7 -51
  38. data/lib/samagotchi/children_status.rb +1 -1
  39. data/lib/samagotchi/cli/parent_wait.rb +1 -1
  40. data/lib/samagotchi/config.rb +17 -112
  41. data/lib/samagotchi/context_command.rb +1 -2
  42. data/lib/samagotchi/context_window.rb +3 -3
  43. data/lib/samagotchi/desktop/macos.rb +1 -1
  44. data/lib/samagotchi/engine/context_judge.rb +21 -119
  45. data/lib/samagotchi/engine/guardrails.rb +4 -2
  46. data/lib/samagotchi/engine/messages.rb +9 -6
  47. data/lib/samagotchi/engine/models.rb +5 -2
  48. data/lib/samagotchi/engine/objectives.rb +30 -80
  49. data/lib/samagotchi/engine/participants.rb +15 -10
  50. data/lib/samagotchi/engine/plugins.rb +3 -1
  51. data/lib/samagotchi/engine/questions.rb +1 -1
  52. data/lib/samagotchi/engine/side_requests.rb +26 -13
  53. data/lib/samagotchi/engine/toolkit.rb +35 -191
  54. data/lib/samagotchi/engine/turn_end.rb +1 -1
  55. data/lib/samagotchi/engine/turn_helpers.rb +16 -39
  56. data/lib/samagotchi/engine/verify.rb +7 -143
  57. data/lib/samagotchi/engine.rb +166 -98
  58. data/lib/samagotchi/engine_peers.rb +1 -1
  59. data/lib/samagotchi/event_fanout.rb +18 -12
  60. data/lib/samagotchi/guardrail_wiring.rb +83 -82
  61. data/lib/samagotchi/guardrails/gate.rb +41 -40
  62. data/lib/samagotchi/guardrails/pair_boundary.rb +2 -1
  63. data/lib/samagotchi/guardrails/review_boundary.rb +2 -1
  64. data/lib/samagotchi/guardrails/targets.rb +28 -11
  65. data/lib/samagotchi/guardrails_command.rb +1 -1
  66. data/lib/samagotchi/host_config.rb +72 -1
  67. data/lib/samagotchi/host_model.rb +2 -6
  68. data/lib/samagotchi/host_registry.rb +1 -1
  69. data/lib/samagotchi/inline_widgets.rb +325 -0
  70. data/lib/samagotchi/kernel_loop.rb +215 -313
  71. data/lib/samagotchi/llm/anthropic_wire.rb +2 -2
  72. data/lib/samagotchi/llm/backend.rb +3 -1
  73. data/lib/samagotchi/llm/chat_loop.rb +87 -49
  74. data/lib/samagotchi/llm/native_backend.rb +3 -2
  75. data/lib/samagotchi/llm_context_apply.rb +54 -1
  76. data/lib/samagotchi/llm_context_forget.rb +5 -3
  77. data/lib/samagotchi/llm_context_notice.rb +1 -1
  78. data/lib/samagotchi/llm_context_strategy.rb +7 -9
  79. data/lib/samagotchi/llm_context_view.rb +9 -0
  80. data/lib/samagotchi/model_binding.rb +3 -3
  81. data/lib/samagotchi/model_price.rb +4 -10
  82. data/lib/samagotchi/model_profile.rb +6 -6
  83. data/lib/samagotchi/model_settings.rb +37 -2
  84. data/lib/samagotchi/note_command.rb +1 -2
  85. data/lib/samagotchi/objectives_audit.rb +4 -3
  86. data/lib/samagotchi/participants.rb +2 -2
  87. data/lib/samagotchi/plugin/context.rb +1 -1
  88. data/lib/samagotchi/plugin/prompt_sections.rb +7 -0
  89. data/lib/samagotchi/plugin/sessions.rb +2 -5
  90. data/lib/samagotchi/plugin/tool_spec.rb +5 -3
  91. data/lib/samagotchi/project_env.rb +1 -1
  92. data/lib/samagotchi/question_desk.rb +1 -1
  93. data/lib/samagotchi/reasoning_history.rb +3 -3
  94. data/lib/samagotchi/reminder_carry.rb +1 -1
  95. data/lib/samagotchi/reprefill_meter.rb +45 -0
  96. data/lib/samagotchi/review_command.rb +1 -1
  97. data/lib/samagotchi/revise_anchor.rb +1 -1
  98. data/lib/samagotchi/sampling_settings.rb +3 -3
  99. data/lib/samagotchi/self_report.rb +7 -7
  100. data/lib/samagotchi/session.rb +50 -7
  101. data/lib/samagotchi/session_access/local.rb +7 -5
  102. data/lib/samagotchi/session_access/remote.rb +17 -3
  103. data/lib/samagotchi/session_archive_command.rb +2 -2
  104. data/lib/samagotchi/session_chain.rb +7 -6
  105. data/lib/samagotchi/session_continue.rb +6 -5
  106. data/lib/samagotchi/session_delete_command.rb +1 -1
  107. data/lib/samagotchi/session_manager/delivery.rb +254 -0
  108. data/lib/samagotchi/session_manager/emptiness.rb +138 -0
  109. data/lib/samagotchi/session_manager/lifecycle.rb +274 -0
  110. data/lib/samagotchi/session_manager/listing.rb +189 -0
  111. data/lib/samagotchi/session_manager/removal.rb +190 -0
  112. data/lib/samagotchi/session_manager/spawn.rb +242 -0
  113. data/lib/samagotchi/session_manager/worker_command.rb +157 -0
  114. data/lib/samagotchi/session_manager.rb +26 -1540
  115. data/lib/samagotchi/session_metrics.rb +1 -1
  116. data/lib/samagotchi/sessions_command.rb +1 -1
  117. data/lib/samagotchi/share_command.rb +1 -1
  118. data/lib/samagotchi/starting_marker.rb +65 -0
  119. data/lib/samagotchi/steer_cut_after.rb +3 -3
  120. data/lib/samagotchi/system_one/recorder.rb +49 -0
  121. data/lib/samagotchi/system_prompt.rb +37 -30
  122. data/lib/samagotchi/terminal_ui/exit_lines.rb +1 -1
  123. data/lib/samagotchi/terminal_ui.rb +2 -6
  124. data/lib/samagotchi/testing/boundary.rb +7 -0
  125. data/lib/samagotchi/testing/bundle.rb +7 -5
  126. data/lib/samagotchi/testing/install.rb +3 -2
  127. data/lib/samagotchi/testing/sessions.rb +1 -1
  128. data/lib/samagotchi/thinking.rb +3 -3
  129. data/lib/samagotchi/token_usage.rb +1 -1
  130. data/lib/samagotchi/tool_activity.rb +15 -7
  131. data/lib/samagotchi/tool_declarations.rb +6 -6
  132. data/lib/samagotchi/tool_output_cut.rb +17 -0
  133. data/lib/samagotchi/tool_response.rb +4 -3
  134. data/lib/samagotchi/tool_runner.rb +96 -102
  135. data/lib/samagotchi/toolkit_binding.rb +40 -14
  136. data/lib/samagotchi/toolkit_command.rb +1 -1
  137. data/lib/samagotchi/tools/deferred_tools.rb +17 -21
  138. data/lib/samagotchi/tools/delegate.rb +10 -5
  139. data/lib/samagotchi/tools/delegate_result.rb +4 -4
  140. data/lib/samagotchi/tools/index_hint.rb +14 -0
  141. data/lib/samagotchi/tools/registry.rb +64 -44
  142. data/lib/samagotchi/tools/send_note.rb +4 -6
  143. data/lib/samagotchi/tools/tool_index.rb +150 -102
  144. data/lib/samagotchi/tools/tool_surface.rb +187 -0
  145. data/lib/samagotchi/turn_context.rb +68 -0
  146. data/lib/samagotchi/turn_stages/context_judge.rb +172 -0
  147. data/lib/samagotchi/turn_stages/objectives.rb +150 -0
  148. data/lib/samagotchi/turn_stages/toolkit_suggestion.rb +257 -0
  149. data/lib/samagotchi/turn_stages/verify_anchors.rb +168 -0
  150. data/lib/samagotchi/turn_stages/warmup.rb +82 -0
  151. data/lib/samagotchi/turn_state.rb +46 -4
  152. data/lib/samagotchi/version.rb +1 -1
  153. data/lib/samagotchi/vision_support.rb +3 -3
  154. data/lib/samagotchi/web/app.rb +15 -8
  155. data/lib/samagotchi/web/markdown_renderer.rb +39 -14
  156. data/lib/samagotchi/web/message_display.rb +1 -1
  157. data/lib/samagotchi/web/participant_access.rb +2 -2
  158. data/lib/samagotchi/web/public/app.js +5 -1
  159. data/lib/samagotchi/web/public/block_host.js +74 -199
  160. data/lib/samagotchi/web/public/block_renderers.css +2 -0
  161. data/lib/samagotchi/web/public/block_source.js +7 -4
  162. data/lib/samagotchi/web/public/block_watch.js +256 -0
  163. data/lib/samagotchi/web/public/composer_fold.js +3 -0
  164. data/lib/samagotchi/web/public/index.html +28 -9
  165. data/lib/samagotchi/web/public/inline_widgets.js +146 -0
  166. data/lib/samagotchi/web/public/owner_verify.js +1 -1
  167. data/lib/samagotchi/web/public/participant.js +1 -1
  168. data/lib/samagotchi/web/public/revise_stack.js +1 -1
  169. data/lib/samagotchi/web/public/stage_watch.js +6 -2
  170. data/lib/samagotchi/web/public/text_roots.js +1 -1
  171. data/lib/samagotchi/web/public/verify_target.js +1 -1
  172. data/lib/samagotchi/web/public/widget_picks.js +130 -0
  173. data/lib/samagotchi/web/public/widget_walk.js +230 -0
  174. data/lib/samagotchi/web/public/widgets.css +70 -0
  175. data/lib/samagotchi/web/session_access_routes.rb +3 -3
  176. data/lib/samagotchi/web/session_control.rb +3 -3
  177. data/lib/samagotchi/web/session_create.rb +3 -3
  178. data/lib/samagotchi/web/session_hub.rb +1 -1
  179. data/lib/samagotchi/web/session_show.rb +3 -3
  180. data/lib/samagotchi/web/session_summary.rb +3 -4
  181. data/lib/samagotchi/worker.rb +55 -27
  182. data/lib/samagotchi/worker_boot.rb +184 -0
  183. data/lib/samagotchi/worker_signals.rb +1 -1
  184. data/lib/samagotchi/worker_task_wakes.rb +2 -2
  185. metadata +29 -1
@@ -5,8 +5,9 @@ module Samagotchi
5
5
  # What a turn's steps use before and around the model: its settings,
6
6
  # images and vision, the model ref and resumed run start it generates
7
7
  # with, the used memories it publishes, and the turn-end warm-up of the
8
- # next one. Writes @next_turn_waiting; reads @model_settings, @kernel,
9
- # @prompt_warmup, @thinking_notices, @turn_state.
8
+ # next one (TurnStages::Warmup, built here). Writes @next_turn_waiting;
9
+ # reads @model_settings, @kernel, @prompt_warmup, @thinking_notices,
10
+ # @turn_state, @reminder_queue, @turn_warmup.
10
11
  module TurnHelpersPart
11
12
  # The turn's settings for the kernel (LLM::TurnSettings): vision,
12
13
  # sampling and thinking, the thinking resolved before the hooks run.
@@ -34,44 +35,20 @@ module Samagotchi
34
35
  # warm-up then. nil: neither.
35
36
  attr_accessor :next_turn_waiting
36
37
 
37
- # After a completed turn, prefill the next turn's prompt up to its user
38
- # message while the user reads (PromptWarmup, cache.warmup). Only on a
39
- # local llama.cpp host on the native loop, and not when the next turn's
40
- # start differs anyway or starts at once: a reminder due, a continue
41
- # offer (the turn ran out of steps), a carried steer or queued input.
42
- # Never fails the turn.
43
- def warm_up_next_turn(turn, result)
44
- return if result.canceled? || result.resumable?
45
-
46
- model = effective_model
47
- client = model.client
48
- return unless warmup_target?(model, client)
49
- return if reminders_due? || @turn_state.carried_steers? || @next_turn_waiting&.call
50
-
51
- messages = ContextNote.with_system_head(turn.session.messages.dup, { role: "system", content: system_prompt(model) })
52
- # Under the next turn's strategy (a /model switch may have changed it);
53
- # the last turn's when it can't be resolved.
54
- prompt, images = @kernel.warmup_prompt(messages, llm_context: @model_settings.turn_llm_context || @kernel.turn_settings&.llm_context)
55
- return unless prompt
56
-
57
- started = @prompt_warmup.start(client: client, prompt: prompt, model: @kernel.turn_settings.model_name,
58
- slot: @kernel.last_slot, images: images)
59
- @kernel.warmed_up! if started
60
- rescue StandardError => e
61
- Log.warn(:model, "warmup_skipped", error: e.class.name, msg: e.message.to_s[0, 200])
62
- end
63
- private :warm_up_next_turn
64
-
65
- # Never a paid or remote host (cache.warmup auto means local only), nor
66
- # the chat loop (Splash keeps its own cache; llama.cpp's chat path is
67
- # not measured), nor a client that can't warm up (a spec's stub).
68
- def warmup_target?(model, client)
69
- return false if model.chat? || model.entry.remote?
70
- return false unless client.respond_to?(:warm_up)
71
-
72
- PromptWarmup.enabled?
38
+ # The turn-end warm-up's stage (TurnStages::Warmup).
39
+ attr_reader :turn_warmup
40
+ private :turn_warmup
41
+
42
+ # The stage over the kernel and the Engine's PromptWarmup (built in
43
+ # #initialize, once the kernel and the reminder queue are). Its one
44
+ # callable is the system prompt, built late (side effects); the
45
+ # host's probe goes with each call (#next_turn_waiting, set after).
46
+ def build_turn_warmup
47
+ TurnStages::Warmup.new(prompt_warmup: @prompt_warmup, kernel: @kernel, turn_state: @turn_state,
48
+ model_settings: @model_settings, reminder_queue: @reminder_queue,
49
+ system_prompt: ->(model) { system_prompt(model) })
73
50
  end
74
- private :warmup_target?
51
+ private :build_turn_warmup
75
52
 
76
53
  # The ref (host:model, as asked) a turn's generations ran on: the model
77
54
  # #generate resolved, after the before_turn hooks (which may switch it).
@@ -2,152 +2,16 @@
2
2
 
3
3
  module Samagotchi
4
4
  class Engine
5
- # Verify and Revise anchors at a turn's end: the opening's stamp, a Revise
6
- # turn's draft checked, a Verify turn's quote checked against its source
7
- # session and its verdict recorded. No ivars of its own: it reads the turn,
8
- # and the sessions it loads through Engine methods.
5
+ # Verify and Revise anchors (TurnStages::VerifyAnchors): #begin_turn
6
+ # checks a Verify turn's claim, #end_turn's event step stamps the opening
7
+ # and records the verdict. Reads @verify_anchors.
9
8
  module VerifyPart
10
- # The turn's anchors, stamped on its opening message (the prompt, or a
11
- # wake turn's note) in the messages it keeps: display metadata, never
12
- # in the prompt (LLM::ChatLoop#plain keeps them, no wire sends them).
13
- # A Verify turn's claim however it ended; a Revise turn's draft only
14
- # once it completed with an answer (#revision_target). Returns the
15
- # stamped ReviseAnchor (the end event's revises), or nil.
16
- def stamp_opening(messages, turn, outcome)
17
- return unless messages.is_a?(Array)
9
+ private
18
10
 
19
- revises = revision_target(messages, turn, outcome)
20
- fields = { verify: turn.verify&.to_h, revises: revises&.to_h }.compact
21
- return if fields.empty?
11
+ # The anchors' stage (TurnStages::VerifyAnchors).
12
+ attr_reader :verify_anchors
22
13
 
23
- opening = messages.reverse.find do |message|
24
- Steer.turn_prompt?(message) && (message[:turn_id] || message["turn_id"]).to_s == turn.id
25
- end
26
- return unless opening
27
-
28
- opening.merge!(fields)
29
- revises
30
- end
31
- private :stamp_opening
32
-
33
- # The turn a Revise turn revised (D6: "this turn revised that one"):
34
- # only a completed turn with an answer (AnswerTail) has revised
35
- # anything. A draft no prompt in the messages carries is no target (a
36
- # stale page, a rolled-back turn); one a stamped turn already revised
37
- # is re-targeted to its stack's top, the newest version, which the
38
- # person meant ("this draft").
39
- def revision_target(messages, turn, outcome)
40
- return unless turn.revises && outcome == "completed"
41
-
42
- slice = AnswerTail.turn_slice(messages, turn.id)
43
- return unless slice&.any? { |message| AnswerTail.answer?(message) }
44
-
45
- target = turn.revises.turn_id
46
- seen = [turn.id]
47
- until seen.include?(target)
48
- return reject_revise_anchor(turn.revises, :turn_missing) unless AnswerTail.turn_slice(messages, target)
49
-
50
- seen << target
51
- newer = messages.reverse.find do |message|
52
- Steer.turn_prompt?(message) && ReviseAnchor.from(message[:revises] || message["revises"])&.turn_id == target
53
- end
54
- return ReviseAnchor.new(turn_id: target) unless newer
55
-
56
- target = (newer[:turn_id] || newer["turn_id"]).to_s
57
- end
58
- reject_revise_anchor(turn.revises, :cycle)
59
- end
60
- private :revision_target
61
-
62
- def reject_revise_anchor(anchor, reason)
63
- Log.warn(:turn, "revise_anchor_rejected", turn_id: anchor.turn_id, reason:)
64
- nil
65
- end
66
- private :reject_revise_anchor
67
-
68
- def verified_anchor(session, anchor)
69
- return unless anchor
70
-
71
- source = verify_anchor_source_session(session, anchor)
72
- return unless source
73
-
74
- turn = AnswerTail.turn_slice(Array(source.messages), anchor.turn_id)
75
- return reject_verify_anchor(anchor, :turn_missing) unless turn
76
-
77
- reply = turn.reverse.find { |message| AnswerTail.answer?(message) }
78
- return reject_verify_anchor(anchor, :reply_missing) unless reply
79
-
80
- quote_text = verify_comparison_text(anchor.quote)
81
- quoted = !quote_text.empty? && verify_quote_in?(quote_text, (reply[:content] || reply["content"]).to_s, source)
82
- return reject_verify_anchor(anchor, :quote_missing) unless quoted
83
-
84
- anchor
85
- end
86
- private :verified_anchor
87
-
88
- # Whether +quote_text+ is in +answer+ as the model wrote it, or as the
89
- # pages show it: a page quotes its own text, which reads the session's
90
- # folder relative, the home folder as ~ and a secret shape as
91
- # [redacted] (a participant's page gets it so, Redact;
92
- # the owner's page rewrites its quote the same way, claim_link.js
93
- # normalizeClaim, so claim links match both pages). +source+ is the
94
- # session whose folder that is.
95
- def verify_quote_in?(quote_text, answer, source)
96
- return true if verify_comparison_text(answer).include?(quote_text)
97
-
98
- viewer = Redact::Viewer.new(cwd: source.working_directory)
99
- verify_comparison_text(Redact.text(answer, viewer)).include?(quote_text)
100
- end
101
- private :verify_quote_in?
102
-
103
- def verify_anchor_source_session(session, anchor)
104
- return session unless session.verify_fresh
105
-
106
- fresh = session.verify_fresh
107
- return reject_verify_anchor(anchor, :fresh_anchor_mismatch) unless fresh.anchor == anchor
108
- return reject_verify_anchor(anchor, :fresh_parent_missing) unless session.parent_id
109
-
110
- Session.load(session.parent_id, state_dir: session_state_dir)
111
- rescue ArgumentError, SystemCallError, IOError => e
112
- Log.warn(:turn, "verify_anchor_rejected", turn_id: anchor.turn_id, reason: :source_session_unavailable,
113
- error: e.class.name)
114
- nil
115
- end
116
- private :verify_anchor_source_session
117
-
118
- def verify_comparison_text(text)
119
- OutputFormatter.strip_markup(text)
120
- .gsub(/!\[([^\]]*)\]\([^)]+\)/, '\1')
121
- .gsub(/\[([^\]]+)\]\([^)]+\)/, '\1')
122
- .gsub(/^[ \t]*(?:\#{1,6}[ \t]+|>[ \t]?|[-+*][ \t]+|\d+[.)][ \t]+)/, "")
123
- .gsub(/(\*\*|__|~~|`+)(.+?)\1/m, '\2')
124
- .gsub(/(?<!\w)\*(\S(?:.*?\S)?)\*(?!\w)/m, '\1')
125
- .gsub(/(?<!\w)_(\S(?:.*?\S)?)_(?!\w)/m, '\1')
126
- .tr("|", " ") # a table row's cells; the page copies them without the pipes
127
- .gsub(/\s+/, " ")
128
- .strip
129
- end
130
- private :verify_comparison_text
131
-
132
- def reject_verify_anchor(anchor, reason)
133
- Log.warn(:turn, "verify_anchor_rejected", turn_id: anchor.turn_id, reason:)
134
- nil
135
- end
136
- private :reject_verify_anchor
137
-
138
- def record_verdict(turn, outcome)
139
- return unless outcome == "completed" && turn.verify
140
-
141
- answer = AnswerTail.find(turn.session.messages, turn_id: turn.id)
142
- parsed = Verdict.parse(answer && (answer[:content] || answer["content"]))
143
- return unless parsed
144
-
145
- record = { anchor: turn.verify.to_h, verdict: parsed.verdict, reason: parsed.reason,
146
- by: turn.origin.author, check_turn_id: turn.id, at: Time.now.iso8601(3) }
147
- turn.session.verdicts = turn.session.verdicts + [record]
148
- record
149
- end
150
- private :record_verdict
14
+ def build_verify_anchors = TurnStages::VerifyAnchors.new
151
15
  end
152
16
  end
153
17
  end