samagotchi 0.156.0 → 0.157.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 +44 -1
- data/bin/chi +1 -0
- data/docs/architecture.md +12 -7
- data/docs/bundles.md +3 -1
- data/docs/cli.md +9 -8
- data/docs/configuration.md +36 -4
- data/docs/guardrails.md +9 -5
- data/docs/hooks.md +11 -5
- data/docs/internals/bridge.md +83 -6
- data/docs/internals/bundles.md +28 -18
- data/docs/internals/context-telemetry.md +4 -3
- data/docs/internals/engine.md +16 -2
- data/docs/internals/participants.md +3 -2
- data/docs/internals/remote-sessions.md +5 -2
- data/docs/internals/web-frontend.md +3 -2
- data/docs/internals/working-set.md +1 -1
- data/docs/memory.md +13 -2
- data/docs/plugins.md +35 -2
- data/docs/sessions.md +9 -9
- data/docs/sub-agent.md +17 -2
- data/docs/testing.md +53 -2
- data/lib/samagotchi/answer_command.rb +2 -1
- data/lib/samagotchi/archive_store.rb +4 -3
- data/lib/samagotchi/bootstrap_command.rb +3 -2
- data/lib/samagotchi/bridge/card_places.rb +10 -4
- data/lib/samagotchi/bridge/card_store.rb +3 -0
- data/lib/samagotchi/bridge/turn_accumulator.rb +109 -9
- data/lib/samagotchi/bridge/turn_drawings.rb +265 -0
- data/lib/samagotchi/bridge.rb +31 -6
- data/lib/samagotchi/broadcast/recipients.rb +8 -8
- data/lib/samagotchi/broadcast/triage_model.rb +1 -1
- data/lib/samagotchi/bundle_command/check.rb +18 -0
- data/lib/samagotchi/bundle_command/try/sandbox.rb +1 -1
- data/lib/samagotchi/bundle_command/try/trace.rb +1 -1
- data/lib/samagotchi/bundle_command.rb +5 -2
- data/lib/samagotchi/bundles/known-names/manifest.yml +4 -7
- data/lib/samagotchi/bundles/known-names/{hooks/known_names.rb → plugin.rb} +17 -0
- data/lib/samagotchi/bundles/source-links/manifest.yml +4 -7
- data/lib/samagotchi/bundles/source-links/{hooks/source_links.rb → plugin.rb} +23 -4
- data/lib/samagotchi/bundles/system/manifest.yml +2 -2
- data/lib/samagotchi/bundles/system/memory_guide.md +1 -1
- data/lib/samagotchi/child_move.rb +6 -6
- data/lib/samagotchi/child_reports.rb +2 -2
- data/lib/samagotchi/children_status.rb +15 -21
- data/lib/samagotchi/cli/parent_wait.rb +8 -22
- data/lib/samagotchi/config.rb +3 -0
- data/lib/samagotchi/context_sources.rb +5 -4
- data/lib/samagotchi/context_window.rb +9 -12
- data/lib/samagotchi/effective_model.rb +57 -22
- data/lib/samagotchi/engine/plugins.rb +1 -1
- data/lib/samagotchi/engine/recap.rb +8 -4
- data/lib/samagotchi/engine.rb +29 -3
- data/lib/samagotchi/events.rb +3 -2
- data/lib/samagotchi/extension_load.rb +6 -3
- data/lib/samagotchi/guardrails_command.rb +1 -1
- data/lib/samagotchi/host_address.rb +52 -0
- data/lib/samagotchi/host_registry.rb +57 -45
- data/lib/samagotchi/kernel_loop.rb +7 -3
- data/lib/samagotchi/llm/chat_loop.rb +6 -3
- data/lib/samagotchi/llm_context_strategy.rb +27 -63
- data/lib/samagotchi/memory_bundle/asset_installer.rb +71 -76
- data/lib/samagotchi/memory_bundle/builder.rb +2 -1
- data/lib/samagotchi/memory_bundle/file_actions.rb +193 -0
- data/lib/samagotchi/memory_bundle/file_digest.rb +13 -0
- data/lib/samagotchi/memory_bundle/file_state.rb +152 -0
- data/lib/samagotchi/memory_bundle/installed_copy.rb +2 -1
- data/lib/samagotchi/memory_bundle/installed_manifest.rb +8 -1
- data/lib/samagotchi/memory_bundle/installer.rb +185 -169
- data/lib/samagotchi/memory_bundle/manifest.rb +14 -4
- data/lib/samagotchi/memory_bundle/merger.rb +69 -65
- data/lib/samagotchi/memory_bundle/plugin_ref.rb +6 -5
- data/lib/samagotchi/memory_bundle/profile.rb +5 -5
- data/lib/samagotchi/memory_bundle/provenance.rb +15 -1
- data/lib/samagotchi/memory_bundle/remerge.rb +25 -12
- data/lib/samagotchi/memory_bundle/shipped_update.rb +51 -6
- data/lib/samagotchi/memory_bundle/status.rb +14 -20
- data/lib/samagotchi/memory_bundle/system_bundle.rb +24 -6
- data/lib/samagotchi/memory_bundle/trash.rb +23 -8
- data/lib/samagotchi/memory_bundle/uninstaller.rb +16 -11
- data/lib/samagotchi/memory_usage.rb +1 -1
- data/lib/samagotchi/model_lookup.rb +75 -0
- data/lib/samagotchi/model_profile.rb +1 -0
- data/lib/samagotchi/models_command.rb +1 -1
- data/lib/samagotchi/note_command.rb +1 -1
- data/lib/samagotchi/participant_mode.rb +2 -1
- data/lib/samagotchi/plugin/api.rb +41 -6
- data/lib/samagotchi/plugin/loader.rb +33 -10
- data/lib/samagotchi/plugin/sessions.rb +1 -1
- data/lib/samagotchi/reasoning_history.rb +14 -20
- data/lib/samagotchi/recap_place.rb +27 -0
- data/lib/samagotchi/reply_wait/liveness.rb +38 -0
- data/lib/samagotchi/reply_wait/poll.rb +44 -15
- data/lib/samagotchi/reply_wait/target.rb +113 -0
- data/lib/samagotchi/reply_wait.rb +22 -2
- data/lib/samagotchi/sampling_settings.rb +9 -16
- data/lib/samagotchi/self_report.rb +34 -35
- data/lib/samagotchi/send_command.rb +17 -23
- data/lib/samagotchi/session.rb +321 -439
- data/lib/samagotchi/session_access/local.rb +5 -6
- data/lib/samagotchi/session_access/remote.rb +5 -3
- data/lib/samagotchi/session_field.rb +133 -0
- data/lib/samagotchi/session_inbox.rb +49 -1
- data/lib/samagotchi/session_manager/emptiness.rb +2 -1
- data/lib/samagotchi/session_manager/listing.rb +29 -100
- data/lib/samagotchi/session_manager.rb +2 -1
- data/lib/samagotchi/session_metrics.rb +7 -4
- data/lib/samagotchi/session_paths.rb +57 -0
- data/lib/samagotchi/session_retention.rb +2 -2
- data/lib/samagotchi/session_row.rb +200 -0
- data/lib/samagotchi/session_setup.rb +15 -12
- data/lib/samagotchi/sessions_command.rb +11 -129
- data/lib/samagotchi/steer_cut_after.rb +7 -14
- data/lib/samagotchi/terminal_ui/attached_loop.rb +6 -26
- data/lib/samagotchi/terminal_ui/join_replay.rb +86 -8
- data/lib/samagotchi/terminal_ui/local_link.rb +2 -2
- data/lib/samagotchi/terminal_ui.rb +3 -1
- data/lib/samagotchi/testing/install.rb +2 -1
- data/lib/samagotchi/thinking.rb +16 -21
- data/lib/samagotchi/tool_response.rb +5 -3
- data/lib/samagotchi/tool_runner.rb +18 -1
- data/lib/samagotchi/tools/delegate.rb +48 -43
- data/lib/samagotchi/tools/delegate_relay.rb +5 -5
- data/lib/samagotchi/tools/delegate_result.rb +1 -1
- data/lib/samagotchi/tools/delegate_wait.rb +41 -17
- data/lib/samagotchi/tools/list_sessions.rb +7 -7
- data/lib/samagotchi/update_command.rb +11 -7
- data/lib/samagotchi/verify_fresh.rb +7 -11
- data/lib/samagotchi/version.rb +1 -1
- data/lib/samagotchi/vision_support.rb +11 -14
- data/lib/samagotchi/web/app.rb +31 -21
- data/lib/samagotchi/web/message_display.rb +57 -7
- data/lib/samagotchi/web/participant_access.rb +1 -1
- data/lib/samagotchi/web/public/activity.js +16 -7
- data/lib/samagotchi/web/public/app.js +29 -8
- data/lib/samagotchi/web/public/bubbles.js +8 -3
- data/lib/samagotchi/web/public/cards_place.js +15 -0
- data/lib/samagotchi/web/public/commands.js +5 -1
- data/lib/samagotchi/web/public/data.js +4 -2
- data/lib/samagotchi/web/public/history_shape.js +220 -0
- data/lib/samagotchi/web/public/recap_stamp.js +17 -0
- data/lib/samagotchi/web/public/reload_check.js +71 -0
- data/lib/samagotchi/web/public/stage_model.js +7 -5
- data/lib/samagotchi/web/public/stage_view.js +7 -3
- data/lib/samagotchi/web/public/stream_handlers.js +8 -2
- data/lib/samagotchi/web/public/timing.js +43 -2
- data/lib/samagotchi/web/public/turn_block.js +215 -30
- data/lib/samagotchi/web/public/turn_drawing.js +43 -0
- data/lib/samagotchi/web/public/turn_events.js +10 -1
- data/lib/samagotchi/web/public/turn_pieces.js +29 -0
- data/lib/samagotchi/web/reload_check_route.rb +95 -0
- data/lib/samagotchi/web/server.rb +4 -2
- data/lib/samagotchi/web/session_access_routes.rb +3 -3
- data/lib/samagotchi/web/session_control.rb +1 -1
- data/lib/samagotchi/web/session_hub.rb +9 -17
- data/lib/samagotchi/web/session_show.rb +64 -2
- data/lib/samagotchi/web/session_summary.rb +36 -24
- data/lib/samagotchi/worker.rb +28 -5
- data/lib/samagotchi/worker_link.rb +3 -0
- metadata +20 -4
- data/lib/samagotchi/send_command/wait_target.rb +0 -85
|
@@ -5,7 +5,8 @@ require_relative "session"
|
|
|
5
5
|
require_relative "archive_store"
|
|
6
6
|
require_relative "git_head"
|
|
7
7
|
require_relative "reply_wait"
|
|
8
|
-
require_relative "
|
|
8
|
+
require_relative "owner_lock"
|
|
9
|
+
require_relative "session_row"
|
|
9
10
|
require_relative "tools/delegate"
|
|
10
11
|
require_relative "tools/delegate_cursor"
|
|
11
12
|
|
|
@@ -50,44 +51,47 @@ module Samagotchi
|
|
|
50
51
|
def of(parent_id, state_dir:, include_archived: false)
|
|
51
52
|
cursors = Tools::DelegateCursors.read(parent_id, state_dir: state_dir)
|
|
52
53
|
SessionManager.children_of(parent_id, state_dir: state_dir).filter_map do |row|
|
|
53
|
-
next if row
|
|
54
|
+
next if row.archived && !include_archived
|
|
54
55
|
|
|
55
|
-
session = load(row
|
|
56
|
+
session = load(row.id, state_dir: state_dir)
|
|
56
57
|
session && child(session, row, cursors, state_dir: state_dir)
|
|
57
58
|
end
|
|
58
59
|
end
|
|
59
60
|
|
|
60
61
|
# The cheap path for the glance views: only the children in the
|
|
61
|
-
# parent's delegates.json (one Session.load and
|
|
62
|
+
# parent's delegates.json (one Session.load and a SessionRow each, no
|
|
62
63
|
# scan). Its keys can also name a fork the model passed to delegate
|
|
63
64
|
# session: or a deleted child: only live delegates of this parent count,
|
|
64
65
|
# archived ones don't.
|
|
65
66
|
# @return [Counts]
|
|
66
67
|
def counts(parent_id, state_dir:)
|
|
67
68
|
cursors = Tools::DelegateCursors.read(parent_id, state_dir: state_dir)
|
|
69
|
+
budgets = SessionRow.budgets
|
|
68
70
|
children = cursors.keys.filter_map do |id|
|
|
69
71
|
session = load(id, state_dir: state_dir)
|
|
70
72
|
next unless session&.delegate? && session.parent_id == parent_id
|
|
71
73
|
next if ArchiveStore.archived?(Session.session_dir(id, state_dir: state_dir))
|
|
72
74
|
|
|
73
|
-
|
|
75
|
+
dir = Session.session_dir(id, state_dir: state_dir)
|
|
76
|
+
child(session, SessionRow.build(session, session_dir: dir, owner: OwnerLock.owner(dir), budgets: budgets), cursors,
|
|
77
|
+
state_dir: state_dir)
|
|
74
78
|
end
|
|
75
79
|
Counts.new(running: children.count { |c| c.state == "running" },
|
|
76
80
|
waiting: children.count { |c| c.state == "waiting" },
|
|
77
81
|
unreported: children.count { |c| c.last_reply && !c.reported })
|
|
78
82
|
end
|
|
79
83
|
|
|
80
|
-
# @param row [
|
|
84
|
+
# @param row [SessionRow] the child's row
|
|
81
85
|
# @param cursors [Hash] the parent's delegates.json
|
|
82
86
|
def child(session, row, cursors, state_dir:)
|
|
83
87
|
reply = ReplyWait.newest_reply(session.id, state_dir: state_dir)
|
|
84
88
|
cursor = Tools::DelegateCursors.get_from(cursors, session.id)
|
|
85
|
-
Child.new(id: session.id, short_id: session.id[0, 8], title: (session.title || row
|
|
86
|
-
state: state_of(session, row, reply), waiting: row
|
|
89
|
+
Child.new(id: session.id, short_id: session.id[0, 8], title: (session.title || row.preview).to_s,
|
|
90
|
+
state: state_of(session, row, reply), waiting: row.waiting, live: !!row.live,
|
|
87
91
|
delegate: session.delegate?, cwd: session.working_directory, branch: GitHead.branch(session.working_directory),
|
|
88
92
|
last_reply: reply && first_line(session.id, reply, state_dir: state_dir),
|
|
89
93
|
last_reply_at: reply && reply_time(reply), reported: !reply.nil? && reported?(session, cursor, reply),
|
|
90
|
-
updated_at: session.updated_at, archived: !!row
|
|
94
|
+
updated_at: session.updated_at, archived: !!row.archived)
|
|
91
95
|
end
|
|
92
96
|
private_class_method :child
|
|
93
97
|
|
|
@@ -97,8 +101,8 @@ module Samagotchi
|
|
|
97
101
|
private_class_method :reported?
|
|
98
102
|
|
|
99
103
|
def state_of(session, row, reply)
|
|
100
|
-
return "waiting" if row
|
|
101
|
-
return "running" if
|
|
104
|
+
return "waiting" if row.waiting
|
|
105
|
+
return "running" if row.running_or_starting?
|
|
102
106
|
return "stopped" if session.status == Session::STATUS_STOPPED
|
|
103
107
|
|
|
104
108
|
outcome = session.last_turn&.outcome
|
|
@@ -109,16 +113,6 @@ module Samagotchi
|
|
|
109
113
|
end
|
|
110
114
|
private_class_method :state_of
|
|
111
115
|
|
|
112
|
-
# The keys of a children_of row that state_of and child read, for a
|
|
113
|
-
# session counts loaded itself.
|
|
114
|
-
def summary_of(session, state_dir:)
|
|
115
|
-
live = WorkerLink.resolve(Session.session_dir(session.id, state_dir: state_dir), unlink: false).worker_owned?
|
|
116
|
-
{ live: live, busy: live && session.status == Session::STATUS_RUNNING, saved_status: session.status,
|
|
117
|
-
updated_at: session.updated_at, waiting: session.waiting_question(live: live)&.dig(:kind),
|
|
118
|
-
preview: session.last_prompt.to_s }
|
|
119
|
-
end
|
|
120
|
-
private_class_method :summary_of
|
|
121
|
-
|
|
122
116
|
def first_line(id, file, state_dir:)
|
|
123
117
|
text = File.read(File.join(ReplyWait.reply_dir(id, state_dir: state_dir), file), 4096)
|
|
124
118
|
text.each_line.map(&:strip).find { |line| !line.empty? }.to_s
|
|
@@ -17,9 +17,6 @@ module Samagotchi
|
|
|
17
17
|
# override the constants (specs stub them on the class).
|
|
18
18
|
module ParentWait
|
|
19
19
|
POLL_INTERVAL = ReplyWait::POLL_INTERVAL
|
|
20
|
-
# No live worker this long while waiting: it died before it could mark
|
|
21
|
-
# the session (a worker takes well under a second to start).
|
|
22
|
-
WORKER_GONE_AFTER = 5
|
|
23
20
|
FORMATS = %w[text json].freeze
|
|
24
21
|
|
|
25
22
|
# @return [Integer] the exit status
|
|
@@ -59,26 +56,15 @@ module Samagotchi
|
|
|
59
56
|
nil
|
|
60
57
|
end
|
|
61
58
|
|
|
62
|
-
# Wait for
|
|
63
|
-
#
|
|
64
|
-
# @param
|
|
65
|
-
#
|
|
66
|
-
#
|
|
67
|
-
# (ReplyWait's turn:): a queued message's, or the turn an answer or
|
|
68
|
-
# a --wait with no message is about (ReplyWait.own_turn)
|
|
69
|
-
# @param queued [Boolean] +turn+ is a queued message's (ReplyWait's
|
|
70
|
-
# queued:)
|
|
71
|
-
# @param ended_before [Boolean] a last_turn that ended before the
|
|
72
|
-
# baseline is the answer (ReplyWait's ended_before:) — the
|
|
73
|
-
# --wait-with-no-message's settled session
|
|
74
|
-
# @param report_turn_id [String, nil] the turn id to include in the
|
|
75
|
-
# report, even when ReplyWait uses the next-reply path
|
|
59
|
+
# Wait for what +target+ binds (ReplyWait) and report it. Ctrl-C
|
|
60
|
+
# leaves the turn running (130).
|
|
61
|
+
# @param target [ReplyWait::Target] which turn, from the cursor and
|
|
62
|
+
# baseline prepare_wait read; its report_turn_id is the turn id the
|
|
63
|
+
# report names, even when ReplyWait takes the next reply
|
|
76
64
|
# @return [Integer] the exit status
|
|
77
|
-
def wait_for_reply(id,
|
|
78
|
-
|
|
79
|
-
result = @access.wait_reply(id,
|
|
80
|
-
poll_interval: self.class::POLL_INTERVAL, turn: turn, queued: queued,
|
|
81
|
-
ended_before: ended_before)
|
|
65
|
+
def wait_for_reply(id, target:, timeout:)
|
|
66
|
+
report_turn_id = target.report_turn_id
|
|
67
|
+
result = @access.wait_reply(id, **target.to_h, timeout: timeout, poll_interval: self.class::POLL_INTERVAL)
|
|
82
68
|
result.turn_id = report_turn_id if report_turn_id && !report_turn_id.to_s.empty?
|
|
83
69
|
result.text = result.text&.dup&.force_encoding(Encoding::UTF_8)&.scrub
|
|
84
70
|
@reported = true
|
data/lib/samagotchi/config.rb
CHANGED
|
@@ -373,6 +373,9 @@ module Samagotchi
|
|
|
373
373
|
# The stage view's working set (files, memories and URLs the turn brought into context): a rail in the stage, a
|
|
374
374
|
# footprint under each finished turn and a "set N" chip in place of the mem chip; ?working_set=1|0 overrides it per page load.
|
|
375
375
|
Entry.new(key: "web.working_set", yaml_path: %w[web working_set], type: :bool, default: true, expose: %i[env config cli], lifecycle: :web_start),
|
|
376
|
+
# Opt-in: the page checks each finished turn against a reload of it (one full read per turn end) and chi web logs
|
|
377
|
+
# reload_checked, with reload_mismatch and the kinds that differed (counts only, no content).
|
|
378
|
+
Entry.new(key: "web.reload_check", yaml_path: %w[web reload_check], type: :bool, default: false, expose: %i[env config cli], lifecycle: :web_start),
|
|
376
379
|
# Quick replies next to Annotate in the page's selection bubble, "|"-separated (a YAML list works too); "" leaves only Annotate.
|
|
377
380
|
Entry.new(key: "web.annotate_presets", yaml_path: %w[web annotate_presets], type: :string, default: "Agreed|Could you please elaborate?", expose: %i[env config cli], lifecycle: :web_start),
|
|
378
381
|
# What a file ref (a tool row's file, a diff line) opens on this machine: a preset (vscode, vscode-insiders, cursor, zed, none) or a URL template with {path} and an optional {line} (Web::Editor).
|
|
@@ -7,6 +7,7 @@ require "time"
|
|
|
7
7
|
require_relative "atomic_file"
|
|
8
8
|
require_relative "memory_paths"
|
|
9
9
|
require_relative "paths"
|
|
10
|
+
require_relative "session_paths"
|
|
10
11
|
require_relative "session"
|
|
11
12
|
|
|
12
13
|
module Samagotchi
|
|
@@ -617,13 +618,13 @@ module Samagotchi
|
|
|
617
618
|
nil
|
|
618
619
|
end
|
|
619
620
|
|
|
620
|
-
# <state dir>/context; +state_dir+ is the sessions dir (
|
|
621
|
+
# <state dir>/context; +state_dir+ is the sessions dir (SessionPaths.default_state_dir).
|
|
621
622
|
def root(state_dir: nil)
|
|
622
|
-
File.join(File.dirname(state_dir ||
|
|
623
|
+
File.join(File.dirname(state_dir || SessionPaths.default_state_dir), DIR)
|
|
623
624
|
end
|
|
624
625
|
|
|
625
626
|
def session_location(session_id, state_dir: nil)
|
|
626
|
-
Location.new(scope: "session", dir: File.join(root(state_dir: state_dir), "sessions",
|
|
627
|
+
Location.new(scope: "session", dir: File.join(root(state_dir: state_dir), "sessions", SessionPaths.check_id!(session_id)),
|
|
627
628
|
key: session_id)
|
|
628
629
|
end
|
|
629
630
|
|
|
@@ -669,7 +670,7 @@ module Samagotchi
|
|
|
669
670
|
# A deleted session's sources, snapshots, subscriptions and markers.
|
|
670
671
|
# @return [Array<String>] the paths removed
|
|
671
672
|
def remove_session(session_id, state_dir: nil)
|
|
672
|
-
return [] unless
|
|
673
|
+
return [] unless SessionPaths.valid_id?(session_id.to_s)
|
|
673
674
|
|
|
674
675
|
dir = session_location(session_id, state_dir: state_dir).dir
|
|
675
676
|
return [] unless Dir.exist?(dir)
|
|
@@ -11,14 +11,14 @@ module Samagotchi
|
|
|
11
11
|
# provider's context_length)
|
|
12
12
|
# 3. models.<key>.window_tokens, else hosts.<name>.window_tokens
|
|
13
13
|
# (#setting: the most specific wins)
|
|
14
|
-
# 4. context.window_tokens (
|
|
15
|
-
# config file)
|
|
14
|
+
# 4. context.window_tokens (--context-window-tokens,
|
|
15
|
+
# SAMAGOTCHI_CONTEXT_WINDOW_TOKENS or the config file)
|
|
16
16
|
# 5. DEFAULT_TOKENS
|
|
17
17
|
# Settings (3 and 4) only fill in when the server and its list report
|
|
18
18
|
# nothing.
|
|
19
19
|
#
|
|
20
|
-
# Sources: :server, :model_list, :model_setting, :host_setting, :
|
|
21
|
-
# (
|
|
20
|
+
# Sources: :server, :model_list, :model_setting, :host_setting, :cli,
|
|
21
|
+
# :env, :config (the file), :default.
|
|
22
22
|
module ContextWindow
|
|
23
23
|
DEFAULT_TOKENS = 256_000
|
|
24
24
|
|
|
@@ -48,16 +48,13 @@ module Samagotchi
|
|
|
48
48
|
# The window config.yml gives this model or its host:
|
|
49
49
|
# models.<key>.window_tokens (by the model's lookup names, as sampling
|
|
50
50
|
# and vision look a model up), else hosts.<name>.window_tokens.
|
|
51
|
-
# @param
|
|
52
|
-
# @param names [Array<String>] HostRegistry#lookup_names
|
|
53
|
-
# @param models [Hash{String => ModelSettings}, nil] ModelSettings.all (specs)
|
|
51
|
+
# @param lookup [ModelLookup] the model's layers (EffectiveModel#lookup)
|
|
54
52
|
# @return [Resolved, nil]
|
|
55
|
-
def setting(
|
|
56
|
-
|
|
57
|
-
tokens = ModelSettings.find(names, :window_tokens, models: models)&.value
|
|
53
|
+
def setting(lookup)
|
|
54
|
+
tokens = lookup.model(:window_tokens)&.value
|
|
58
55
|
return Resolved.new(tokens: tokens, source: :model_setting) if positive_integer?(tokens)
|
|
59
56
|
|
|
60
|
-
tokens =
|
|
57
|
+
tokens = lookup.host(:window_tokens)
|
|
61
58
|
positive_integer?(tokens) ? Resolved.new(tokens: tokens, source: :host_setting) : nil
|
|
62
59
|
rescue StandardError
|
|
63
60
|
nil
|
|
@@ -79,7 +76,7 @@ module Samagotchi
|
|
|
79
76
|
end
|
|
80
77
|
return Resolved.new(tokens: DEFAULT_TOKENS, source: :default) unless positive_integer?(value)
|
|
81
78
|
|
|
82
|
-
Resolved.new(tokens: value, source:
|
|
79
|
+
Resolved.new(tokens: value, source: { cli: :cli, env: :env }.fetch(origin, :config))
|
|
83
80
|
end
|
|
84
81
|
|
|
85
82
|
# For callers with no client at hand (tool output guardrails): the last
|
|
@@ -4,6 +4,7 @@ require_relative "host_registry"
|
|
|
4
4
|
require_relative "log"
|
|
5
5
|
require_relative "context_window"
|
|
6
6
|
require_relative "llm_context_strategy"
|
|
7
|
+
require_relative "model_lookup"
|
|
7
8
|
require_relative "model_profile"
|
|
8
9
|
require_relative "reasoning_history"
|
|
9
10
|
require_relative "sampling_settings"
|
|
@@ -22,7 +23,8 @@ module Samagotchi
|
|
|
22
23
|
|
|
23
24
|
# The effective model resolved once (HostRegistry#resolve: its host and
|
|
24
25
|
# client, the id sent) with the names its models: entry may be under
|
|
25
|
-
# (HostRegistry#lookup_names), and its settings read from them
|
|
26
|
+
# (HostRegistry#lookup_names), and its settings read from them through
|
|
27
|
+
# one ModelLookup (every layer's input, with the registry's env). An
|
|
26
28
|
# immutable snapshot built per read, never kept across reads: config.yml,
|
|
27
29
|
# a model listing (which may move a bare id to another host) and another
|
|
28
30
|
# process's saved lists all change what a resolve gives without any
|
|
@@ -32,14 +34,17 @@ module Samagotchi
|
|
|
32
34
|
# Engine has always given (Unresolved); building one raises as
|
|
33
35
|
# HostRegistry#resolve does (SessionModelSettings#model_setting gives the
|
|
34
36
|
# fallback then).
|
|
35
|
-
EffectiveModel = Data.define(:registry, :name, :typed, :target, :names) do
|
|
37
|
+
EffectiveModel = Data.define(:registry, :name, :typed, :target, :names, :lookup) do
|
|
36
38
|
# @param registry [HostRegistry]
|
|
37
39
|
# @param choice [ModelChoice]
|
|
40
|
+
# @param models [Hash{String => ModelSettings}, nil] one models: map for
|
|
41
|
+
# many models (a picker); ModelSettings.all at each read by default
|
|
38
42
|
# @raise what HostRegistry#resolve raises
|
|
39
|
-
def self.of(registry, choice)
|
|
43
|
+
def self.of(registry, choice, models: nil)
|
|
40
44
|
target = registry.resolve(choice.name)
|
|
41
|
-
|
|
42
|
-
|
|
45
|
+
names = registry.lookup_names(choice.typed, resolved: choice.name, target: target)
|
|
46
|
+
new(registry: registry, name: choice.name, typed: choice.typed, target: target, names: names,
|
|
47
|
+
lookup: ModelLookup.for(target, names: names, models: models, env: registry.env))
|
|
43
48
|
end
|
|
44
49
|
|
|
45
50
|
# A saved session's model (no worker): its model name, the default when
|
|
@@ -50,6 +55,34 @@ module Samagotchi
|
|
|
50
55
|
of(registry, ModelChoice.new(name: name, typed: session.model_typed || name))
|
|
51
56
|
end
|
|
52
57
|
|
|
58
|
+
# A saved session's LLM context strategy, apply rule and budget, each
|
|
59
|
+
# with where it came from (LLMContextStrategy::Explained#summary), as
|
|
60
|
+
# its worker would resolve them; nil when they can't be (an unreadable
|
|
61
|
+
# config, a model that resolves nowhere). From config and the registry
|
|
62
|
+
# only: no network, no model call. What a session page, a session
|
|
63
|
+
# list's ctx % and a spawn-time check all read.
|
|
64
|
+
# @param session [Session, nil]
|
|
65
|
+
# @param registry [HostRegistry, nil] the hosts to resolve against;
|
|
66
|
+
# HostRegistry.current by default
|
|
67
|
+
# @return [Hash, nil] Explained#summary, symbol keys
|
|
68
|
+
def self.session_llm_context(session, registry: nil)
|
|
69
|
+
return nil if session.nil?
|
|
70
|
+
|
|
71
|
+
own = session.llm_context
|
|
72
|
+
of_session(session, registry: registry || HostRegistry.current).llm_context_explained(own&.resolve_args || {})&.summary(own)
|
|
73
|
+
rescue StandardError # degrade-ok: a saved session's model that resolves nowhere has no budget to show; the readers log their own
|
|
74
|
+
nil
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# The budget a saved session's turns run under
|
|
78
|
+
# (.session_llm_context's :budget_tokens), nil when it is off or can't
|
|
79
|
+
# be resolved. What a session list's ctx % counts against, so a saved
|
|
80
|
+
# session's fill reads as the live meter.
|
|
81
|
+
# @return [Integer, nil]
|
|
82
|
+
def self.session_budget(session, registry: nil)
|
|
83
|
+
session_llm_context(session, registry: registry)&.fetch(:budget_tokens, nil)
|
|
84
|
+
end
|
|
85
|
+
|
|
53
86
|
def entry = target.entry
|
|
54
87
|
def client = target.client
|
|
55
88
|
def bare = target.bare_model
|
|
@@ -63,21 +96,21 @@ module Samagotchi
|
|
|
63
96
|
|
|
64
97
|
# The configured request parameters (hosts: and models: sampling).
|
|
65
98
|
def sampling
|
|
66
|
-
SamplingSettings.for(
|
|
99
|
+
SamplingSettings.for(lookup)
|
|
67
100
|
rescue StandardError => e
|
|
68
101
|
unresolved(:sampling_unresolved, e, SamplingSettings::EMPTY)
|
|
69
102
|
end
|
|
70
103
|
|
|
71
104
|
# "temperature=0.6 (hosts.work)", nil when none.
|
|
72
105
|
def sampling_summary
|
|
73
|
-
SamplingSettings.summary(
|
|
106
|
+
SamplingSettings.summary(lookup)
|
|
74
107
|
rescue StandardError => e
|
|
75
108
|
unresolved(:sampling_unresolved, e, nil)
|
|
76
109
|
end
|
|
77
110
|
|
|
78
111
|
# The thinking level (Thinking.resolve), the session's +own+ first.
|
|
79
112
|
def thinking(own:)
|
|
80
|
-
Thinking.resolve(
|
|
113
|
+
Thinking.resolve(lookup, session: own).first
|
|
81
114
|
rescue StandardError => e
|
|
82
115
|
unresolved(:thinking_unresolved, e, Thinking::DEFAULT)
|
|
83
116
|
end
|
|
@@ -85,23 +118,25 @@ module Samagotchi
|
|
|
85
118
|
# The thinking level with where it came from (SettingExplained), nil
|
|
86
119
|
# when it can't be resolved.
|
|
87
120
|
def thinking_explained(own:)
|
|
88
|
-
Thinking.explain(
|
|
121
|
+
Thinking.explain(lookup, session: own)
|
|
89
122
|
rescue StandardError => e
|
|
90
123
|
unresolved(:thinking_unresolved, e, nil)
|
|
91
124
|
end
|
|
92
125
|
|
|
93
126
|
# What a thinking level change costs the prompt cache
|
|
94
127
|
# (Thinking.cache_cost); the block gives the prompt profile, asked only
|
|
95
|
-
# on a native host. Raises.
|
|
128
|
+
# on a native host; a local chat host's is the one its name says. Raises.
|
|
96
129
|
# @return [Symbol]
|
|
97
130
|
def thinking_cache_cost(&)
|
|
98
|
-
Thinking.cache_cost(target,
|
|
131
|
+
return Thinking.cache_cost(target, inferred: ModelProfile.inferred_profile_name(bare)) if entry&.chat?
|
|
132
|
+
|
|
133
|
+
Thinking.cache_cost(target, profile: yield&.name)
|
|
99
134
|
end
|
|
100
135
|
|
|
101
136
|
# The reasoning_history level (ReasoningHistory.resolve), the session's
|
|
102
137
|
# +own+ first.
|
|
103
138
|
def reasoning_history(own:)
|
|
104
|
-
ReasoningHistory.resolve(
|
|
139
|
+
ReasoningHistory.resolve(lookup, session: own).first
|
|
105
140
|
rescue StandardError => e
|
|
106
141
|
unresolved(:reasoning_history_unresolved, e, ReasoningHistory::DEFAULT)
|
|
107
142
|
end
|
|
@@ -112,7 +147,7 @@ module Samagotchi
|
|
|
112
147
|
def reasoning_history_explained(own:, native: false)
|
|
113
148
|
return nil unless native || entry&.chat?
|
|
114
149
|
|
|
115
|
-
ReasoningHistory.explain(
|
|
150
|
+
ReasoningHistory.explain(lookup, session: own)
|
|
116
151
|
rescue StandardError => e
|
|
117
152
|
unresolved(:reasoning_history_unresolved, e, nil)
|
|
118
153
|
end
|
|
@@ -122,7 +157,7 @@ module Samagotchi
|
|
|
122
157
|
def reasoning_history_summary(own:)
|
|
123
158
|
return nil unless entry&.chat?
|
|
124
159
|
|
|
125
|
-
level, source = ReasoningHistory.resolve(
|
|
160
|
+
level, source = ReasoningHistory.resolve(lookup, session: own)
|
|
126
161
|
source ? ReasoningHistory.label(level, source) : nil
|
|
127
162
|
rescue StandardError => e
|
|
128
163
|
unresolved(:reasoning_history_unresolved, e, nil)
|
|
@@ -139,7 +174,7 @@ module Samagotchi
|
|
|
139
174
|
# [seconds, source] a cut waits for thinking (SteerCutAfter.resolve);
|
|
140
175
|
# the global and its name when it can't be resolved.
|
|
141
176
|
def steer_cut_after_explained
|
|
142
|
-
SteerCutAfter.resolve(
|
|
177
|
+
SteerCutAfter.resolve(lookup)
|
|
143
178
|
rescue StandardError => e
|
|
144
179
|
unresolved(:steer_cut_after_unresolved, e, [SteerCut.cut_after, "steer.cut_after"])
|
|
145
180
|
end
|
|
@@ -148,7 +183,7 @@ module Samagotchi
|
|
|
148
183
|
# (LLMContextStrategy.explain) under the session's +args+
|
|
149
184
|
# (LLMContextOverride#resolve_args), nil when it can't be resolved.
|
|
150
185
|
def llm_context_explained(args)
|
|
151
|
-
LLMContextStrategy.explain(
|
|
186
|
+
LLMContextStrategy.explain(lookup, **args)
|
|
152
187
|
rescue StandardError => e
|
|
153
188
|
unresolved(:llm_context_unresolved, e, nil)
|
|
154
189
|
end
|
|
@@ -156,14 +191,14 @@ module Samagotchi
|
|
|
156
191
|
# The LLM context layers its turns run under; [] when they can't be
|
|
157
192
|
# resolved.
|
|
158
193
|
def llm_context_layers(args)
|
|
159
|
-
LLMContextStrategy.resolve(
|
|
194
|
+
LLMContextStrategy.resolve(lookup, **args).active_layers
|
|
160
195
|
rescue StandardError => e
|
|
161
196
|
unresolved(:llm_context_unresolved, e, [])
|
|
162
197
|
end
|
|
163
198
|
|
|
164
199
|
# models:/hosts: window_tokens (ContextWindow.setting), nil when unset.
|
|
165
200
|
def window_setting
|
|
166
|
-
ContextWindow.setting(
|
|
201
|
+
ContextWindow.setting(lookup)
|
|
167
202
|
rescue StandardError => e
|
|
168
203
|
unresolved(:window_unresolved, e, nil)
|
|
169
204
|
end
|
|
@@ -171,7 +206,7 @@ module Samagotchi
|
|
|
171
206
|
# The window config.yml gives this model or its host
|
|
172
207
|
# (ContextWindow.setting), never asking a server: a session loaded on
|
|
173
208
|
# it (Engine#session=, before a worker's Bridge serves). nil when none.
|
|
174
|
-
def configured_context_window = ContextWindow.setting(
|
|
209
|
+
def configured_context_window = ContextWindow.setting(lookup)
|
|
175
210
|
|
|
176
211
|
# The window as its loop would see it (ChatLoop#context_window: a remote
|
|
177
212
|
# chat host has no /props, only its model list); nil when it can't be
|
|
@@ -183,7 +218,7 @@ module Samagotchi
|
|
|
183
218
|
adapter = registry.adapter_for(entry)
|
|
184
219
|
client = nil if adapter.remote?
|
|
185
220
|
end
|
|
186
|
-
ContextWindow.resolve(client: client, model: bare, adapter: adapter, setting: ContextWindow.setting(
|
|
221
|
+
ContextWindow.resolve(client: client, model: bare, adapter: adapter, setting: ContextWindow.setting(lookup))
|
|
187
222
|
rescue StandardError => e
|
|
188
223
|
unresolved(:window_unresolved, e, nil)
|
|
189
224
|
end
|
|
@@ -232,7 +267,7 @@ module Samagotchi
|
|
|
232
267
|
|
|
233
268
|
# Whether it sees images (VisionSupport.for) under +profile+.
|
|
234
269
|
def vision_support(profile)
|
|
235
|
-
VisionSupport.for(
|
|
270
|
+
VisionSupport.for(lookup, profile: profile, adapter: vision_adapter)
|
|
236
271
|
end
|
|
237
272
|
|
|
238
273
|
# A chat host's adapter (what it says of images), nil on a native host.
|
|
@@ -246,7 +281,7 @@ module Samagotchi
|
|
|
246
281
|
# Not cached here. Raises.
|
|
247
282
|
# @return [ModelProfile::Resolution]
|
|
248
283
|
def profile_resolution
|
|
249
|
-
ModelProfile.resolve(names: names, entry: entry, client: client, bare_model: bare)
|
|
284
|
+
ModelProfile.resolve(names: names, entry: entry, client: client, bare_model: bare, models: lookup.models)
|
|
250
285
|
end
|
|
251
286
|
|
|
252
287
|
# See Unresolved.fallback.
|
|
@@ -60,7 +60,7 @@ module Samagotchi
|
|
|
60
60
|
prompt_sections: @prompt_sections,
|
|
61
61
|
prompt_changed: -> { prompt_changed! },
|
|
62
62
|
judgments: @judgments,
|
|
63
|
-
hook_failed: ->(hook, failed) { @hook_routes.plugin_hook_failed(hook, failed) }
|
|
63
|
+
hook_failed: ->(hook, failed, effect: :log) { @hook_routes.plugin_hook_failed(hook, failed, effect: effect) }
|
|
64
64
|
)
|
|
65
65
|
# What plugins show while they load (an MCP server that didn't
|
|
66
66
|
# start) waits for the first turn, beside the load warnings: no UI
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require_relative "../recap_place"
|
|
4
|
+
|
|
3
5
|
module Samagotchi
|
|
4
6
|
class Engine
|
|
5
7
|
# The idle recap (IdleRecap) and the shared idle scheduler: the recap job
|
|
@@ -96,9 +98,10 @@ module Samagotchi
|
|
|
96
98
|
@recap ? @recap.request_now : :off
|
|
97
99
|
end
|
|
98
100
|
|
|
99
|
-
# The recap saved with the current session (recap.json),
|
|
100
|
-
# user turns came after it (0: it is current)
|
|
101
|
-
#
|
|
101
|
+
# The recap saved with the current session (recap.json), how many
|
|
102
|
+
# user turns came after it (0: it is current), and the stamp of the
|
|
103
|
+
# last turn it covers (RecapPlace: where a page puts it; nil, the count).
|
|
104
|
+
# @return [Hash, nil] {text:, covered:, turns_since:, opening_id:, created_at:}
|
|
102
105
|
def saved_recap
|
|
103
106
|
state = @recap&.state
|
|
104
107
|
return nil unless state
|
|
@@ -106,7 +109,8 @@ module Samagotchi
|
|
|
106
109
|
messages = @session&.messages || []
|
|
107
110
|
covered = state[:covered].to_i
|
|
108
111
|
turns_since = Array(messages).drop(covered).count { |m| Steer.turn_opening?(m) }
|
|
109
|
-
{ text: state[:text], covered: covered, turns_since: turns_since,
|
|
112
|
+
{ text: state[:text], covered: covered, turns_since: turns_since, opening_id: RecapPlace.opening_id(messages, covered),
|
|
113
|
+
created_at: state[:created_at] }
|
|
110
114
|
end
|
|
111
115
|
|
|
112
116
|
# Start the shared idle scheduler (reminders + optional recap). The recap
|
data/lib/samagotchi/engine.rb
CHANGED
|
@@ -230,7 +230,9 @@ module Samagotchi
|
|
|
230
230
|
@chat_backend_mutex = Mutex.new
|
|
231
231
|
@side_judgments = SideJudgments.new
|
|
232
232
|
@judgments = build_judgments
|
|
233
|
-
|
|
233
|
+
# Taken once: a running worker keeps the hosts it started with. A
|
|
234
|
+
# client (specs) goes on a registry of its own, never the shared one.
|
|
235
|
+
@host_registry = host_registry || (client ? HostRegistry.new : HostRegistry.current)
|
|
234
236
|
# The turn stages over the objectives (its audit, view and proposals)
|
|
235
237
|
# and the Verify/Revise anchors (TurnStages).
|
|
236
238
|
@objectives_stage = build_objectives_stage
|
|
@@ -718,7 +720,10 @@ module Samagotchi
|
|
|
718
720
|
# (its limit goes in last_turn). The end event names its turn
|
|
719
721
|
# (`turn_id:`, as :turn_started does) and, for a Verify turn,
|
|
720
722
|
# `verify: true` (its opening's stamp: a page watching it live offers
|
|
721
|
-
# no Revise on its answer, verdict or not, as a reload does).
|
|
723
|
+
# no Revise on its answer, verdict or not, as a reload does). When the
|
|
724
|
+
# turn keeps messages, the event also names its own range in them,
|
|
725
|
+
# `kept[kept_from...kept_to]` (display-side: Bridge::TurnDrawings
|
|
726
|
+
# reads it; no message gains a key).
|
|
722
727
|
def end_turn(turn, outcome, save: false, exhausted: false)
|
|
723
728
|
seconds = turn.elapsed
|
|
724
729
|
turn.outcome = outcome
|
|
@@ -727,6 +732,7 @@ module Samagotchi
|
|
|
727
732
|
event[:turn_id] = turn.id
|
|
728
733
|
event[:verify] = true if turn.verify
|
|
729
734
|
revises = @verify_anchors.stamp_opening(kept, turn, outcome)
|
|
735
|
+
kept_range!(event, turn, kept)
|
|
730
736
|
replace_session_messages(turn.session, kept) if kept
|
|
731
737
|
verdict = @verify_anchors.record_verdict(turn, outcome)
|
|
732
738
|
event[:verdict] = verdict if verdict
|
|
@@ -744,6 +750,20 @@ module Samagotchi
|
|
|
744
750
|
end
|
|
745
751
|
private :end_turn
|
|
746
752
|
|
|
753
|
+
# The end event's kept_from/kept_to (#end_turn): only when the turn
|
|
754
|
+
# keeps messages and its start is known (#turn_messages ran). An ending
|
|
755
|
+
# that replaces an earlier turn's note at the history's tail
|
|
756
|
+
# (TurnNote.replace_trailing on a Continue stopped before its first step)
|
|
757
|
+
# leaves only system messages and its own note after it, so the range
|
|
758
|
+
# still starts at or before the turn's note and draws nothing else.
|
|
759
|
+
def kept_range!(event, turn, kept)
|
|
760
|
+
return unless kept && turn.history_size
|
|
761
|
+
|
|
762
|
+
event[:kept_from] = turn.history_size
|
|
763
|
+
event[:kept_to] = kept.size
|
|
764
|
+
end
|
|
765
|
+
private :kept_range!
|
|
766
|
+
|
|
747
767
|
# What a notice may stand in for (hook_notify's fallback_for:).
|
|
748
768
|
NOTICE_FALLBACKS = HookRoutes::NOTICE_FALLBACKS
|
|
749
769
|
|
|
@@ -806,8 +826,11 @@ module Samagotchi
|
|
|
806
826
|
# +wall+: the wall time it started (MessageTime.now, once): the
|
|
807
827
|
# :turn_started event's at and its user message's (and reminders') stamp.
|
|
808
828
|
# +verify+, +revises+: a Verify turn's claim, a Revise turn's draft.
|
|
829
|
+
# +history_size+: turn.messages' size under the system head, before
|
|
830
|
+
# the reminders and the prompt (#turn_messages): where the turn's own
|
|
831
|
+
# messages start in what it keeps (the end event's kept_from).
|
|
809
832
|
Turn = Struct.new(:context, :prompt, :continue, :on_event, :started_at, :messages, :ended, :prepared_settings,
|
|
810
|
-
:limit, :resumed, :resume_from, :wall, :verify, :revises, :outcome) do
|
|
833
|
+
:limit, :resumed, :resume_from, :wall, :verify, :revises, :outcome, :history_size) do
|
|
811
834
|
# The turn's id (:turn_started's turn_id, its metrics record's id and
|
|
812
835
|
# its saved prompt's), session, origin and controller: its context's.
|
|
813
836
|
def id = context.id
|
|
@@ -1124,6 +1147,9 @@ module Samagotchi
|
|
|
1124
1147
|
# Built once per Engine (and again after a model switch) so the prompt
|
|
1125
1148
|
# prefix, and the model server's KV cache for it, stay stable.
|
|
1126
1149
|
turn.messages = ContextNote.with_system_head(turn.messages, { role: "system", content: system_prompt })
|
|
1150
|
+
# Where the turn's own messages start (the end event's kept_from):
|
|
1151
|
+
# after the head this may have added, before the reminders and prompt.
|
|
1152
|
+
turn.history_size = turn.messages.size
|
|
1127
1153
|
# Explicit --memory preloads are now known after system prompt build.
|
|
1128
1154
|
@used_memories.add(activated_memory_names).absorb(session)
|
|
1129
1155
|
|
data/lib/samagotchi/events.rb
CHANGED
|
@@ -13,8 +13,9 @@ module Samagotchi
|
|
|
13
13
|
# (#kept_turn?).
|
|
14
14
|
TURN_KEPT = %i[turn_completed turn_canceled].freeze
|
|
15
15
|
# The kinds of a running turn's parts (Bridge::TurnAccumulator), which a
|
|
16
|
-
# joining UI replays as live events
|
|
17
|
-
|
|
16
|
+
# joining UI replays as live events (a card part only in a finished
|
|
17
|
+
# turn's drawing: a join takes its cards from CardStore).
|
|
18
|
+
PART_KINDS = %w[generation thinking text tool input steer reminder notice card].freeze
|
|
18
19
|
# Types no Engine emits that a UI handles: the Bridge's stream frames
|
|
19
20
|
# and the web's one synthetic replay event (a prompt merged into the
|
|
20
21
|
# turn, turn_events.js snapshotEvents).
|
|
@@ -49,12 +49,15 @@ module Samagotchi
|
|
|
49
49
|
end
|
|
50
50
|
|
|
51
51
|
# Load the installed bundles' plugins into +registries+; one that fails
|
|
52
|
-
# goes to +failures+,
|
|
53
|
-
#
|
|
52
|
+
# goes to +failures+, a required one (a guardrail plugin) to the hook
|
|
53
|
+
# failures, where it denies every tool call, and the rest still load.
|
|
54
|
+
# The block runs after them, still loading: what it shows is held with
|
|
55
|
+
# theirs.
|
|
54
56
|
def load_plugins(registries, failures:)
|
|
55
57
|
@held_events = []
|
|
56
58
|
@loading = true
|
|
57
|
-
Plugin::Loader.load_installed(registries, failures: failures, settings: bundle_settings)
|
|
59
|
+
Plugin::Loader.load_installed(registries, failures: failures, guardrail_failures: @hook_failures, settings: bundle_settings)
|
|
60
|
+
.tap { yield if block_given? }
|
|
58
61
|
ensure
|
|
59
62
|
@loading = false
|
|
60
63
|
end
|
|
@@ -190,7 +190,7 @@ module Samagotchi
|
|
|
190
190
|
threshold = threshold(options[:threshold])
|
|
191
191
|
return usage_error(threshold) if threshold.is_a?(String)
|
|
192
192
|
|
|
193
|
-
client = @client || SystemOne::Client.from_config(host_registry: HostRegistry.
|
|
193
|
+
client = @client || SystemOne::Client.from_config(host_registry: HostRegistry.current, mode: Config.get("guardrails.system_one.mode"), model: options[:model])
|
|
194
194
|
if client.nil?
|
|
195
195
|
error_line("chi guardrails replay: no System 1 client — set guardrails.system_one.mode to audit or on " \
|
|
196
196
|
"and system_one.host in config.yml")
|