samagotchi 0.153.0 → 0.154.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +42 -1
- data/README.md +2 -3
- data/bin/chi +23 -24
- data/docs/architecture.md +30 -33
- data/docs/broadcast.md +5 -5
- data/docs/bundles.md +9 -12
- data/docs/cli.md +82 -96
- data/docs/configuration.md +27 -26
- data/docs/context.md +3 -3
- data/docs/desktop.md +1 -1
- data/docs/guardrails.md +8 -10
- data/docs/hooks.md +9 -9
- data/docs/internals/attached-context.md +2 -2
- data/docs/internals/background-tasks.md +3 -4
- data/docs/internals/block-renderers.md +4 -0
- data/docs/internals/bridge.md +21 -8
- data/docs/internals/context-telemetry.md +1 -1
- data/docs/internals/engine.md +33 -7
- data/docs/internals/objectives.md +6 -5
- data/docs/internals/participants.md +7 -7
- data/docs/internals/prompt-caching.md +4 -2
- data/docs/internals/remote-sessions.md +7 -7
- data/docs/internals/web-frontend.md +2 -2
- data/docs/internals/web-push.md +1 -1
- data/docs/memory.md +2 -2
- data/docs/plugins.md +23 -28
- data/docs/sessions.md +24 -24
- data/docs/sub-agent.md +2 -2
- data/docs/system-one.md +1 -1
- data/docs/testing.md +31 -6
- data/lib/samagotchi/answer_text.rb +33 -0
- data/lib/samagotchi/bridge/card_places.rb +56 -7
- data/lib/samagotchi/bridge/card_store.rb +24 -9
- data/lib/samagotchi/bridge.rb +52 -32
- data/lib/samagotchi/bridge_client.rb +19 -14
- data/lib/samagotchi/broadcast/recipients.rb +2 -2
- data/lib/samagotchi/broadcast/triage.rb +1 -1
- data/lib/samagotchi/broadcast_command.rb +5 -5
- data/lib/samagotchi/bundle_command/try/command.rb +1 -1
- data/lib/samagotchi/bundle_command/try/run.rb +1 -1
- data/lib/samagotchi/bundle_command/try/trace.rb +1 -1
- data/lib/samagotchi/bundle_command.rb +2 -2
- data/lib/samagotchi/bundles/btw/manifest.yml +2 -2
- data/lib/samagotchi/bundles/btw/plugin.rb +1 -1
- data/lib/samagotchi/bundles/coordinator/manifest.yml +2 -2
- data/lib/samagotchi/bundles/coordinator/plugin.rb +3 -2
- data/lib/samagotchi/bundles/decision-card/manifest.yml +4 -4
- data/lib/samagotchi/bundles/decision-card/plugin.rb +1 -9
- data/lib/samagotchi/bundles/dev/manifest.yml +2 -2
- data/lib/samagotchi/bundles/github-pr/manifest.yml +2 -2
- data/lib/samagotchi/bundles/github-pr/plugin.rb +3 -3
- data/lib/samagotchi/bundles/skills/manifest.yml +2 -2
- data/lib/samagotchi/bundles/skills/plugin.rb +3 -2
- data/lib/samagotchi/bundles/system/config_modification_protocol.md +3 -4
- data/lib/samagotchi/bundles/system/manifest.yml +3 -3
- data/lib/samagotchi/bundles/system/self_map.md +1 -1
- data/lib/samagotchi/child_move.rb +3 -3
- data/lib/samagotchi/commands/registry.rb +6 -6
- data/lib/samagotchi/composer_route.rb +4 -5
- data/lib/samagotchi/config.rb +14 -12
- data/lib/samagotchi/context_candidate_choice.rb +1 -1
- data/lib/samagotchi/context_candidates.rb +4 -3
- data/lib/samagotchi/continue_offer.rb +1 -1
- data/lib/samagotchi/debug_log.rb +1 -1
- data/lib/samagotchi/degrade.rb +75 -0
- data/lib/samagotchi/desktop/macos/ChiRunner.swift +3 -3
- data/lib/samagotchi/engine/cards.rb +87 -0
- data/lib/samagotchi/engine/context_judge.rb +138 -0
- data/lib/samagotchi/engine/events.rb +131 -0
- data/lib/samagotchi/engine/guardrails.rb +87 -0
- data/lib/samagotchi/engine/hooks.rb +119 -0
- data/lib/samagotchi/engine/messages.rb +124 -0
- data/lib/samagotchi/engine/model_settings.rb +127 -0
- data/lib/samagotchi/engine/models.rb +261 -0
- data/lib/samagotchi/engine/objectives.rb +116 -0
- data/lib/samagotchi/engine/participants.rb +86 -0
- data/lib/samagotchi/engine/plugins.rb +208 -0
- data/lib/samagotchi/engine/questions.rb +98 -0
- data/lib/samagotchi/engine/recap.rb +130 -0
- data/lib/samagotchi/engine/session.rb +131 -0
- data/lib/samagotchi/engine/side_requests.rb +135 -0
- data/lib/samagotchi/engine/steering.rb +134 -0
- data/lib/samagotchi/engine/toolkit.rb +269 -0
- data/lib/samagotchi/engine/turn_end.rb +180 -0
- data/lib/samagotchi/engine/turn_helpers.rb +160 -0
- data/lib/samagotchi/engine/verify.rb +153 -0
- data/lib/samagotchi/engine.rb +62 -2646
- data/lib/samagotchi/engine_snapshots.rb +9 -8
- data/lib/samagotchi/grants.rb +575 -0
- data/lib/samagotchi/guardrail_wiring.rb +2 -2
- data/lib/samagotchi/guardrails/context.rb +2 -3
- data/lib/samagotchi/guardrails/parent_approvals.rb +2 -2
- data/lib/samagotchi/guardrails/parent_policy.rb +2 -2
- data/lib/samagotchi/hook_routes.rb +3 -3
- data/lib/samagotchi/idle_recap.rb +7 -6
- data/lib/samagotchi/idle_reminders.rb +3 -4
- data/lib/samagotchi/iteration_limit.rb +2 -2
- data/lib/samagotchi/kernel_loop.rb +13 -13
- data/lib/samagotchi/launch_mode.rb +13 -32
- data/lib/samagotchi/level_setting_command.rb +3 -2
- data/lib/samagotchi/llm/chat_loop.rb +3 -1
- data/lib/samagotchi/llm_context_command.rb +3 -2
- data/lib/samagotchi/log.rb +7 -7
- data/lib/samagotchi/log_line.rb +1 -1
- data/lib/samagotchi/log_path.rb +1 -1
- data/lib/samagotchi/note_command.rb +1 -1
- data/lib/samagotchi/note_delivery.rb +18 -8
- data/lib/samagotchi/objectives.rb +24 -3
- data/lib/samagotchi/objectives_check.rb +8 -27
- data/lib/samagotchi/objectives_command.rb +4 -69
- data/lib/samagotchi/objectives_edit.rb +87 -0
- data/lib/samagotchi/output_formatter.rb +7 -1
- data/lib/samagotchi/owner_lock.rb +7 -1
- data/lib/samagotchi/parent_answers_command.rb +5 -4
- data/lib/samagotchi/participant_exposure.rb +42 -0
- data/lib/samagotchi/participant_mode.rb +1 -1
- data/lib/samagotchi/participant_name.rb +1 -1
- data/lib/samagotchi/participants.rb +17 -17
- data/lib/samagotchi/participants_watch.rb +1 -1
- data/lib/samagotchi/plugin/api.rb +3 -2
- data/lib/samagotchi/plugin/context.rb +21 -7
- data/lib/samagotchi/plugin/peer.rb +2 -1
- data/lib/samagotchi/plugin/sessions.rb +6 -4
- data/lib/samagotchi/plugin_tasks.rb +1 -2
- data/lib/samagotchi/private_files.rb +29 -0
- data/lib/samagotchi/project_env.rb +2 -2
- data/lib/samagotchi/question_desk.rb +8 -7
- data/lib/samagotchi/recap_command.rb +2 -1
- data/lib/samagotchi/recap_setup.rb +1 -1
- data/lib/samagotchi/recap_store.rb +1 -1
- data/lib/samagotchi/redact.rb +86 -0
- data/lib/samagotchi/reminder_queue.rb +2 -2
- data/lib/samagotchi/remote_attach_command.rb +1 -1
- data/lib/samagotchi/reply_wait/poll.rb +2 -2
- data/lib/samagotchi/review_start.rb +1 -1
- data/lib/samagotchi/run_options.rb +6 -6
- data/lib/samagotchi/self_report.rb +42 -39
- data/lib/samagotchi/send_command/busy.rb +1 -1
- data/lib/samagotchi/send_command.rb +4 -1
- data/lib/samagotchi/session.rb +11 -2
- data/lib/samagotchi/session_access/contract.rb +3 -3
- data/lib/samagotchi/session_access/local.rb +9 -9
- data/lib/samagotchi/session_access/remote.rb +17 -7
- data/lib/samagotchi/session_access.rb +4 -4
- data/lib/samagotchi/session_archive_command.rb +2 -2
- data/lib/samagotchi/session_chain.rb +8 -6
- data/lib/samagotchi/session_commands.rb +45 -48
- data/lib/samagotchi/session_continue.rb +1 -1
- data/lib/samagotchi/session_delete_command.rb +4 -4
- data/lib/samagotchi/session_manager.rb +67 -49
- data/lib/samagotchi/session_metrics.rb +2 -2
- data/lib/samagotchi/session_model_settings.rb +3 -2
- data/lib/samagotchi/session_participants.rb +1 -1
- data/lib/samagotchi/session_retention.rb +27 -7
- data/lib/samagotchi/sessions_command.rb +4 -4
- data/lib/samagotchi/share_command.rb +10 -10
- data/lib/samagotchi/steer.rb +13 -2
- data/lib/samagotchi/stream_event.rb +22 -0
- data/lib/samagotchi/system_prompt.rb +154 -145
- data/lib/samagotchi/task_watch.rb +1 -1
- data/lib/samagotchi/terminal_ui/attach_launcher.rb +72 -10
- data/lib/samagotchi/terminal_ui/attached_loop/composer.rb +12 -9
- data/lib/samagotchi/terminal_ui/attached_loop/exit_commands.rb +16 -0
- data/lib/samagotchi/terminal_ui/attached_loop/questions.rb +2 -3
- data/lib/samagotchi/terminal_ui/attached_loop.rb +17 -8
- data/lib/samagotchi/terminal_ui/attached_view.rb +1 -11
- data/lib/samagotchi/terminal_ui/event_renderer.rb +3 -5
- data/lib/samagotchi/terminal_ui/formatting.rb +7 -7
- data/lib/samagotchi/terminal_ui/input_support.rb +17 -22
- data/lib/samagotchi/terminal_ui/join_replay.rb +16 -12
- data/lib/samagotchi/terminal_ui/line_reader.rb +2 -2
- data/lib/samagotchi/terminal_ui/live_region.rb +2 -2
- data/lib/samagotchi/terminal_ui/log_tail.rb +135 -0
- data/lib/samagotchi/terminal_ui/one_shot_sink.rb +2 -2
- data/lib/samagotchi/terminal_ui/plain_surface.rb +1 -1
- data/lib/samagotchi/terminal_ui/question_prompt.rb +4 -5
- data/lib/samagotchi/terminal_ui/reline_seam.rb +2 -12
- data/lib/samagotchi/terminal_ui/status_row.rb +6 -14
- data/lib/samagotchi/terminal_ui.rb +142 -1387
- data/lib/samagotchi/title_command.rb +2 -2
- data/lib/samagotchi/tool_runner.rb +15 -16
- data/lib/samagotchi/toolkit_command.rb +2 -1
- data/lib/samagotchi/tools/delegate.rb +3 -1
- data/lib/samagotchi/tools/delegate_cursor.rb +3 -3
- data/lib/samagotchi/tools/delegate_wait.rb +1 -1
- data/lib/samagotchi/tools/objectives_tool.rb +2 -2
- data/lib/samagotchi/tools/send_note.rb +2 -1
- data/lib/samagotchi/turn_endings.rb +2 -2
- data/lib/samagotchi/turn_flow.rb +11 -7
- data/lib/samagotchi/update_hint.rb +2 -2
- data/lib/samagotchi/version.rb +1 -1
- data/lib/samagotchi/web/app.rb +42 -51
- data/lib/samagotchi/web/message_display.rb +7 -0
- data/lib/samagotchi/web/participant_access.rb +2 -2
- data/lib/samagotchi/web/participant_review.rb +5 -5
- data/lib/samagotchi/web/participant_stream_filter.rb +8 -8
- data/lib/samagotchi/web/participant_view.rb +2 -82
- data/lib/samagotchi/web/participants_admin.rb +1 -1
- data/lib/samagotchi/web/public/block_host.js +35 -8
- data/lib/samagotchi/web/public/block_renderers.css +9 -5
- data/lib/samagotchi/web/public/card_stamps.js +27 -0
- data/lib/samagotchi/web/public/cards_place.js +5 -3
- data/lib/samagotchi/web/public/chains.js +2 -2
- data/lib/samagotchi/web/public/claim_link.js +4 -4
- data/lib/samagotchi/web/public/composer_mode.js +1 -1
- data/lib/samagotchi/web/public/format.js +4 -3
- data/lib/samagotchi/web/public/turn_html.js +8 -4
- data/lib/samagotchi/web/push/store.rb +1 -1
- data/lib/samagotchi/web/session_access_routes.rb +13 -4
- data/lib/samagotchi/web/session_control.rb +12 -8
- data/lib/samagotchi/web/session_create.rb +1 -1
- data/lib/samagotchi/web/session_hub.rb +2 -2
- data/lib/samagotchi/web/session_show.rb +6 -2
- data/lib/samagotchi/web/session_summary.rb +1 -1
- data/lib/samagotchi/worker.rb +103 -9
- data/lib/samagotchi/worker_link.rb +3 -3
- data/lib/samagotchi/working_set_command.rb +3 -2
- data/lib/samagotchi.rb +0 -1
- metadata +31 -7
- data/lib/samagotchi/pending_input_queue.rb +0 -55
- data/lib/samagotchi/terminal_ui/between_turns.rb +0 -138
- data/lib/samagotchi/terminal_ui/repl_input.rb +0 -152
- data/lib/samagotchi/web/grants.rb +0 -575
- data/lib/samagotchi/web/participant_exposure.rb +0 -44
- data/lib/samagotchi/web/private_files.rb +0 -31
data/lib/samagotchi/worker.rb
CHANGED
|
@@ -14,6 +14,7 @@ require_relative "turn_note"
|
|
|
14
14
|
require_relative "steer"
|
|
15
15
|
require_relative "turn_origin"
|
|
16
16
|
require_relative "worker_idle_exit"
|
|
17
|
+
require_relative "degrade"
|
|
17
18
|
require_relative "hold_stop"
|
|
18
19
|
require_relative "children_status"
|
|
19
20
|
require_relative "worker_wakes"
|
|
@@ -51,7 +52,7 @@ module Samagotchi
|
|
|
51
52
|
# It runs the session's Engine and Bridge, takes queued prompts from the
|
|
52
53
|
# input dir one turn at a time, and returns when nobody has used it for the
|
|
53
54
|
# idle-exit timeout. A failed turn is rolled back and its prompt handed back
|
|
54
|
-
# (:prompt_restored),
|
|
55
|
+
# (:prompt_restored), and the loop goes on. A stop marked on
|
|
55
56
|
# disk exits the process; an error outside a turn marks the session and
|
|
56
57
|
# exits with 1.
|
|
57
58
|
#
|
|
@@ -188,6 +189,10 @@ module Samagotchi
|
|
|
188
189
|
# checks again then).
|
|
189
190
|
def discard? = @discard
|
|
190
191
|
|
|
192
|
+
# Whether this worker runs a `chi scratch` session: deleted as it leaves
|
|
193
|
+
# (SessionManager.run_session_loop).
|
|
194
|
+
def scratch? = !!@session&.scratch
|
|
195
|
+
|
|
191
196
|
# Whether delegate reports wait that an idle parent runs a turn for
|
|
192
197
|
# (#wake_state): SessionManager.run_session_loop starts a new worker
|
|
193
198
|
# for them after this one leaves. Reports the budget or a failure held
|
|
@@ -201,8 +206,9 @@ module Samagotchi
|
|
|
201
206
|
# to exit (Bridge POST /exit), :restart when it asked for a restart
|
|
202
207
|
# (the caller starts a new worker), :stopped when the session was stopped
|
|
203
208
|
# (chi stop), :signal when a signal stopped it (WorkerSignals),
|
|
204
|
-
# :crashed when the loop raised (the session is marked errored)
|
|
205
|
-
#
|
|
209
|
+
# :crashed when the loop raised (the session is marked errored),
|
|
210
|
+
# :scratch_left when a scratch session's terminal is gone (the caller
|
|
211
|
+
# deletes it); SessionManager.run_session_loop turns it into the exit
|
|
206
212
|
def run
|
|
207
213
|
# The thread a signal's expired grace raises in (the main thread in a
|
|
208
214
|
# worker process).
|
|
@@ -248,6 +254,8 @@ module Samagotchi
|
|
|
248
254
|
# The session, its Engine and what runs its turns, before anyone can
|
|
249
255
|
# reach it.
|
|
250
256
|
def start
|
|
257
|
+
# A scratch worker's grace for its terminal's first stream counts from here.
|
|
258
|
+
@started_at = monotonic_now
|
|
251
259
|
# The wake turns' budget (delegate reports, attached context, peers), from now.
|
|
252
260
|
@wakes = WorkerWakes.new(grace: WAKE_START_GRACE)
|
|
253
261
|
# This worker holds the session now (a continue's starting marker held
|
|
@@ -340,7 +348,7 @@ module Samagotchi
|
|
|
340
348
|
@bridge.queue_command(line, client_id: client_id, after_file: after_file,
|
|
341
349
|
enqueued_id: enqueued_id, author: author)
|
|
342
350
|
})
|
|
343
|
-
# /model's default is the config's
|
|
351
|
+
# /model's default is the config's; the Engine started
|
|
344
352
|
# on the session's model. nil when there is no default.model.
|
|
345
353
|
@default_model = ModelProfile.default_model_name
|
|
346
354
|
@commands = SessionCommands.new(engine: @engine, turn_flow: @turn_flow,
|
|
@@ -416,6 +424,31 @@ module Samagotchi
|
|
|
416
424
|
@context_poller = ContextPoller.new(session_id: @session_id, state_dir: @state_dir,
|
|
417
425
|
project_root: @session.project_root, cwd: @session.working_directory,
|
|
418
426
|
on_change: -> { @waker.wake }).start
|
|
427
|
+
@scratch_watch = start_scratch_watch if @session.scratch
|
|
428
|
+
end
|
|
429
|
+
|
|
430
|
+
# A scratch session's turn never runs on with no terminal: a turn
|
|
431
|
+
# waiting on a question or an approval would keep the worker up for
|
|
432
|
+
# nobody. Each tick while a turn runs and its terminal is gone
|
|
433
|
+
# (#scratch_unattended?), the question is dropped and the turn
|
|
434
|
+
# cancelled as a stop cancels it; the idle pass then leaves
|
|
435
|
+
# (:scratch_left) and the session is deleted.
|
|
436
|
+
def start_scratch_watch
|
|
437
|
+
Thread.new do
|
|
438
|
+
loop do
|
|
439
|
+
sleep(@poll_interval)
|
|
440
|
+
Degrade.call(:worker, "scratch_watch_failed") { cancel_unattended_turn }
|
|
441
|
+
end
|
|
442
|
+
end.tap { |thread| thread.report_on_exception = false }
|
|
443
|
+
end
|
|
444
|
+
|
|
445
|
+
def cancel_unattended_turn
|
|
446
|
+
return unless @engine.turn_running? && scratch_unattended?
|
|
447
|
+
|
|
448
|
+
Log.info(:worker, "scratch_turn_cancelled", sid: @session_id)
|
|
449
|
+
@engine.cancel_question(SessionManager::STOP_CANCEL_REASON) if @engine.pending_question
|
|
450
|
+
@engine.cancel_current_turn!(SessionManager::STOP_CANCEL_REASON.to_sym)
|
|
451
|
+
@waker.wake
|
|
419
452
|
end
|
|
420
453
|
|
|
421
454
|
# One pass of the loop: the first work found runs (queued commands, a
|
|
@@ -468,6 +501,7 @@ module Samagotchi
|
|
|
468
501
|
return if run_wake_turn
|
|
469
502
|
return if run_task_wake
|
|
470
503
|
return if run_due_reminders
|
|
504
|
+
return left(:scratch_left) if scratch_unattended? && !@engine.turn_running? && leave_scratch
|
|
471
505
|
return left(:idle_exit) if @idle_exit.due? && leave_idle
|
|
472
506
|
|
|
473
507
|
leaving = @exit_requested && leave_on_request
|
|
@@ -553,6 +587,7 @@ module Samagotchi
|
|
|
553
587
|
TEARDOWN_LEAVE_WAIT = 10
|
|
554
588
|
|
|
555
589
|
def teardown
|
|
590
|
+
@scratch_watch&.kill
|
|
556
591
|
@config_restart_unsubscribe&.call
|
|
557
592
|
@context_poller&.stop
|
|
558
593
|
drop_queued_commands
|
|
@@ -571,6 +606,8 @@ module Samagotchi
|
|
|
571
606
|
engine = nil
|
|
572
607
|
engine = Samagotchi::Engine.new(
|
|
573
608
|
model_name: @session.model_name,
|
|
609
|
+
# `chi scratch`: no memory_write, no delegates, approvals in memory.
|
|
610
|
+
scratch: @session.scratch,
|
|
574
611
|
model_typed: @session.model_typed,
|
|
575
612
|
# The session's --memory and --mute lists: the same prompt on every
|
|
576
613
|
# (re)spawn.
|
|
@@ -783,7 +820,7 @@ module Samagotchi
|
|
|
783
820
|
end
|
|
784
821
|
|
|
785
822
|
# A participant's cap in dollars: their own, else the config's.
|
|
786
|
-
def participant_cap(entry) = entry&.cap.is_a?(Numeric) ? entry.cap.to_f :
|
|
823
|
+
def participant_cap(entry) = entry&.cap.is_a?(Numeric) ? entry.cap.to_f : Grants.default_cap
|
|
787
824
|
|
|
788
825
|
# A participant's cleaned name, else their id.
|
|
789
826
|
def participant_label(author, name)
|
|
@@ -830,7 +867,7 @@ module Samagotchi
|
|
|
830
867
|
nil
|
|
831
868
|
end
|
|
832
869
|
|
|
833
|
-
# A due reminder runs as a continue turn
|
|
870
|
+
# A due reminder runs as a continue turn: Engine#run_turn
|
|
834
871
|
# injects the reminders as a tail system message, and no user message is
|
|
835
872
|
# added. A prompt's turn may have injected them already (a stale latch):
|
|
836
873
|
# then there is nothing to run.
|
|
@@ -1414,7 +1451,7 @@ module Samagotchi
|
|
|
1414
1451
|
# WorkerInbound.save_or_log: a failed save between turns is logged.
|
|
1415
1452
|
def save_or_log(at, &) = WorkerInbound.save_or_log(at, &)
|
|
1416
1453
|
|
|
1417
|
-
# Back to the conversation before the failed turn
|
|
1454
|
+
# Back to the conversation before the failed turn (so
|
|
1418
1455
|
# failed prompts don't pile up as consecutive user messages), and each
|
|
1419
1456
|
# prompt it took (its own and any merged into it) goes back to its
|
|
1420
1457
|
# sender, who can send it again. The rollback and the announcements are
|
|
@@ -1559,6 +1596,60 @@ module Samagotchi
|
|
|
1559
1596
|
end
|
|
1560
1597
|
end
|
|
1561
1598
|
|
|
1599
|
+
# How long a scratch worker waits for its terminal's first stream
|
|
1600
|
+
# (AttachLauncher attaches within BRIDGE_WAIT of the spawn).
|
|
1601
|
+
SCRATCH_JOIN_GRACE = 30
|
|
1602
|
+
|
|
1603
|
+
# How long a scratch worker's terminal may have no stream open, after
|
|
1604
|
+
# it had one, before it counts as gone: twice the attached terminal's
|
|
1605
|
+
# whole reconnect ladder (TerminalUI::LocalLink#reconnect_delays), so
|
|
1606
|
+
# a reconnect gap (a dropped stream, a slow worker) never reads as a
|
|
1607
|
+
# terminal that left.
|
|
1608
|
+
SCRATCH_GONE_AFTER = 2 * BridgeClient::EventStream::REDISCOVER_DELAYS.sum
|
|
1609
|
+
|
|
1610
|
+
# Whether this is a `chi scratch` session's worker whose terminal is
|
|
1611
|
+
# gone: no terminal stream (a tui: client id's) open for
|
|
1612
|
+
# SCRATCH_GONE_AFTER, after a stream was (a killed TUI's closes as its
|
|
1613
|
+
# writer reads the hang-up), or none came within SCRATCH_JOIN_GRACE.
|
|
1614
|
+
# Any other stream (a web tab's, which chi web refuses for a scratch
|
|
1615
|
+
# session anyway) never keeps it. Its terminal deletes it on every way
|
|
1616
|
+
# out it sees; this is for the ones it doesn't (kill -9, a closed
|
|
1617
|
+
# terminal window).
|
|
1618
|
+
def scratch_unattended?
|
|
1619
|
+
return false unless @session&.scratch && @bridge
|
|
1620
|
+
|
|
1621
|
+
if @bridge.open_streams_of(ClientId::TUI_PREFIX).positive?
|
|
1622
|
+
@unattended_since = nil
|
|
1623
|
+
return false
|
|
1624
|
+
end
|
|
1625
|
+
return monotonic_now - @started_at >= SCRATCH_JOIN_GRACE unless @bridge.streams_served.positive?
|
|
1626
|
+
|
|
1627
|
+
# Set by the first look (the scratch watch or the idle pass) that
|
|
1628
|
+
# finds no stream; a stream back resets it above.
|
|
1629
|
+
@unattended_since ||= monotonic_now
|
|
1630
|
+
monotonic_now - @unattended_since >= SCRATCH_GONE_AFTER
|
|
1631
|
+
end
|
|
1632
|
+
|
|
1633
|
+
def monotonic_now = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
1634
|
+
|
|
1635
|
+
# #leave_idle for a scratch worker its terminal left: checked again with
|
|
1636
|
+
# the event log held, then the intake closes. The session is deleted
|
|
1637
|
+
# once the lock is free (SessionManager.run_session_loop: :scratch_left).
|
|
1638
|
+
# @return [Boolean] false when a client came back since
|
|
1639
|
+
def leave_scratch
|
|
1640
|
+
stop_bridge_after do
|
|
1641
|
+
@engine.synchronize_events do
|
|
1642
|
+
# A turn still running is the scratch watch's to cancel first.
|
|
1643
|
+
next false unless scratch_unattended? && !@engine.turn_running?
|
|
1644
|
+
|
|
1645
|
+
@bridge&.close_intake
|
|
1646
|
+
@engine.stop_idle(join: false)
|
|
1647
|
+
Log.info(:worker, "scratch_left", served: @bridge.streams_served)
|
|
1648
|
+
true
|
|
1649
|
+
end
|
|
1650
|
+
end
|
|
1651
|
+
end
|
|
1652
|
+
|
|
1562
1653
|
# Check again with the event log held, which the Bridge holds while it
|
|
1563
1654
|
# queues a POST /turn, then close the Bridge's intake so no client can
|
|
1564
1655
|
# queue one after the check, and stop the idle jobs (reminder callback,
|
|
@@ -1694,6 +1785,9 @@ module Samagotchi
|
|
|
1694
1785
|
# @return [WorkerIdleExit::Hold, nil]
|
|
1695
1786
|
def exit_hold(client_id, kind:, stop:, ask:)
|
|
1696
1787
|
if kind == :restart
|
|
1788
|
+
# A scratch session's worker ends with its terminal: never restarted.
|
|
1789
|
+
return WorkerIdleExit::Hold.new(reason: :scratch) if @session.scratch
|
|
1790
|
+
|
|
1697
1791
|
hold = @idle_exit.hold_for_restart
|
|
1698
1792
|
return hold && WorkerIdleExit::Hold.new(reason: hold)
|
|
1699
1793
|
end
|
|
@@ -1792,7 +1886,7 @@ module Samagotchi
|
|
|
1792
1886
|
# A restart keeps even an empty session (a new worker takes it over at
|
|
1793
1887
|
# once) and leaves the recap to the conversation's next real pause.
|
|
1794
1888
|
def left(result)
|
|
1795
|
-
deleting = result == :exit_requested && @exit_deletes
|
|
1889
|
+
deleting = (result == :exit_requested && @exit_deletes) || result == :scratch_left
|
|
1796
1890
|
# The attached context goes with this process: a change that landed after
|
|
1797
1891
|
# the leaving pass looked at it has no later pass to note it, so note it
|
|
1798
1892
|
# here (no wake turn: the worker is on its way out). Not into a session
|
|
@@ -1805,7 +1899,7 @@ module Samagotchi
|
|
|
1805
1899
|
# session /exit --delete deletes next: its save could land after the
|
|
1806
1900
|
# delete and write the session back.
|
|
1807
1901
|
@task_wakes.absorb unless deleting
|
|
1808
|
-
return result if result
|
|
1902
|
+
return result if %i[restart scratch_left].include?(result)
|
|
1809
1903
|
|
|
1810
1904
|
@discard = empty_session?
|
|
1811
1905
|
write_recap_on_leave unless @discard || deleting
|
|
@@ -23,9 +23,9 @@ module Samagotchi
|
|
|
23
23
|
# past START_LIMIT without one;
|
|
24
24
|
# - Leaving: the worker closed its Bridge and holds the lock for its last work;
|
|
25
25
|
# - Skew: a worker whose sidecar speaks a newer PROTOCOL than this chi;
|
|
26
|
-
# - Stale: a sidecar, but the lock is free (or a chi
|
|
26
|
+
# - Stale: a sidecar, but the lock is free (or a one-turn chi run holds it, which
|
|
27
27
|
# writes none): its worker died;
|
|
28
|
-
# - None: no worker and no sidecar, or a chi
|
|
28
|
+
# - None: no worker and no sidecar, or a one-turn chi run.
|
|
29
29
|
# A kernel releases a dead worker's lock, so a free lock is the proof of
|
|
30
30
|
# death a TCP probe never gave (a port can be reused by another session's
|
|
31
31
|
# Bridge).
|
|
@@ -80,7 +80,7 @@ module Samagotchi
|
|
|
80
80
|
end
|
|
81
81
|
|
|
82
82
|
# No worker: no sidecar in the session folder, and no worker's lock (a
|
|
83
|
-
# chi
|
|
83
|
+
# one-turn chi run's, +owner+, is no worker's).
|
|
84
84
|
None = Data.define(:owner) do
|
|
85
85
|
def initialize(owner: nil) = super
|
|
86
86
|
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
require_relative "working_set"
|
|
4
4
|
require_relative "working_set_steer"
|
|
5
5
|
require_relative "tools/memory"
|
|
6
|
+
require_relative "session"
|
|
6
7
|
|
|
7
8
|
module Samagotchi
|
|
8
9
|
# /working-set: with no arguments the session's working set (WorkingSet,
|
|
@@ -50,7 +51,7 @@ module Samagotchi
|
|
|
50
51
|
return [listing, [], :ok] if verb.nil?
|
|
51
52
|
raise ArgumentError, USAGE unless VERBS.include?(verb) && !words.empty?
|
|
52
53
|
|
|
53
|
-
session = @engine.session or raise ArgumentError,
|
|
54
|
+
session = @engine.session or raise ArgumentError, Session::NONE_YET
|
|
54
55
|
cwd = session.working_directory
|
|
55
56
|
strategy = @engine.working_set_strategy
|
|
56
57
|
messages = @engine.clone_messages(session.messages)
|
|
@@ -79,7 +80,7 @@ module Samagotchi
|
|
|
79
80
|
# The set under the strategy the next turn runs, and the pending ops.
|
|
80
81
|
def listing
|
|
81
82
|
session = @engine.session
|
|
82
|
-
return
|
|
83
|
+
return Session::NONE_YET unless session
|
|
83
84
|
|
|
84
85
|
messages = Array(session.messages)
|
|
85
86
|
items = WorkingSet.build(messages, cwd: session.working_directory, strategy: @engine.working_set_strategy,
|
data/lib/samagotchi.rb
CHANGED
|
@@ -7,7 +7,6 @@ require_relative "samagotchi/prompt"
|
|
|
7
7
|
require_relative "samagotchi/client"
|
|
8
8
|
require_relative "samagotchi/debug_log"
|
|
9
9
|
require_relative "samagotchi/delivery"
|
|
10
|
-
require_relative "samagotchi/pending_input_queue"
|
|
11
10
|
require_relative "samagotchi/kernel_loop"
|
|
12
11
|
require_relative "samagotchi/session"
|
|
13
12
|
require_relative "samagotchi/terminal_ui"
|
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.154.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Dmitry Dedov
|
|
@@ -185,6 +185,7 @@ files:
|
|
|
185
185
|
- lib/samagotchi/answer_display.rb
|
|
186
186
|
- lib/samagotchi/answer_refs.rb
|
|
187
187
|
- lib/samagotchi/answer_tail.rb
|
|
188
|
+
- lib/samagotchi/answer_text.rb
|
|
188
189
|
- lib/samagotchi/archive_store.rb
|
|
189
190
|
- lib/samagotchi/atomic_file.rb
|
|
190
191
|
- lib/samagotchi/block_renderers.rb
|
|
@@ -335,6 +336,7 @@ files:
|
|
|
335
336
|
- lib/samagotchi/cut.rb
|
|
336
337
|
- lib/samagotchi/cut_policy.rb
|
|
337
338
|
- lib/samagotchi/debug_log.rb
|
|
339
|
+
- lib/samagotchi/degrade.rb
|
|
338
340
|
- lib/samagotchi/delivery.rb
|
|
339
341
|
- lib/samagotchi/desktop.rb
|
|
340
342
|
- lib/samagotchi/desktop/macos.rb
|
|
@@ -356,6 +358,26 @@ files:
|
|
|
356
358
|
- lib/samagotchi/effective_model.rb
|
|
357
359
|
- lib/samagotchi/empty_answer_retry.rb
|
|
358
360
|
- lib/samagotchi/engine.rb
|
|
361
|
+
- lib/samagotchi/engine/cards.rb
|
|
362
|
+
- lib/samagotchi/engine/context_judge.rb
|
|
363
|
+
- lib/samagotchi/engine/events.rb
|
|
364
|
+
- lib/samagotchi/engine/guardrails.rb
|
|
365
|
+
- lib/samagotchi/engine/hooks.rb
|
|
366
|
+
- lib/samagotchi/engine/messages.rb
|
|
367
|
+
- lib/samagotchi/engine/model_settings.rb
|
|
368
|
+
- lib/samagotchi/engine/models.rb
|
|
369
|
+
- lib/samagotchi/engine/objectives.rb
|
|
370
|
+
- lib/samagotchi/engine/participants.rb
|
|
371
|
+
- lib/samagotchi/engine/plugins.rb
|
|
372
|
+
- lib/samagotchi/engine/questions.rb
|
|
373
|
+
- lib/samagotchi/engine/recap.rb
|
|
374
|
+
- lib/samagotchi/engine/session.rb
|
|
375
|
+
- lib/samagotchi/engine/side_requests.rb
|
|
376
|
+
- lib/samagotchi/engine/steering.rb
|
|
377
|
+
- lib/samagotchi/engine/toolkit.rb
|
|
378
|
+
- lib/samagotchi/engine/turn_end.rb
|
|
379
|
+
- lib/samagotchi/engine/turn_helpers.rb
|
|
380
|
+
- lib/samagotchi/engine/verify.rb
|
|
359
381
|
- lib/samagotchi/engine_peers.rb
|
|
360
382
|
- lib/samagotchi/engine_snapshots.rb
|
|
361
383
|
- lib/samagotchi/event_fanout.rb
|
|
@@ -367,6 +389,7 @@ files:
|
|
|
367
389
|
- lib/samagotchi/generation_phase.rb
|
|
368
390
|
- lib/samagotchi/git_env.rb
|
|
369
391
|
- lib/samagotchi/git_head.rb
|
|
392
|
+
- lib/samagotchi/grants.rb
|
|
370
393
|
- lib/samagotchi/guardrail_wiring.rb
|
|
371
394
|
- lib/samagotchi/guardrails.rb
|
|
372
395
|
- lib/samagotchi/guardrails/approval.rb
|
|
@@ -526,11 +549,13 @@ files:
|
|
|
526
549
|
- lib/samagotchi/objectives_audit.rb
|
|
527
550
|
- lib/samagotchi/objectives_check.rb
|
|
528
551
|
- lib/samagotchi/objectives_command.rb
|
|
552
|
+
- lib/samagotchi/objectives_edit.rb
|
|
529
553
|
- lib/samagotchi/output_formatter.rb
|
|
530
554
|
- lib/samagotchi/owner_lock.rb
|
|
531
555
|
- lib/samagotchi/owner_prompt.rb
|
|
532
556
|
- lib/samagotchi/parent_answers_command.rb
|
|
533
557
|
- lib/samagotchi/parent_report.rb
|
|
558
|
+
- lib/samagotchi/participant_exposure.rb
|
|
534
559
|
- lib/samagotchi/participant_messages.rb
|
|
535
560
|
- lib/samagotchi/participant_mode.rb
|
|
536
561
|
- lib/samagotchi/participant_name.rb
|
|
@@ -538,7 +563,6 @@ files:
|
|
|
538
563
|
- lib/samagotchi/participants_watch.rb
|
|
539
564
|
- lib/samagotchi/paths.rb
|
|
540
565
|
- lib/samagotchi/peer_sources.rb
|
|
541
|
-
- lib/samagotchi/pending_input_queue.rb
|
|
542
566
|
- lib/samagotchi/pending_question.rb
|
|
543
567
|
- lib/samagotchi/plugin/api.rb
|
|
544
568
|
- lib/samagotchi/plugin/attached_context.rb
|
|
@@ -557,6 +581,7 @@ files:
|
|
|
557
581
|
- lib/samagotchi/plugin/tool_spec.rb
|
|
558
582
|
- lib/samagotchi/plugin_session_state.rb
|
|
559
583
|
- lib/samagotchi/plugin_tasks.rb
|
|
584
|
+
- lib/samagotchi/private_files.rb
|
|
560
585
|
- lib/samagotchi/process_group.rb
|
|
561
586
|
- lib/samagotchi/project_env.rb
|
|
562
587
|
- lib/samagotchi/project_scope.rb
|
|
@@ -578,6 +603,7 @@ files:
|
|
|
578
603
|
- lib/samagotchi/recap_setup.rb
|
|
579
604
|
- lib/samagotchi/recap_store.rb
|
|
580
605
|
- lib/samagotchi/recap_title.rb
|
|
606
|
+
- lib/samagotchi/redact.rb
|
|
581
607
|
- lib/samagotchi/redacted_inspect.rb
|
|
582
608
|
- lib/samagotchi/ref.rb
|
|
583
609
|
- lib/samagotchi/relay.rb
|
|
@@ -643,6 +669,7 @@ files:
|
|
|
643
669
|
- lib/samagotchi/steer.rb
|
|
644
670
|
- lib/samagotchi/steer_cut.rb
|
|
645
671
|
- lib/samagotchi/steer_cut_after.rb
|
|
672
|
+
- lib/samagotchi/stream_event.rb
|
|
646
673
|
- lib/samagotchi/system_one.rb
|
|
647
674
|
- lib/samagotchi/system_one/answer.rb
|
|
648
675
|
- lib/samagotchi/system_one/approval_label.rb
|
|
@@ -674,7 +701,6 @@ files:
|
|
|
674
701
|
- lib/samagotchi/terminal_ui/attached_loop/queueing.rb
|
|
675
702
|
- lib/samagotchi/terminal_ui/attached_loop/sending.rb
|
|
676
703
|
- lib/samagotchi/terminal_ui/attached_view.rb
|
|
677
|
-
- lib/samagotchi/terminal_ui/between_turns.rb
|
|
678
704
|
- lib/samagotchi/terminal_ui/event_renderer.rb
|
|
679
705
|
- lib/samagotchi/terminal_ui/exit_lines.rb
|
|
680
706
|
- lib/samagotchi/terminal_ui/formatting.rb
|
|
@@ -685,6 +711,7 @@ files:
|
|
|
685
711
|
- lib/samagotchi/terminal_ui/line_reader.rb
|
|
686
712
|
- lib/samagotchi/terminal_ui/live_region.rb
|
|
687
713
|
- lib/samagotchi/terminal_ui/local_link.rb
|
|
714
|
+
- lib/samagotchi/terminal_ui/log_tail.rb
|
|
688
715
|
- lib/samagotchi/terminal_ui/model_segments_text.rb
|
|
689
716
|
- lib/samagotchi/terminal_ui/one_shot_sink.rb
|
|
690
717
|
- lib/samagotchi/terminal_ui/own_turns.rb
|
|
@@ -696,7 +723,6 @@ files:
|
|
|
696
723
|
- lib/samagotchi/terminal_ui/reline_seam.rb
|
|
697
724
|
- lib/samagotchi/terminal_ui/remote_connector.rb
|
|
698
725
|
- lib/samagotchi/terminal_ui/remote_link.rb
|
|
699
|
-
- lib/samagotchi/terminal_ui/repl_input.rb
|
|
700
726
|
- lib/samagotchi/terminal_ui/screen.rb
|
|
701
727
|
- lib/samagotchi/terminal_ui/status_row.rb
|
|
702
728
|
- lib/samagotchi/terminal_ui/surface.rb
|
|
@@ -810,20 +836,17 @@ files:
|
|
|
810
836
|
- lib/samagotchi/web/block_renderer_routes.rb
|
|
811
837
|
- lib/samagotchi/web/capabilities.rb
|
|
812
838
|
- lib/samagotchi/web/editor.rb
|
|
813
|
-
- lib/samagotchi/web/grants.rb
|
|
814
839
|
- lib/samagotchi/web/info_probe.rb
|
|
815
840
|
- lib/samagotchi/web/lan.rb
|
|
816
841
|
- lib/samagotchi/web/link_codes.rb
|
|
817
842
|
- lib/samagotchi/web/markdown_renderer.rb
|
|
818
843
|
- lib/samagotchi/web/message_display.rb
|
|
819
844
|
- lib/samagotchi/web/participant_access.rb
|
|
820
|
-
- lib/samagotchi/web/participant_exposure.rb
|
|
821
845
|
- lib/samagotchi/web/participant_review.rb
|
|
822
846
|
- lib/samagotchi/web/participant_stream_filter.rb
|
|
823
847
|
- lib/samagotchi/web/participant_view.rb
|
|
824
848
|
- lib/samagotchi/web/participants_admin.rb
|
|
825
849
|
- lib/samagotchi/web/principal.rb
|
|
826
|
-
- lib/samagotchi/web/private_files.rb
|
|
827
850
|
- lib/samagotchi/web/project_list.rb
|
|
828
851
|
- lib/samagotchi/web/proxy_gate.rb
|
|
829
852
|
- lib/samagotchi/web/public/activity.js
|
|
@@ -844,6 +867,7 @@ files:
|
|
|
844
867
|
- lib/samagotchi/web/public/block_source.js
|
|
845
868
|
- lib/samagotchi/web/public/bubbles.js
|
|
846
869
|
- lib/samagotchi/web/public/card.js
|
|
870
|
+
- lib/samagotchi/web/public/card_stamps.js
|
|
847
871
|
- lib/samagotchi/web/public/cards_place.js
|
|
848
872
|
- lib/samagotchi/web/public/chains.js
|
|
849
873
|
- lib/samagotchi/web/public/chip_popover.js
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Samagotchi
|
|
4
|
-
# Thread-safe FIFO of user steering messages submitted while a turn is
|
|
5
|
-
# running. UIs (TUI, web, background workers) are push-only producers;
|
|
6
|
-
# KernelLoop drains the queue at iteration boundaries and injects the
|
|
7
|
-
# messages into the conversation. True mid-stream injection is impossible
|
|
8
|
-
# with llama.cpp's /completion API, so draining only happens between full
|
|
9
|
-
# LLM responses / tool dispatches.
|
|
10
|
-
#
|
|
11
|
-
# Usage:
|
|
12
|
-
# queue = PendingInputQueue.new
|
|
13
|
-
# queue.push("please also check the specs")
|
|
14
|
-
# kernel.run(messages, pending_input: queue.method(:drain))
|
|
15
|
-
class PendingInputQueue
|
|
16
|
-
def initialize
|
|
17
|
-
@mutex = Mutex.new
|
|
18
|
-
@messages = []
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
# Append a message to the queue. Nil/empty strings are ignored.
|
|
22
|
-
# +seq+ is the sender's own order number for it (the REPL numbers every
|
|
23
|
-
# line it takes during a turn, so its leftovers keep send order across
|
|
24
|
-
# this queue and its after-turn list: #drain_entries).
|
|
25
|
-
def push(text, seq: nil)
|
|
26
|
-
text = text.to_s
|
|
27
|
-
return if text.empty?
|
|
28
|
-
|
|
29
|
-
@mutex.synchronize { @messages << [seq, text] }
|
|
30
|
-
nil
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
# Remove and return all queued messages in FIFO order. Non-blocking.
|
|
34
|
-
# @return [Array<String>]
|
|
35
|
-
def drain = drain_entries.map(&:last)
|
|
36
|
-
|
|
37
|
-
# #drain with each message's +seq+ (nil when pushed without one).
|
|
38
|
-
# @return [Array(Integer|nil, String)]
|
|
39
|
-
def drain_entries
|
|
40
|
-
@mutex.synchronize do
|
|
41
|
-
drained = @messages
|
|
42
|
-
@messages = []
|
|
43
|
-
drained
|
|
44
|
-
end
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
def empty?
|
|
48
|
-
@mutex.synchronize { @messages.empty? }
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
def size
|
|
52
|
-
@mutex.synchronize { @messages.size }
|
|
53
|
-
end
|
|
54
|
-
end
|
|
55
|
-
end
|
|
@@ -1,138 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require_relative "formatting"
|
|
4
|
-
require_relative "event_renderer"
|
|
5
|
-
|
|
6
|
-
module Samagotchi
|
|
7
|
-
class TerminalUI
|
|
8
|
-
# What the REPL prints between turns: cards and plugins' notices shown
|
|
9
|
-
# outside a turn, anytime commands' output, plugins' init lines and load
|
|
10
|
-
# warnings, and a recap written while idle.
|
|
11
|
-
#
|
|
12
|
-
# They are announced on other threads (the Engine's observers, the idle
|
|
13
|
-
# scheduler, an anytime command's own), where they are only kept; the
|
|
14
|
-
# main thread prints them at the open prompt (#flush_recap,
|
|
15
|
-
# #flush_cards), after the command that showed them. One that comes
|
|
16
|
-
# while a turn runs prints at once (above the live region) where the
|
|
17
|
-
# turn wouldn't print it itself.
|
|
18
|
-
class BetweenTurns
|
|
19
|
-
include Formatting
|
|
20
|
-
|
|
21
|
-
# A plugin's init task and a load warning: shown between turns too.
|
|
22
|
-
INIT_EVENTS = %i[plugin_init_started plugin_init_finished guardrail_warning].freeze
|
|
23
|
-
|
|
24
|
-
# @param surface [Surface] where lines print (swapped with #surface=)
|
|
25
|
-
# @param view [AttachedView] turns the activity row for init tasks
|
|
26
|
-
# @param renderer [EventRenderer] draws cards
|
|
27
|
-
# @param turn_running [#call] whether a turn runs now
|
|
28
|
-
# @param quiet [Boolean] a --non-interactive run: no init lines
|
|
29
|
-
# @param gaps [GapClock, nil] the session's last activity: a recap
|
|
30
|
-
# after a quiet gap has its divider
|
|
31
|
-
def initialize(surface:, view:, renderer:, turn_running:, quiet: false, gaps: nil)
|
|
32
|
-
@surface = surface
|
|
33
|
-
@view = view
|
|
34
|
-
@renderer = renderer
|
|
35
|
-
@turn_running = turn_running
|
|
36
|
-
@quiet = quiet
|
|
37
|
-
@cards = Queue.new
|
|
38
|
-
@recap = nil
|
|
39
|
-
@gaps = gaps
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
attr_writer :surface
|
|
43
|
-
|
|
44
|
-
# The Engine's observer for cards, notices and init events (any
|
|
45
|
-
# thread). A card or a plugin's notice shown outside a turn is kept
|
|
46
|
-
# for the next flush; one shown during a turn is a turn event, the
|
|
47
|
-
# turn's sink prints it where it happens (EventRenderer).
|
|
48
|
-
#
|
|
49
|
-
# An anytime command's (event[:anytime]) print as it shows them: on
|
|
50
|
-
# the main thread (the command runs at the prompt) or beside a running
|
|
51
|
-
# turn, else at the next flush.
|
|
52
|
-
#
|
|
53
|
-
# A plugin's init task (chi.init) turns the activity row while it runs
|
|
54
|
-
# and prints a line when it is done; a load warning announced before
|
|
55
|
-
# the first turn, one. Beside a running turn they print at once.
|
|
56
|
-
def observe(event)
|
|
57
|
-
if INIT_EVENTS.include?(event[:type])
|
|
58
|
-
return if @quiet
|
|
59
|
-
return @view.init_started(event) if event[:type] == :plugin_init_started
|
|
60
|
-
|
|
61
|
-
@view.init_finished(event) if event[:type] == :plugin_init_finished
|
|
62
|
-
return show(event) if turn_running?
|
|
63
|
-
|
|
64
|
-
return @cards << event
|
|
65
|
-
end
|
|
66
|
-
return unless (event[:type] == :card && !event[:in_turn]) || (event[:type] == :hook_notice && event[:between_turns])
|
|
67
|
-
return show(event) if event[:anytime] && (Thread.current == Thread.main || turn_running?)
|
|
68
|
-
|
|
69
|
-
@cards << event
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
# Keep an item for the next flush (any thread).
|
|
73
|
-
def keep(item)
|
|
74
|
-
@cards << item
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
# An anytime command's output: beside a running turn at once, else at
|
|
78
|
-
# the next flush.
|
|
79
|
-
def show_or_keep(item)
|
|
80
|
-
turn_running? ? show(item) : keep(item)
|
|
81
|
-
end
|
|
82
|
-
|
|
83
|
-
# The Engine's observer for :recap_ready (the idle scheduler's thread):
|
|
84
|
-
# kept for #flush_recap. One collected just as a turn started describes
|
|
85
|
-
# the chat before it, and is dropped.
|
|
86
|
-
def take_recap(event)
|
|
87
|
-
return unless event[:type] == :recap_ready
|
|
88
|
-
return if event[:recap].to_s.strip.empty? || turn_running?
|
|
89
|
-
|
|
90
|
-
@recap = { text: event[:recap].to_s, at: event[:created_at] }
|
|
91
|
-
end
|
|
92
|
-
|
|
93
|
-
# Print a recap written while idle (main thread, at the open prompt).
|
|
94
|
-
def flush_recap
|
|
95
|
-
recap = @recap
|
|
96
|
-
return unless recap
|
|
97
|
-
|
|
98
|
-
@recap = nil
|
|
99
|
-
line = @gaps&.divider
|
|
100
|
-
@surface.commit(gap_divider(line)) if line
|
|
101
|
-
@surface.commit(recap_block(recap[:text], at: recap[:at]))
|
|
102
|
-
end
|
|
103
|
-
|
|
104
|
-
# Print the cards, notices and anytime commands' output kept since the
|
|
105
|
-
# last flush (main thread). A card replaced later in the same batch
|
|
106
|
-
# (the same id: btw's "thinking…", then its answer) prints once, as its
|
|
107
|
-
# last.
|
|
108
|
-
def flush_cards
|
|
109
|
-
items = []
|
|
110
|
-
loop { items << @cards.pop(true) }
|
|
111
|
-
rescue ThreadError
|
|
112
|
-
items.each_with_index do |item, index|
|
|
113
|
-
replaced = item[:type] == :card && items.drop(index + 1).any? { |later| later[:type] == :card && later[:id] == item[:id] }
|
|
114
|
-
show(item) unless replaced
|
|
115
|
-
end
|
|
116
|
-
nil
|
|
117
|
-
end
|
|
118
|
-
|
|
119
|
-
# A card, a notice, an anytime command's output (:command_output), a
|
|
120
|
-
# plugin init task's done line or a load warning.
|
|
121
|
-
def show(item)
|
|
122
|
-
case item[:type]
|
|
123
|
-
when :card then @renderer.render_card(item)
|
|
124
|
-
when :command_output then @surface.commit(item[:text])
|
|
125
|
-
when :guardrail_warning then @surface.commit(EventRenderer.load_warning_line(item))
|
|
126
|
-
when :plugin_init_finished
|
|
127
|
-
line = EventRenderer.init_line(item)
|
|
128
|
-
@surface.commit(line) if line
|
|
129
|
-
else @surface.commit(EventRenderer.hook_notice_line(item))
|
|
130
|
-
end
|
|
131
|
-
end
|
|
132
|
-
|
|
133
|
-
private
|
|
134
|
-
|
|
135
|
-
def turn_running? = @turn_running.call
|
|
136
|
-
end
|
|
137
|
-
end
|
|
138
|
-
end
|