samagotchi 0.158.0 → 0.159.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 +21 -1
- data/bin/chi +3 -1
- data/docs/architecture.md +7 -6
- data/docs/cli.md +56 -1
- data/docs/configuration.md +9 -0
- data/docs/context.md +7 -1
- data/docs/guardrails.md +3 -1
- data/docs/hooks.md +3 -0
- data/docs/internals/bridge.md +1 -0
- data/docs/internals/bundles.md +9 -7
- data/docs/memory.md +5 -1
- data/docs/scheduling.md +228 -0
- data/docs/sessions.md +25 -1
- data/lib/samagotchi/bridge.rb +26 -2
- data/lib/samagotchi/bundle_command.rb +38 -1
- data/lib/samagotchi/bundles/system/manifest.yml +1 -1
- data/lib/samagotchi/client_id.rb +13 -3
- data/lib/samagotchi/config.rb +12 -0
- data/lib/samagotchi/context_move.rb +74 -0
- data/lib/samagotchi/guardrails/pair_boundary.rb +1 -1
- data/lib/samagotchi/memory_bundle/asset_installer.rb +84 -103
- data/lib/samagotchi/memory_bundle/asset_state.rb +81 -0
- data/lib/samagotchi/memory_bundle/file_actions.rb +51 -0
- data/lib/samagotchi/memory_bundle/shipped_update.rb +17 -12
- data/lib/samagotchi/memory_bundle/status.rb +20 -1
- data/lib/samagotchi/memory_bundle/uninstaller.rb +10 -4
- data/lib/samagotchi/run_options.rb +1 -0
- data/lib/samagotchi/schedule_command.rb +252 -0
- data/lib/samagotchi/schedules.rb +948 -0
- data/lib/samagotchi/session_access/contract.rb +1 -1
- data/lib/samagotchi/session_access/local.rb +20 -0
- data/lib/samagotchi/session_manager/spawn.rb +25 -11
- data/lib/samagotchi/session_manager/worker_command.rb +13 -13
- data/lib/samagotchi/terminal_ui/formatting.rb +2 -0
- data/lib/samagotchi/tool_declarations.rb +43 -0
- data/lib/samagotchi/tools/builtin_calls.rb +2 -0
- data/lib/samagotchi/tools/builtins.rb +17 -0
- data/lib/samagotchi/tools/cancel_schedule.rb +43 -0
- data/lib/samagotchi/tools/list_schedules.rb +43 -0
- data/lib/samagotchi/tools/schedule_task.rb +39 -0
- data/lib/samagotchi/version.rb +1 -1
- data/lib/samagotchi/web/public/chains.js +32 -8
- data/lib/samagotchi/web/public/index.html +4 -1
- data/lib/samagotchi/web/public/info_bar.js +4 -3
- data/lib/samagotchi/web/public/turn_events.js +4 -0
- data/lib/samagotchi/web/session_hub.rb +20 -0
- data/lib/samagotchi/worker.rb +24 -6
- data/lib/samagotchi/worker_boot.rb +3 -4
- data/lib/samagotchi/worker_inbound.rb +23 -0
- data/lib/samagotchi/worker_link.rb +5 -0
- data/lib/samagotchi/worker_wakes.rb +9 -1
- metadata +8 -1
data/lib/samagotchi/worker.rb
CHANGED
|
@@ -374,7 +374,9 @@ module Samagotchi
|
|
|
374
374
|
# chi web's Stop asks about these before TERMed-ing
|
|
375
375
|
# the worker (its own holds routes).
|
|
376
376
|
on_holds: -> { @idle_exit&.stoppable_holds },
|
|
377
|
-
on_holds_stop: -> { @hold_stop&.stop_all }
|
|
377
|
+
on_holds_stop: -> { @hold_stop&.stop_all },
|
|
378
|
+
# `chi schedule tick` asks this before firing.
|
|
379
|
+
on_activity: method(:activity_snapshot))
|
|
378
380
|
# What failed to load and what plugins showed as they loaded, now that
|
|
379
381
|
# a UI can be there (a late one gets them in the snapshot).
|
|
380
382
|
@engine.announce_load_events!
|
|
@@ -410,12 +412,12 @@ module Samagotchi
|
|
|
410
412
|
# there is no live SSE or in-process cancel/answer).
|
|
411
413
|
# @param on_input [#call, nil] called after the Bridge queues a turn
|
|
412
414
|
def start_bridge(engine:, state_dir:, session_id:, on_input: nil, on_command: nil, on_exit_request: nil,
|
|
413
|
-
exit_discards: nil, exit_stopped: nil, on_holds: nil, on_holds_stop: nil)
|
|
415
|
+
exit_discards: nil, exit_stopped: nil, on_holds: nil, on_holds_stop: nil, on_activity: nil)
|
|
414
416
|
require_relative "bridge"
|
|
415
417
|
Samagotchi::Bridge.new(
|
|
416
418
|
engine: engine, state_dir: state_dir, session_id: session_id, input_format: SessionInbox::INPUT_FORMAT,
|
|
417
419
|
on_input: on_input, on_command: on_command, on_exit_request: on_exit_request, exit_discards: exit_discards,
|
|
418
|
-
exit_stopped: exit_stopped, on_holds: on_holds, on_holds_stop: on_holds_stop
|
|
420
|
+
exit_stopped: exit_stopped, on_holds: on_holds, on_holds_stop: on_holds_stop, on_activity: on_activity
|
|
419
421
|
).start
|
|
420
422
|
rescue StandardError => e
|
|
421
423
|
Log.error(:bridge, "start_failed", echo: "Bridge: failed to start for session #{session_id}: #{e.class}: #{e.message}", sid: session_id, error: e.class.name)
|
|
@@ -426,6 +428,22 @@ module Samagotchi
|
|
|
426
428
|
Degrade.call(:config, "idle_exit_minutes_unreadable") { Samagotchi::Config.get("session.idle_exit_minutes") }
|
|
427
429
|
end
|
|
428
430
|
|
|
431
|
+
# What this worker is busy with right now, for GET /activity: the same
|
|
432
|
+
# signals WorkerIdleExit#hold reads. A schedule never holds a worker up,
|
|
433
|
+
# so +reminders+ and +tasks_holding+ are reported for the log but are not a
|
|
434
|
+
# reason for a tick to skip a firing.
|
|
435
|
+
# @return [Hash]
|
|
436
|
+
def activity_snapshot
|
|
437
|
+
{
|
|
438
|
+
turn_running: @engine.turn_running?,
|
|
439
|
+
input_pending: input_pending?,
|
|
440
|
+
awaiting_continue: @turn_flow.awaiting_continue?,
|
|
441
|
+
open_streams: @bridge&.open_streams.to_i,
|
|
442
|
+
reminders: @engine.reminder_store&.any? ? 1 : 0,
|
|
443
|
+
tasks_holding: Degrade.call(:worker, "activity_tasks_unreadable") { @task_wakes&.watch&.holding&.size.to_i }
|
|
444
|
+
}
|
|
445
|
+
end
|
|
446
|
+
|
|
429
447
|
# The delegate children of this session that are running a turn or have
|
|
430
448
|
# a live worker. ChildrenStatus.of scans the session files; this runs on
|
|
431
449
|
# an exit request, not every pass.
|
|
@@ -1033,9 +1051,9 @@ module Samagotchi
|
|
|
1033
1051
|
kept: "Its note stays for the user's next message.", mark: task_wake)
|
|
1034
1052
|
end
|
|
1035
1053
|
|
|
1036
|
-
# The idle loop's sleep: the fallback tick, or less while reports
|
|
1037
|
-
# out the start grace.
|
|
1038
|
-
def idle_wait = @wakes.idle_wait(@poll_interval) { wake_state == :due }
|
|
1054
|
+
# The idle loop's sleep: the fallback tick, or less while reports or
|
|
1055
|
+
# attached-context wakes wait out the start grace.
|
|
1056
|
+
def idle_wait = @wakes.idle_wait(@poll_interval) { wake_state == :due || @inbound.context_wake_waiting? }
|
|
1039
1057
|
|
|
1040
1058
|
# The wake budget is spent: the parent's UIs hear once that reports
|
|
1041
1059
|
# wait for the next message.
|
|
@@ -3,9 +3,8 @@
|
|
|
3
3
|
require_relative "session_manager"
|
|
4
4
|
|
|
5
5
|
module Samagotchi
|
|
6
|
-
# WorkerBoot: the worker process, from
|
|
7
|
-
#
|
|
8
|
-
# SessionManager.run_session_loop) to what it does as it leaves (CROSS-VERSION
|
|
6
|
+
# WorkerBoot: the worker process, from the entry the boot string names
|
|
7
|
+
# (WorkerBoot.run_session_loop) to what it does as it leaves (CROSS-VERSION
|
|
9
8
|
# CONTRACT: spec/worker_contract_spec.rb). It takes the session's OwnerLock,
|
|
10
9
|
# leaves the spawner's process tree, installs the signals and the project
|
|
11
10
|
# env, and runs the Worker (worker.rb loads only then, after the lock). Calls
|
|
@@ -14,7 +13,7 @@ module Samagotchi
|
|
|
14
13
|
module WorkerBoot
|
|
15
14
|
class << self
|
|
16
15
|
# Run the session loop inside the forked process: the worker's main,
|
|
17
|
-
# which the boot string
|
|
16
|
+
# which the boot string names directly.
|
|
18
17
|
#
|
|
19
18
|
# Every worker starts its per-session Bridge (the single live client
|
|
20
19
|
# transport) on a port bound to 127.0.0.1 before the loop and stops it on
|
|
@@ -106,6 +106,7 @@ module Samagotchi
|
|
|
106
106
|
@stopped = stopped
|
|
107
107
|
@queue_command = queue_command
|
|
108
108
|
@initial_prompt_taken = false
|
|
109
|
+
@context_wake_waiting = false
|
|
109
110
|
end
|
|
110
111
|
|
|
111
112
|
# Add the queued context notes to the conversation (between turns only,
|
|
@@ -148,12 +149,18 @@ module Samagotchi
|
|
|
148
149
|
# @return [ContextWake, nil] the wake turn to run now
|
|
149
150
|
# @raise [SystemCallError, IOError] the caller logs it (context_failed)
|
|
150
151
|
def absorb_context(before_turn: false, wake: false)
|
|
152
|
+
@context_wake_waiting = false
|
|
151
153
|
return nil unless before_turn || conversation_started?
|
|
152
154
|
return nil if @stopped.call
|
|
153
155
|
|
|
154
156
|
batch = @context_absorber.pending
|
|
155
157
|
return nil unless batch
|
|
156
158
|
|
|
159
|
+
if wake && context_wake_waiting_for?(batch)
|
|
160
|
+
@context_wake_waiting = true
|
|
161
|
+
return nil
|
|
162
|
+
end
|
|
163
|
+
|
|
157
164
|
waking = wake ? context_wake_for(batch) : nil
|
|
158
165
|
turn_id = SecureRandom.uuid if waking
|
|
159
166
|
batch.deliveries.each do |delivery|
|
|
@@ -170,6 +177,10 @@ module Samagotchi
|
|
|
170
177
|
waking && ContextWake.new(delivery: waking, turn_id: turn_id)
|
|
171
178
|
end
|
|
172
179
|
|
|
180
|
+
# Whether #absorb_context left an eligible wake batch uncommitted for
|
|
181
|
+
# the start grace, so the idle loop can revisit it when grace expires.
|
|
182
|
+
def context_wake_waiting? = @context_wake_waiting
|
|
183
|
+
|
|
173
184
|
# A failed wake turn kept nothing but its note: the note goes back to
|
|
174
185
|
# a plain note (no turn start, the background wording), so a reload
|
|
175
186
|
# draws no empty turn for it. +wake+: a ContextWake or a TaskWake.
|
|
@@ -300,6 +311,18 @@ module Samagotchi
|
|
|
300
311
|
waking.first
|
|
301
312
|
end
|
|
302
313
|
|
|
314
|
+
def context_wake_waiting_for?(batch)
|
|
315
|
+
return false unless @wakes.in_grace?
|
|
316
|
+
|
|
317
|
+
candidates = batch.deliveries.select(&:wake_note)
|
|
318
|
+
return false if candidates.empty? || !context_wakes_on?
|
|
319
|
+
return false unless @wakes.context_ready?(awaiting_continue: @awaiting_continue.call, names: candidates.map(&:name))
|
|
320
|
+
|
|
321
|
+
candidates.any? do |delivery|
|
|
322
|
+
delivery.peer ? @wakes.peer_in_a_row < @wakes.peer_turns : !woke_lately?(delivery.subscription, Time.now)
|
|
323
|
+
end
|
|
324
|
+
end
|
|
325
|
+
|
|
303
326
|
# A peer's answer waits as a note: the UIs hear it once per
|
|
304
327
|
# interactive input (WorkerWakes#notice_peer_budget!). +key+: the
|
|
305
328
|
# budget that holds it.
|
|
@@ -34,6 +34,11 @@ module Samagotchi
|
|
|
34
34
|
# newer worker's (Skew).
|
|
35
35
|
PROTOCOL = 1
|
|
36
36
|
|
|
37
|
+
# A worker whose sidecar publishes this may be asked what it is busy with
|
|
38
|
+
# (Bridge's GET /activity, Worker#activity_snapshot): a sidecar without it
|
|
39
|
+
# is an older chi's, and asking it would only cost a 404.
|
|
40
|
+
ACTIVITY_FEATURE = "activity"
|
|
41
|
+
|
|
37
42
|
# Seconds a worker may hold the lock without publishing its Bridge before
|
|
38
43
|
# Starting is stuck (SessionManager::WORKER_START_GRACE).
|
|
39
44
|
START_LIMIT = 30.0
|
|
@@ -101,7 +101,15 @@ module Samagotchi
|
|
|
101
101
|
# not paused, past the start grace and under the budget. +names+: the
|
|
102
102
|
# sources asking, for the log line when the budget holds them.
|
|
103
103
|
def context_open?(awaiting_continue:, names:)
|
|
104
|
-
return false if
|
|
104
|
+
return false if in_grace?
|
|
105
|
+
|
|
106
|
+
context_ready?(awaiting_continue:, names:)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# The context wake gates apart from start grace; used to decide whether
|
|
110
|
+
# a wake must remain pending until that grace ends.
|
|
111
|
+
def context_ready?(awaiting_continue:, names:)
|
|
112
|
+
return false if @paused || awaiting_continue
|
|
105
113
|
|
|
106
114
|
if @in_a_row >= max
|
|
107
115
|
Log.info(:worker, "context_wake_held", reason: "max_wakes", names: names.join(","))
|
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.159.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Dmitry Dedov
|
|
@@ -176,6 +176,7 @@ files:
|
|
|
176
176
|
- docs/memory.md
|
|
177
177
|
- docs/plugins.md
|
|
178
178
|
- docs/releasing.md
|
|
179
|
+
- docs/scheduling.md
|
|
179
180
|
- docs/sessions.md
|
|
180
181
|
- docs/sub-agent.md
|
|
181
182
|
- docs/system-one.md
|
|
@@ -499,6 +500,7 @@ files:
|
|
|
499
500
|
- lib/samagotchi/log_subscriber.rb
|
|
500
501
|
- lib/samagotchi/memory_bundle.rb
|
|
501
502
|
- lib/samagotchi/memory_bundle/asset_installer.rb
|
|
503
|
+
- lib/samagotchi/memory_bundle/asset_state.rb
|
|
502
504
|
- lib/samagotchi/memory_bundle/builder.rb
|
|
503
505
|
- lib/samagotchi/memory_bundle/bundle_hook.rb
|
|
504
506
|
- lib/samagotchi/memory_bundle/entry_size.rb
|
|
@@ -640,6 +642,8 @@ files:
|
|
|
640
642
|
- lib/samagotchi/run_options.rb
|
|
641
643
|
- lib/samagotchi/sampling_settings.rb
|
|
642
644
|
- lib/samagotchi/sandbox_layout.rb
|
|
645
|
+
- lib/samagotchi/schedule_command.rb
|
|
646
|
+
- lib/samagotchi/schedules.rb
|
|
643
647
|
- lib/samagotchi/self_report.rb
|
|
644
648
|
- lib/samagotchi/send_command.rb
|
|
645
649
|
- lib/samagotchi/send_command/busy.rb
|
|
@@ -802,6 +806,7 @@ files:
|
|
|
802
806
|
- lib/samagotchi/tools/builtin_calls.rb
|
|
803
807
|
- lib/samagotchi/tools/builtins.rb
|
|
804
808
|
- lib/samagotchi/tools/cancel_reminder.rb
|
|
809
|
+
- lib/samagotchi/tools/cancel_schedule.rb
|
|
805
810
|
- lib/samagotchi/tools/context_read.rb
|
|
806
811
|
- lib/samagotchi/tools/deferred_tools.rb
|
|
807
812
|
- lib/samagotchi/tools/delegate.rb
|
|
@@ -814,6 +819,7 @@ files:
|
|
|
814
819
|
- lib/samagotchi/tools/forget_outputs.rb
|
|
815
820
|
- lib/samagotchi/tools/index_hint.rb
|
|
816
821
|
- lib/samagotchi/tools/list_reminders.rb
|
|
822
|
+
- lib/samagotchi/tools/list_schedules.rb
|
|
817
823
|
- lib/samagotchi/tools/list_sessions.rb
|
|
818
824
|
- lib/samagotchi/tools/memory.rb
|
|
819
825
|
- lib/samagotchi/tools/objectives_tool.rb
|
|
@@ -823,6 +829,7 @@ files:
|
|
|
823
829
|
- lib/samagotchi/tools/ref_text.rb
|
|
824
830
|
- lib/samagotchi/tools/register_reminder.rb
|
|
825
831
|
- lib/samagotchi/tools/registry.rb
|
|
832
|
+
- lib/samagotchi/tools/schedule_task.rb
|
|
826
833
|
- lib/samagotchi/tools/send_note.rb
|
|
827
834
|
- lib/samagotchi/tools/shell.rb
|
|
828
835
|
- lib/samagotchi/tools/task_create.rb
|