samagotchi 0.91.0 → 0.93.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 +88 -1
- data/README.md +5 -2
- data/bin/chi +8 -8
- data/docs/architecture.md +20 -16
- data/docs/bundle-authoring.md +2 -1
- data/docs/cli.md +5 -5
- data/docs/configuration.md +3 -1
- data/docs/context.md +5 -3
- data/docs/guardrails.md +4 -5
- data/docs/hooks.md +3 -3
- data/docs/internals/background-tasks.md +2 -2
- data/docs/internals/bundles.md +4 -4
- data/docs/internals/engine.md +27 -8
- data/docs/internals/tool-guardrails.md +10 -2
- data/docs/memory.md +6 -0
- data/docs/plugins.md +30 -13
- data/docs/releasing.md +3 -0
- data/docs/sessions.md +4 -4
- data/docs/testing.md +2 -1
- data/lib/samagotchi/bootstrap/probe.rb +2 -2
- data/lib/samagotchi/bridge.rb +8 -9
- data/lib/samagotchi/bundle_command/check.rb +43 -12
- data/lib/samagotchi/bundle_command/scaffold.rb +12 -0
- data/lib/samagotchi/bundle_command/test_run.rb +12 -0
- data/lib/samagotchi/bundle_command/try/command.rb +164 -0
- data/lib/samagotchi/bundle_command/try/render.rb +80 -0
- data/lib/samagotchi/bundle_command/try/run.rb +35 -17
- data/lib/samagotchi/bundle_command/try/sandbox.rb +113 -34
- data/lib/samagotchi/bundle_command/try/trace.rb +20 -26
- data/lib/samagotchi/bundle_command.rb +11 -213
- data/lib/samagotchi/bundle_session_settings.rb +82 -45
- data/lib/samagotchi/bundles/core/manifest.yml +2 -2
- data/lib/samagotchi/bundles/cost-cap/manifest.yml +6 -5
- data/lib/samagotchi/bundles/cost-cap/plugin.rb +57 -12
- data/lib/samagotchi/bundles/system/manifest.yml +1 -1
- data/lib/samagotchi/child_env.rb +50 -0
- data/lib/samagotchi/child_reports.rb +12 -14
- data/lib/samagotchi/client_id.rb +18 -0
- data/lib/samagotchi/config/restart_watch.rb +112 -0
- data/lib/samagotchi/config.rb +18 -59
- data/lib/samagotchi/engine.rb +26 -26
- data/lib/samagotchi/guardrails/data_readers.rb +34 -30
- data/lib/samagotchi/guardrails/parent_levels.rb +31 -0
- data/lib/samagotchi/guardrails/parent_policy.rb +9 -20
- data/lib/samagotchi/guardrails/shell_lex.rb +28 -7
- data/lib/samagotchi/hook_question.rb +21 -0
- data/lib/samagotchi/hook_routes.rb +6 -6
- data/lib/samagotchi/hooks/registry.rb +7 -5
- data/lib/samagotchi/host_registry.rb +1 -1
- data/lib/samagotchi/kernel_loop.rb +14 -3
- data/lib/samagotchi/llm/anthropic_messages.rb +5 -0
- data/lib/samagotchi/llm/chat_loop.rb +3 -1
- data/lib/samagotchi/llm/errors.rb +4 -4
- data/lib/samagotchi/memory_bundle/builder.rb +3 -2
- data/lib/samagotchi/memory_bundle/installed_bundle.rb +7 -2
- data/lib/samagotchi/memory_bundle/installer.rb +1 -0
- data/lib/samagotchi/memory_bundle/manifest.rb +42 -8
- data/lib/samagotchi/memory_bundle/provenance.rb +2 -1
- data/lib/samagotchi/parent_answers_command.rb +6 -6
- data/lib/samagotchi/parent_report.rb +12 -0
- data/lib/samagotchi/plugin/context.rb +6 -5
- data/lib/samagotchi/plugin/http_transport.rb +14 -3
- data/lib/samagotchi/plugin/sessions.rb +2 -3
- data/lib/samagotchi/question_desk.rb +12 -9
- data/lib/samagotchi/reply_wait/poll.rb +267 -0
- data/lib/samagotchi/reply_wait.rb +51 -190
- data/lib/samagotchi/sandbox_layout.rb +66 -0
- data/lib/samagotchi/send_command/parent_gate.rb +83 -0
- data/lib/samagotchi/send_command/wait_target.rb +55 -0
- data/lib/samagotchi/send_command.rb +34 -103
- data/lib/samagotchi/session.rb +10 -9
- data/lib/samagotchi/session_inbox.rb +31 -8
- data/lib/samagotchi/session_manager.rb +60 -35
- data/lib/samagotchi/session_metrics.rb +22 -3
- data/lib/samagotchi/sessions_command.rb +4 -4
- data/lib/samagotchi/task_watch.rb +64 -21
- data/lib/samagotchi/terminal_ui/attached_loop.rb +3 -3
- data/lib/samagotchi/terminal_ui/formatting.rb +8 -5
- data/lib/samagotchi/testing/bundle.rb +33 -20
- data/lib/samagotchi/testing/host.rb +2 -8
- data/lib/samagotchi/testing/install.rb +26 -17
- data/lib/samagotchi/testing/recorder.rb +6 -9
- data/lib/samagotchi/testing/sandbox.rb +45 -37
- data/lib/samagotchi/testing/waiting.rb +5 -7
- data/lib/samagotchi/tool_response.rb +28 -6
- data/lib/samagotchi/tools/delegate.rb +10 -10
- data/lib/samagotchi/tools/delegate_cursor.rb +32 -8
- data/lib/samagotchi/tools/delegate_relay.rb +31 -16
- data/lib/samagotchi/tools/delegate_wait.rb +4 -4
- data/lib/samagotchi/tools/task_runtime.rb +2 -2
- data/lib/samagotchi/turn_checkpoint.rb +23 -10
- data/lib/samagotchi/version.rb +1 -1
- data/lib/samagotchi/web/app.rb +46 -63
- data/lib/samagotchi/web/public/app.js +130 -554
- data/lib/samagotchi/web/public/cards_place.js +4 -1
- data/lib/samagotchi/web/public/images.js +6 -0
- data/lib/samagotchi/web/public/index.html +1 -1
- data/lib/samagotchi/web/public/model_pick.js +10 -0
- data/lib/samagotchi/web/public/send_turn.js +173 -0
- data/lib/samagotchi/web/public/session_actions.js +203 -0
- data/lib/samagotchi/web/public/start_page.js +236 -0
- data/lib/samagotchi/web/public/toasts.js +17 -9
- data/lib/samagotchi/web/public/unqueue.js +20 -4
- data/lib/samagotchi/worker.rb +77 -185
- data/lib/samagotchi/worker_idle_exit.rb +20 -5
- data/lib/samagotchi/worker_inbound.rb +5 -5
- data/lib/samagotchi/worker_task_wakes.rb +160 -0
- data/lib/samagotchi/worker_wakes.rb +0 -3
- metadata +15 -1
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "securerandom"
|
|
4
|
+
|
|
5
|
+
require_relative "child_reports"
|
|
6
|
+
require_relative "kernel_loop"
|
|
7
|
+
require_relative "log"
|
|
8
|
+
require_relative "task_finish_note"
|
|
9
|
+
require_relative "task_watch"
|
|
10
|
+
require_relative "tools/task_runtime"
|
|
11
|
+
require_relative "worker_inbound"
|
|
12
|
+
require_relative "worker_wakes"
|
|
13
|
+
|
|
14
|
+
module Samagotchi
|
|
15
|
+
# A worker's finish wake (docs/internals/background-tasks.md, Finish
|
|
16
|
+
# wake): its TaskWatch, fed by the Engine's raw events (#observe), and
|
|
17
|
+
# the TASK FINISHED notes for the tasks that finished unseen. #take
|
|
18
|
+
# writes them and hands back the wake turn to run, which the Worker runs
|
|
19
|
+
# (Worker#run_wake); #absorb gives them to a prompt's turn as plain notes.
|
|
20
|
+
# On the loop's thread, like WorkerInbound.
|
|
21
|
+
class WorkerTaskWakes
|
|
22
|
+
# @return [TaskWatch]
|
|
23
|
+
attr_reader :watch
|
|
24
|
+
|
|
25
|
+
# @param wakes [WorkerWakes] the wake budget a task's wake asks
|
|
26
|
+
# @param awaiting_continue [#call] whether a continue offer waits
|
|
27
|
+
# @param idle [#call] nothing queued and no exit asked for: a finish
|
|
28
|
+
# may start a turn
|
|
29
|
+
# @param save [#call] saves the session (a failure is the callee's to log)
|
|
30
|
+
def initialize(engine:, session:, wakes:, awaiting_continue:, idle:, save:)
|
|
31
|
+
@engine = engine
|
|
32
|
+
@session = session
|
|
33
|
+
@wakes = wakes
|
|
34
|
+
@awaiting_continue = awaiting_continue
|
|
35
|
+
@idle = idle
|
|
36
|
+
@save = save
|
|
37
|
+
@watch = TaskWatch.new
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# The Engine's raw events feed the task watch (session.task_wakes not
|
|
41
|
+
# off): a result that started a task or showed its end, a turn's start,
|
|
42
|
+
# a user's Stop of it (M5).
|
|
43
|
+
def observe(event)
|
|
44
|
+
case event[:type]
|
|
45
|
+
when :tool_call_completed then @watch.observe(event) unless TaskWatch.mode == "off"
|
|
46
|
+
when :turn_started then @watch.turn_started
|
|
47
|
+
when :turn_canceled then @watch.turn_canceled(event[:cancellation_reason])
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Whether a finished task would start a wake turn now: the Engine skips
|
|
52
|
+
# the turn-end warm-up then (next_turn_waiting).
|
|
53
|
+
def due?
|
|
54
|
+
TaskWatch.mode == "wake" && @watch.any? && @wakes.task_open?(awaiting_continue: @awaiting_continue.call) &&
|
|
55
|
+
@watch.finished?
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# The background tasks this session started that finished unseen
|
|
59
|
+
# (TaskWatch#take_finished), each as a TASK FINISHED note
|
|
60
|
+
# (TaskFinishNote): the first one not note-only starts a wake turn from
|
|
61
|
+
# task:<id> when session.task_wakes is wake, nothing is queued, no exit
|
|
62
|
+
# was asked for and the wake budget is open (WorkerWakes#task_open?);
|
|
63
|
+
# the others, and every one otherwise, are plain notes for the next
|
|
64
|
+
# turn (M2). A spent budget is announced once.
|
|
65
|
+
# @return [WorkerInbound::TaskWake, nil] the wake turn to run now
|
|
66
|
+
def take
|
|
67
|
+
return nil if @wakes.in_grace? || !@watch.any?
|
|
68
|
+
|
|
69
|
+
finished = take_finished
|
|
70
|
+
return nil if finished.empty?
|
|
71
|
+
|
|
72
|
+
waking = finished.find { |entry, _| !entry.note_only } if wake_open?
|
|
73
|
+
task_wake = note_finished(finished, waking: waking)
|
|
74
|
+
return nil if task_wake == :failed
|
|
75
|
+
|
|
76
|
+
@save.call
|
|
77
|
+
return task_wake if task_wake
|
|
78
|
+
|
|
79
|
+
budget_notice(finished.count { |entry, _| !entry.note_only }) if TaskWatch.mode == "wake" && @wakes.spent?
|
|
80
|
+
nil
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# Before a prompt's turn: the finished tasks join it as plain notes.
|
|
84
|
+
def absorb
|
|
85
|
+
return unless @watch.any?
|
|
86
|
+
|
|
87
|
+
finished = take_finished
|
|
88
|
+
return if finished.empty?
|
|
89
|
+
return if note_finished(finished) == :failed
|
|
90
|
+
|
|
91
|
+
@save.call
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
private
|
|
95
|
+
|
|
96
|
+
# Each finished task's note into the conversation: +waking+'s as the
|
|
97
|
+
# wake turn's start, the others plain. A note that can't be written (a
|
|
98
|
+
# log that can't be read, say) puts it and the ones after it back in
|
|
99
|
+
# the watch for the next look.
|
|
100
|
+
# @return [WorkerInbound::TaskWake, nil, :failed]
|
|
101
|
+
def note_finished(finished, waking: nil)
|
|
102
|
+
written = []
|
|
103
|
+
(finished - [waking]).each do |entry, record|
|
|
104
|
+
add_note(entry, record)
|
|
105
|
+
written << entry
|
|
106
|
+
end
|
|
107
|
+
waking && add_wake_note(*waking)
|
|
108
|
+
rescue StandardError => e
|
|
109
|
+
Log.warn(:worker, "task_note_failed", error: e.class.name, msg: e.message)
|
|
110
|
+
@watch.put_back(finished.map(&:first) - written)
|
|
111
|
+
:failed
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
# Only the tasks the conversation still holds (a !rollback, a restored
|
|
115
|
+
# turn may have dropped the result that started one). A failure to
|
|
116
|
+
# read them is logged and counted (TaskWatch#look_failed: past
|
|
117
|
+
# TaskWatch::MAX_FAILURES they no longer hold the worker up): they wait
|
|
118
|
+
# for the next look.
|
|
119
|
+
def take_finished
|
|
120
|
+
@watch.take_finished(keep: Tools::TaskRuntime.created_ids_in(@engine.messages_checkpoint))
|
|
121
|
+
rescue StandardError => e
|
|
122
|
+
Log.warn(:worker, "task_watch_failed", error: e.class.name, msg: e.message)
|
|
123
|
+
@watch.look_failed
|
|
124
|
+
[]
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def wake_open?
|
|
128
|
+
TaskWatch.mode == "wake" && @idle.call && @wakes.task_open?(awaiting_continue: @awaiting_continue.call)
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def note(entry, record, wake:, turn_id: nil)
|
|
132
|
+
TaskFinishNote.note(record, limit_sec: entry.limit_sec, wake: wake, turn_id: turn_id,
|
|
133
|
+
cap: KernelLoop.resolve_output_char_cap(nil))
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def add_note(entry, record)
|
|
137
|
+
@engine.add_context_note(@session, note(entry, record, wake: false))
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
# The wake note, in the conversation as the wake turn's first message
|
|
141
|
+
# (before TurnFlow#before_prompt_turn, so a restore keeps it).
|
|
142
|
+
# @return [WorkerInbound::TaskWake]
|
|
143
|
+
def add_wake_note(entry, record)
|
|
144
|
+
turn_id = SecureRandom.uuid
|
|
145
|
+
@engine.add_context_note(@session, note(entry, record, wake: true, turn_id: turn_id))
|
|
146
|
+
WorkerInbound::TaskWake.new(id: entry.id, turn_id: turn_id, plain_note: note(entry, record, wake: false))
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
# The wake budget is spent: the UIs hear once that finished tasks wait
|
|
150
|
+
# as notes (one notice per stretch, shared with the other kinds).
|
|
151
|
+
def budget_notice(count)
|
|
152
|
+
return unless count.positive? && @wakes.notice_budget!
|
|
153
|
+
|
|
154
|
+
@engine.announce(type: :hook_notice, hook: "task", level: :info, between_turns: true,
|
|
155
|
+
text: "#{count} finished background task#{"s" if count != 1} noted; the model reads " \
|
|
156
|
+
"#{count == 1 ? "it" : "them"} with your next message " \
|
|
157
|
+
"(#{@wakes.max} wake turn#{"s" if @wakes.max != 1} in a row, #{ChildRing::MAX_WAKES_KEY})")
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
end
|
|
@@ -117,9 +117,6 @@ module Samagotchi
|
|
|
117
117
|
!@paused && !awaiting_continue && !in_grace? && @in_a_row < max
|
|
118
118
|
end
|
|
119
119
|
|
|
120
|
-
# Whether wakes are paused (a failed wake turn) until a human's input.
|
|
121
|
-
def paused? = @paused
|
|
122
|
-
|
|
123
120
|
# A wake turn starts; +peer+: for a peer's answer, which counts toward
|
|
124
121
|
# both budgets. @return [Integer] the wake turns in a row now
|
|
125
122
|
def count!(peer: false)
|
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.
|
|
4
|
+
version: 0.93.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Dmitry Dedov
|
|
@@ -204,6 +204,8 @@ files:
|
|
|
204
204
|
- lib/samagotchi/bundle_command/check.rb
|
|
205
205
|
- lib/samagotchi/bundle_command/scaffold.rb
|
|
206
206
|
- lib/samagotchi/bundle_command/test_run.rb
|
|
207
|
+
- lib/samagotchi/bundle_command/try/command.rb
|
|
208
|
+
- lib/samagotchi/bundle_command/try/render.rb
|
|
207
209
|
- lib/samagotchi/bundle_command/try/run.rb
|
|
208
210
|
- lib/samagotchi/bundle_command/try/sandbox.rb
|
|
209
211
|
- lib/samagotchi/bundle_command/try/trace.rb
|
|
@@ -263,6 +265,7 @@ files:
|
|
|
263
265
|
- lib/samagotchi/bundles/system/self_map.md
|
|
264
266
|
- lib/samagotchi/cache_confirm.rb
|
|
265
267
|
- lib/samagotchi/cancellation_controller.rb
|
|
268
|
+
- lib/samagotchi/child_env.rb
|
|
266
269
|
- lib/samagotchi/child_move.rb
|
|
267
270
|
- lib/samagotchi/child_reports.rb
|
|
268
271
|
- lib/samagotchi/children_status.rb
|
|
@@ -276,6 +279,7 @@ files:
|
|
|
276
279
|
- lib/samagotchi/commands/registry.rb
|
|
277
280
|
- lib/samagotchi/composer_route.rb
|
|
278
281
|
- lib/samagotchi/config.rb
|
|
282
|
+
- lib/samagotchi/config/restart_watch.rb
|
|
279
283
|
- lib/samagotchi/config_text_edit.rb
|
|
280
284
|
- lib/samagotchi/context_absorber.rb
|
|
281
285
|
- lib/samagotchi/context_command.rb
|
|
@@ -331,6 +335,7 @@ files:
|
|
|
331
335
|
- lib/samagotchi/guardrails/model_size.rb
|
|
332
336
|
- lib/samagotchi/guardrails/outside.rb
|
|
333
337
|
- lib/samagotchi/guardrails/parent_approvals.rb
|
|
338
|
+
- lib/samagotchi/guardrails/parent_levels.rb
|
|
334
339
|
- lib/samagotchi/guardrails/parent_policy.rb
|
|
335
340
|
- lib/samagotchi/guardrails/protected_paths.rb
|
|
336
341
|
- lib/samagotchi/guardrails/read_only_shell.rb
|
|
@@ -343,6 +348,7 @@ files:
|
|
|
343
348
|
- lib/samagotchi/guardrails/shell_paths.rb
|
|
344
349
|
- lib/samagotchi/guardrails/targets.rb
|
|
345
350
|
- lib/samagotchi/guardrails/verdict.rb
|
|
351
|
+
- lib/samagotchi/hook_question.rb
|
|
346
352
|
- lib/samagotchi/hook_routes.rb
|
|
347
353
|
- lib/samagotchi/hooks.rb
|
|
348
354
|
- lib/samagotchi/hooks/bundle_loader.rb
|
|
@@ -490,10 +496,14 @@ files:
|
|
|
490
496
|
- lib/samagotchi/reminder_queue.rb
|
|
491
497
|
- lib/samagotchi/reminder_store.rb
|
|
492
498
|
- lib/samagotchi/reply_wait.rb
|
|
499
|
+
- lib/samagotchi/reply_wait/poll.rb
|
|
493
500
|
- lib/samagotchi/row_refs.rb
|
|
494
501
|
- lib/samagotchi/sampling_settings.rb
|
|
502
|
+
- lib/samagotchi/sandbox_layout.rb
|
|
495
503
|
- lib/samagotchi/self_report.rb
|
|
496
504
|
- lib/samagotchi/send_command.rb
|
|
505
|
+
- lib/samagotchi/send_command/parent_gate.rb
|
|
506
|
+
- lib/samagotchi/send_command/wait_target.rb
|
|
497
507
|
- lib/samagotchi/served_model.rb
|
|
498
508
|
- lib/samagotchi/session.rb
|
|
499
509
|
- lib/samagotchi/session_archive_command.rb
|
|
@@ -700,7 +710,9 @@ files:
|
|
|
700
710
|
- lib/samagotchi/web/public/route.js
|
|
701
711
|
- lib/samagotchi/web/public/scope.js
|
|
702
712
|
- lib/samagotchi/web/public/scroll.js
|
|
713
|
+
- lib/samagotchi/web/public/send_turn.js
|
|
703
714
|
- lib/samagotchi/web/public/sentences.js
|
|
715
|
+
- lib/samagotchi/web/public/session_actions.js
|
|
704
716
|
- lib/samagotchi/web/public/session_state.js
|
|
705
717
|
- lib/samagotchi/web/public/session_title.js
|
|
706
718
|
- lib/samagotchi/web/public/sessions_list.js
|
|
@@ -710,6 +722,7 @@ files:
|
|
|
710
722
|
- lib/samagotchi/web/public/stage_slots.js
|
|
711
723
|
- lib/samagotchi/web/public/stage_view.js
|
|
712
724
|
- lib/samagotchi/web/public/stage_watch.js
|
|
725
|
+
- lib/samagotchi/web/public/start_page.js
|
|
713
726
|
- lib/samagotchi/web/public/storage.js
|
|
714
727
|
- lib/samagotchi/web/public/stream_handlers.js
|
|
715
728
|
- lib/samagotchi/web/public/strip.js
|
|
@@ -743,6 +756,7 @@ files:
|
|
|
743
756
|
- lib/samagotchi/worker_inbound.rb
|
|
744
757
|
- lib/samagotchi/worker_sidecar.rb
|
|
745
758
|
- lib/samagotchi/worker_signals.rb
|
|
759
|
+
- lib/samagotchi/worker_task_wakes.rb
|
|
746
760
|
- lib/samagotchi/worker_wakes.rb
|
|
747
761
|
- lib/samagotchi/yaml_lines.rb
|
|
748
762
|
homepage: https://github.com/dm1try/samagotchi
|