samagotchi 0.155.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 +57 -1
- data/bin/chi +2 -1
- data/docs/architecture.md +22 -13
- 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/anthropic.md +1 -1
- data/docs/internals/attached-context.md +3 -2
- data/docs/internals/background-tasks.md +1 -1
- 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 +641 -937
- data/docs/internals/llm-context-forget.md +8 -3
- data/docs/internals/objectives.md +2 -2
- data/docs/internals/participants.md +3 -2
- data/docs/internals/prompt-caching.md +4 -1
- data/docs/internals/remote-sessions.md +8 -3
- data/docs/internals/web-frontend.md +3 -2
- data/docs/internals/working-set.md +2 -2
- data/docs/memory.md +13 -2
- data/docs/plugins.md +35 -2
- data/docs/sessions.md +11 -11
- data/docs/sub-agent.md +17 -2
- data/docs/system-one.md +3 -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/config_writer.rb +1 -1
- 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/broadcast_command.rb +3 -3
- data/lib/samagotchi/bundle_command/check.rb +18 -0
- data/lib/samagotchi/bundle_command/try/sandbox.rb +2 -2
- 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/config_modification_protocol.md +2 -2
- data/lib/samagotchi/bundles/system/manifest.yml +3 -3
- data/lib/samagotchi/bundles/system/memory_guide.md +1 -1
- data/lib/samagotchi/child_move.rb +13 -57
- data/lib/samagotchi/child_reports.rb +2 -2
- data/lib/samagotchi/children_status.rb +15 -21
- data/lib/samagotchi/cli/parent_wait.rb +9 -23
- data/lib/samagotchi/config.rb +20 -112
- data/lib/samagotchi/context_command.rb +1 -2
- data/lib/samagotchi/context_sources.rb +5 -4
- data/lib/samagotchi/context_window.rb +9 -12
- data/lib/samagotchi/desktop/macos.rb +1 -1
- data/lib/samagotchi/effective_model.rb +57 -22
- data/lib/samagotchi/engine/context_judge.rb +19 -11
- data/lib/samagotchi/engine/messages.rb +1 -1
- data/lib/samagotchi/engine/models.rb +5 -2
- data/lib/samagotchi/engine/objectives.rb +29 -11
- data/lib/samagotchi/engine/plugins.rb +1 -1
- data/lib/samagotchi/engine/recap.rb +8 -4
- data/lib/samagotchi/engine/side_requests.rb +21 -11
- data/lib/samagotchi/engine/toolkit.rb +10 -9
- data/lib/samagotchi/engine/turn_end.rb +1 -1
- data/lib/samagotchi/engine/turn_helpers.rb +7 -7
- data/lib/samagotchi/engine/verify.rb +1 -1
- data/lib/samagotchi/engine.rb +43 -12
- data/lib/samagotchi/events.rb +3 -2
- data/lib/samagotchi/extension_load.rb +6 -3
- data/lib/samagotchi/guardrails/targets.rb +24 -9
- data/lib/samagotchi/guardrails_command.rb +1 -1
- data/lib/samagotchi/host_address.rb +52 -0
- data/lib/samagotchi/host_config.rb +72 -1
- data/lib/samagotchi/host_model.rb +2 -6
- data/lib/samagotchi/host_registry.rb +58 -46
- data/lib/samagotchi/kernel_loop.rb +53 -124
- data/lib/samagotchi/llm/anthropic_wire.rb +2 -2
- data/lib/samagotchi/llm/chat_loop.rb +40 -21
- data/lib/samagotchi/llm/native_backend.rb +1 -1
- data/lib/samagotchi/llm_context_apply.rb +54 -1
- data/lib/samagotchi/llm_context_notice.rb +1 -1
- data/lib/samagotchi/llm_context_strategy.rb +29 -67
- data/lib/samagotchi/llm_context_view.rb +9 -0
- 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_price.rb +4 -10
- data/lib/samagotchi/model_profile.rb +7 -6
- data/lib/samagotchi/model_settings.rb +37 -2
- data/lib/samagotchi/models_command.rb +1 -1
- data/lib/samagotchi/note_command.rb +2 -3
- data/lib/samagotchi/objectives_audit.rb +4 -3
- data/lib/samagotchi/participant_mode.rb +2 -1
- data/lib/samagotchi/participants.rb +2 -2
- data/lib/samagotchi/plugin/api.rb +41 -6
- data/lib/samagotchi/plugin/context.rb +1 -1
- data/lib/samagotchi/plugin/loader.rb +33 -10
- data/lib/samagotchi/plugin/sessions.rb +3 -6
- data/lib/samagotchi/plugin/tool_spec.rb +5 -3
- data/lib/samagotchi/project_env.rb +1 -1
- data/lib/samagotchi/reasoning_history.rb +14 -20
- data/lib/samagotchi/recap_place.rb +27 -0
- data/lib/samagotchi/reminder_carry.rb +1 -1
- 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/reprefill_meter.rb +45 -0
- data/lib/samagotchi/review_command.rb +1 -1
- data/lib/samagotchi/sampling_settings.rb +9 -16
- data/lib/samagotchi/self_report.rb +36 -37
- data/lib/samagotchi/send_command.rb +17 -23
- data/lib/samagotchi/session.rb +370 -445
- data/lib/samagotchi/session_access/local.rb +12 -11
- data/lib/samagotchi/session_access/remote.rb +22 -6
- data/lib/samagotchi/session_archive_command.rb +2 -2
- data/lib/samagotchi/session_chain.rb +7 -6
- data/lib/samagotchi/session_continue.rb +6 -5
- data/lib/samagotchi/session_delete_command.rb +1 -1
- data/lib/samagotchi/session_field.rb +133 -0
- data/lib/samagotchi/session_inbox.rb +49 -1
- data/lib/samagotchi/session_manager/delivery.rb +254 -0
- data/lib/samagotchi/session_manager/emptiness.rb +139 -0
- data/lib/samagotchi/session_manager/lifecycle.rb +274 -0
- data/lib/samagotchi/session_manager/listing.rb +118 -0
- data/lib/samagotchi/session_manager/removal.rb +190 -0
- data/lib/samagotchi/session_manager/spawn.rb +242 -0
- data/lib/samagotchi/session_manager/worker_command.rb +157 -0
- data/lib/samagotchi/session_manager.rb +28 -1541
- data/lib/samagotchi/session_metrics.rb +8 -5
- 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/share_command.rb +1 -1
- data/lib/samagotchi/starting_marker.rb +65 -0
- data/lib/samagotchi/steer_cut_after.rb +7 -14
- data/lib/samagotchi/system_one/recorder.rb +49 -0
- data/lib/samagotchi/terminal_ui/attached_loop.rb +6 -26
- data/lib/samagotchi/terminal_ui/exit_lines.rb +1 -1
- 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 +5 -7
- data/lib/samagotchi/testing/install.rb +2 -1
- data/lib/samagotchi/testing/sessions.rb +1 -1
- data/lib/samagotchi/thinking.rb +16 -21
- data/lib/samagotchi/token_usage.rb +1 -1
- data/lib/samagotchi/tool_activity.rb +10 -4
- data/lib/samagotchi/tool_declarations.rb +2 -2
- data/lib/samagotchi/tool_output_cut.rb +17 -0
- data/lib/samagotchi/tool_response.rb +5 -3
- data/lib/samagotchi/tool_runner.rb +25 -5
- data/lib/samagotchi/toolkit_command.rb +1 -1
- data/lib/samagotchi/tools/delegate.rb +55 -45
- data/lib/samagotchi/tools/delegate_relay.rb +5 -5
- data/lib/samagotchi/tools/delegate_result.rb +5 -5
- data/lib/samagotchi/tools/delegate_wait.rb +41 -17
- data/lib/samagotchi/tools/index_hint.rb +14 -0
- data/lib/samagotchi/tools/list_sessions.rb +7 -7
- data/lib/samagotchi/tools/registry.rb +28 -11
- data/lib/samagotchi/tools/send_note.rb +4 -6
- data/lib/samagotchi/tools/tool_index.rb +52 -51
- data/lib/samagotchi/tools/tool_surface.rb +22 -8
- data/lib/samagotchi/turn_context.rb +2 -1
- data/lib/samagotchi/turn_stages/context_judge.rb +38 -36
- data/lib/samagotchi/turn_stages/objectives.rb +56 -52
- data/lib/samagotchi/turn_stages/toolkit_suggestion.rb +13 -17
- data/lib/samagotchi/turn_stages/verify_anchors.rb +9 -10
- data/lib/samagotchi/turn_stages/warmup.rb +14 -15
- 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 +45 -28
- data/lib/samagotchi/web/message_display.rb +57 -7
- data/lib/samagotchi/web/participant_access.rb +3 -3
- 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 +6 -6
- data/lib/samagotchi/web/session_control.rb +4 -4
- data/lib/samagotchi/web/session_create.rb +3 -3
- data/lib/samagotchi/web/session_hub.rb +9 -17
- data/lib/samagotchi/web/session_show.rb +67 -5
- data/lib/samagotchi/web/session_summary.rb +39 -28
- data/lib/samagotchi/worker.rb +83 -32
- data/lib/samagotchi/worker_boot.rb +184 -0
- data/lib/samagotchi/worker_link.rb +3 -0
- data/lib/samagotchi/worker_signals.rb +1 -1
- data/lib/samagotchi/worker_task_wakes.rb +2 -2
- metadata +32 -4
- data/lib/samagotchi/send_command/wait_target.rb +0 -85
|
@@ -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.
|
|
@@ -5,7 +5,7 @@ module Samagotchi
|
|
|
5
5
|
# The attached-context candidate judge (TurnStages::ContextJudge,
|
|
6
6
|
# forwarded): prepare_turn starts its pass, run_turn's ensure shows the
|
|
7
7
|
# cards it held, and a plugin's late candidate asks it. Reads
|
|
8
|
-
# @context_judge, @side_judgments, @host_registry.
|
|
8
|
+
# @context_judge, @side_judgments, @host_registry, @turn_state, @session.
|
|
9
9
|
module ContextJudgePart
|
|
10
10
|
private
|
|
11
11
|
|
|
@@ -13,19 +13,27 @@ module Samagotchi
|
|
|
13
13
|
attr_reader :context_judge
|
|
14
14
|
|
|
15
15
|
# A late proposal no owner prompt mentions (Plugin::Host
|
|
16
|
-
# #candidate_proposed
|
|
17
|
-
|
|
16
|
+
# #candidate_proposed, maybe while the plugins load, before a session
|
|
17
|
+
# or the event log is there): TurnStages::ContextJudge#late_candidates
|
|
18
|
+
# on the session the Engine is on (none, or a review session: nothing,
|
|
19
|
+
# before anything else is read), the owner's prompts so far, the
|
|
20
|
+
# recorder and the sessions dir, all read now on the caller's thread.
|
|
21
|
+
def judge_late_candidates
|
|
22
|
+
session = @session
|
|
23
|
+
return if session.nil? || session.review?
|
|
18
24
|
|
|
19
|
-
|
|
25
|
+
@context_judge.late_candidates(session, messages: plugin_messages, recorder: system_one_recorder,
|
|
26
|
+
state_dir: session_state_dir)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# The stage over this Engine's side asks (built in
|
|
20
30
|
# #build_tools_and_plugins, before the plugins load: one may propose a
|
|
21
|
-
# candidate as it loads).
|
|
31
|
+
# candidate as it loads). Its two callables are the asks thread's late
|
|
32
|
+
# reads: the session the Engine is on and where a card goes, both as
|
|
33
|
+
# an answer comes.
|
|
22
34
|
def build_context_judge
|
|
23
|
-
TurnStages::ContextJudge.new(
|
|
24
|
-
|
|
25
|
-
recording: ->(client, judgment, session, mode:) { system_one_recording(client, judgment, session, mode: mode) },
|
|
26
|
-
session: -> { session }, messages: -> { plugin_messages }, turn_running: -> { turn_running? },
|
|
27
|
-
show_card: ->(**card) { show_card(**card) }
|
|
28
|
-
)
|
|
35
|
+
TurnStages::ContextJudge.new(side_judgments: @side_judgments, host_registry: @host_registry, turn_state: @turn_state,
|
|
36
|
+
show_card: ->(**card) { show_card(**card) }, current_session: -> { @session })
|
|
29
37
|
end
|
|
30
38
|
end
|
|
31
39
|
end
|
|
@@ -46,7 +46,7 @@ module Samagotchi
|
|
|
46
46
|
from_cwd: note[:from_cwd], text: note[:text], context_source: note[:context_source],
|
|
47
47
|
created_at: note[:created_at], objectives: entry }.compact)
|
|
48
48
|
announce_objectives(session) if entry
|
|
49
|
-
@objectives_stage.note(session, note)
|
|
49
|
+
@objectives_stage.note(session, note, recorder: system_one_recorder, state_dir: session_state_dir)
|
|
50
50
|
message
|
|
51
51
|
end
|
|
52
52
|
end
|
|
@@ -228,13 +228,16 @@ module Samagotchi
|
|
|
228
228
|
private
|
|
229
229
|
|
|
230
230
|
# Pick the loop for +model+ (EffectiveModel); the chat loop is pointed
|
|
231
|
-
# at its host's adapter (one per host, kept for its cached model list)
|
|
231
|
+
# at its host's adapter (one per host, kept for its cached model list)
|
|
232
|
+
# and client (the window probe, the re-prefill's host).
|
|
232
233
|
def backend_for(model)
|
|
233
234
|
return @native_backend unless model.chat?
|
|
234
235
|
|
|
235
236
|
@chat_backend_mutex.synchronize do
|
|
236
|
-
@chat_backend ||= LLM::ChatLoop.new(kernel: @kernel,
|
|
237
|
+
@chat_backend ||= LLM::ChatLoop.new(kernel: @kernel, reprefill: @reprefill,
|
|
238
|
+
stable_length: ->(text) { @prompt_builder.stable_length(text) })
|
|
237
239
|
@chat_backend.adapter = @host_registry.adapter_for(model.entry)
|
|
240
|
+
@chat_backend.client = model.client
|
|
238
241
|
@chat_backend.session_id = session&.id
|
|
239
242
|
@chat_backend
|
|
240
243
|
end
|
|
@@ -9,8 +9,22 @@ module Samagotchi
|
|
|
9
9
|
# @host_registry, @session.
|
|
10
10
|
module ObjectivesPart
|
|
11
11
|
# The session's objectives as the page draws them, when that differs
|
|
12
|
-
# from the last announced (TurnStages::Objectives#announce)
|
|
13
|
-
|
|
12
|
+
# from the last announced (TurnStages::Objectives#announce), from any
|
|
13
|
+
# thread: end_turn's step, a command, Check this's thread, a note,
|
|
14
|
+
# a rollback. Under the event lock, which guards the last view: the
|
|
15
|
+
# sessions dir and the running turn's conversation read there, the
|
|
16
|
+
# event announced in the same step. It only informs: a failure is
|
|
17
|
+
# logged, never raised.
|
|
18
|
+
def announce_objectives(session = @session)
|
|
19
|
+
return unless session
|
|
20
|
+
|
|
21
|
+
synchronize_events do
|
|
22
|
+
event = @objectives_stage.announce(session, state_dir: session_state_dir, running: live_conversation)
|
|
23
|
+
announce(event) if event
|
|
24
|
+
end
|
|
25
|
+
rescue StandardError => e
|
|
26
|
+
Log.warn(:turn, "objectives_announce_failed", error: e.class.name, msg: e.message)
|
|
27
|
+
end
|
|
14
28
|
|
|
15
29
|
# Check this (ObjectivesCheck)'s one side request. Its usage is in the
|
|
16
30
|
# session's side line. Raises as ctx.ask_model's request does.
|
|
@@ -32,16 +46,20 @@ module Samagotchi
|
|
|
32
46
|
# The objectives' stage (TurnStages::Objectives).
|
|
33
47
|
attr_reader :objectives_stage
|
|
34
48
|
|
|
35
|
-
#
|
|
36
|
-
#
|
|
49
|
+
# However +turn+ ended (run_turn's ensure, after the turn flag is
|
|
50
|
+
# released): a completed turn's proposal cards shown
|
|
51
|
+
# (TurnStages::Objectives#finally). A card that fails is logged.
|
|
52
|
+
def show_objective_proposals(turn)
|
|
53
|
+
@objectives_stage.finally(turn).each { |card| show_card(**card) }
|
|
54
|
+
rescue StandardError => e
|
|
55
|
+
Log.warn(:turn, "objectives_proposal_failed", error: e.class.name, msg: e.message)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# The stage over this Engine's side asks (built in #initialize, once
|
|
59
|
+
# the host registry is). Each call takes its values: the recorder,
|
|
60
|
+
# the sessions dir, the running conversation.
|
|
37
61
|
def build_objectives_stage
|
|
38
|
-
TurnStages::Objectives.new(
|
|
39
|
-
side_judgments: @side_judgments, host_registry: @host_registry, state_dir: -> { session_state_dir },
|
|
40
|
-
recording: ->(client, judgment, session, mode:) { system_one_recording(client, judgment, session, mode: mode) },
|
|
41
|
-
runs: -> { system_one_runs }, synchronize: ->(&block) { synchronize_events(&block) },
|
|
42
|
-
announce: ->(event) { announce(event) }, running: -> { live_conversation },
|
|
43
|
-
show_card: ->(**card) { show_card(**card) }
|
|
44
|
-
)
|
|
62
|
+
TurnStages::Objectives.new(side_judgments: @side_judgments, host_registry: @host_registry)
|
|
45
63
|
end
|
|
46
64
|
end
|
|
47
65
|
end
|
|
@@ -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
|
|
@@ -6,6 +6,7 @@ module Samagotchi
|
|
|
6
6
|
# IdleClient, their usage in the session's side line, and System 1's
|
|
7
7
|
# recording of judged asks. Writes @side_client/@side_client_key (under
|
|
8
8
|
# @side_client_mutex); reads @metrics, @session, @host_registry.
|
|
9
|
+
# The recorder (SystemOne::Recorder) is the turn stages' recording seam.
|
|
9
10
|
module SideRequestsPart
|
|
10
11
|
# Count one side request (a recap, a plugin's ctx.ask_model: IdleClient's
|
|
11
12
|
# on_usage) in the session's side line, apart from its turns' totals.
|
|
@@ -52,24 +53,33 @@ module Samagotchi
|
|
|
52
53
|
|
|
53
54
|
private
|
|
54
55
|
|
|
55
|
-
# +client+ (nil for none) saving its asks as +judgment+'s runs
|
|
56
|
-
#
|
|
57
|
-
#
|
|
58
|
-
#
|
|
59
|
-
# A scratch session's asks aren't saved; a participant's turn is never
|
|
60
|
-
# judged, so it never comes here.
|
|
56
|
+
# +client+ (nil for none) saving its asks as +judgment+'s runs
|
|
57
|
+
# (SystemOne::Recorder#wrap, over a recorder built now): the
|
|
58
|
+
# guardrails' System 1 client. No client or a scratch session: the
|
|
59
|
+
# client as it is, with nothing read (no recorder built).
|
|
61
60
|
# @param mode [String, nil] the use's mode, for its runs (Recording.wrap)
|
|
62
61
|
def system_one_recording(client, judgment, session, mode: nil)
|
|
63
62
|
return client if client.nil? || session&.scratch
|
|
64
63
|
|
|
65
|
-
|
|
66
|
-
SystemOne::Recording.wrap(client, judgment: judgment, runs: system_one_runs, context: context, recorded_mode: mode)
|
|
67
|
-
rescue StandardError => e
|
|
68
|
-
Log.warn(:system_one, "system_one_recording_failed", error: e.class.name, msg: e.message.to_s[0, 200])
|
|
69
|
-
client
|
|
64
|
+
system_one_recorder.wrap(client, judgment, session, mode: mode)
|
|
70
65
|
end
|
|
71
66
|
private :system_one_recording
|
|
72
67
|
|
|
68
|
+
# What a turn stage saves its System 1 asks with (SystemOne::Recorder):
|
|
69
|
+
# this Engine's runs and the model it names now, read at this call and
|
|
70
|
+
# never kept, so each stage call sees the model as it is then (an
|
|
71
|
+
# outgoing ask after a before_turn hook's switch, the new one). Never
|
|
72
|
+
# raises: on a failure, SystemOne::Recorder::NONE (no runs, the plain
|
|
73
|
+
# client), said once per failure as before.
|
|
74
|
+
# @return [SystemOne::Recorder]
|
|
75
|
+
def system_one_recorder
|
|
76
|
+
SystemOne::Recorder.new(runs: system_one_runs, session_model: effective_model_name)
|
|
77
|
+
rescue StandardError => e
|
|
78
|
+
SystemOne::Recorder.failed(e)
|
|
79
|
+
SystemOne::Recorder::NONE
|
|
80
|
+
end
|
|
81
|
+
private :system_one_recorder
|
|
82
|
+
|
|
73
83
|
# Where this Engine's runs are saved; read each time, as the settings are.
|
|
74
84
|
def system_one_runs = SystemOne::Runs.for_sessions_dir(session_state_dir)
|
|
75
85
|
private :system_one_runs
|
|
@@ -22,10 +22,14 @@ module Samagotchi
|
|
|
22
22
|
# turn's staged tool sets and its toolkit apply.
|
|
23
23
|
def publish_tools! = @toolkit_binding.publish!
|
|
24
24
|
|
|
25
|
+
# That published Registry (ToolkitBinding#published): what a reader
|
|
26
|
+
# off the turn thread (/toolkit) reads of the tools.
|
|
27
|
+
def published_tools = @toolkit_binding.published
|
|
28
|
+
|
|
25
29
|
# The tools this session registered (Tools::Registry), declared or not.
|
|
26
30
|
attr_reader :tools
|
|
27
31
|
|
|
28
|
-
public :tools, :toolkit_kits, :resolved_toolkit, :toolkit_explained, :toolkit_summary
|
|
32
|
+
public :tools, :published_tools, :toolkit_kits, :resolved_toolkit, :toolkit_explained, :toolkit_summary
|
|
29
33
|
|
|
30
34
|
# A plugin's ctx.load_tools: stage the reachable tools +names+ names
|
|
31
35
|
# (Tools::ToolIndex#deferred_name, on the published Registry) that the
|
|
@@ -35,7 +39,7 @@ module Samagotchi
|
|
|
35
39
|
# @return [Array<String>] the wire names staged
|
|
36
40
|
def load_tools(names, bundle)
|
|
37
41
|
added = ToolLoads.added(@session&.messages)
|
|
38
|
-
published =
|
|
42
|
+
published = published_tools
|
|
39
43
|
surface = Tools::ToolSurface.for(published)
|
|
40
44
|
wanted = names.filter_map do |name|
|
|
41
45
|
wire = @tool_index.deferred_name(name, surface)
|
|
@@ -97,14 +101,11 @@ module Samagotchi
|
|
|
97
101
|
public :warm_toolkit_suggestion!
|
|
98
102
|
|
|
99
103
|
# The stage over this Engine's side asks, binding and tools (built in
|
|
100
|
-
# #build_tools_and_plugins, before the plugins load).
|
|
104
|
+
# #build_tools_and_plugins, before the plugins load). Its turn's start
|
|
105
|
+
# takes the recorder (#system_one_recorder) per call.
|
|
101
106
|
def build_toolkit_suggestion
|
|
102
|
-
TurnStages::ToolkitSuggestion.new(
|
|
103
|
-
|
|
104
|
-
tools: @tools, state_dir: -> { session_state_dir },
|
|
105
|
-
recording: ->(client, judgment, session, mode:) { system_one_recording(client, judgment, session, mode: mode) },
|
|
106
|
-
runs: -> { system_one_runs }
|
|
107
|
-
)
|
|
107
|
+
TurnStages::ToolkitSuggestion.new(side_judgments: @side_judgments, host_registry: @host_registry,
|
|
108
|
+
toolkit_binding: @toolkit_binding, tools: @tools)
|
|
108
109
|
end
|
|
109
110
|
private :build_toolkit_suggestion
|
|
110
111
|
end
|
|
@@ -117,7 +117,7 @@ module Samagotchi
|
|
|
117
117
|
# a display version of the answer (AnswerDisplay) and event[:refs]
|
|
118
118
|
# for refs on it (AnswerRefs).
|
|
119
119
|
session = turn.session
|
|
120
|
-
@objectives_stage.outgoing(turn, result) unless canceled || result.exhausted?
|
|
120
|
+
@objectives_stage.outgoing(turn, result, recorder: system_one_recorder) unless canceled || result.exhausted?
|
|
121
121
|
display = AnswerDisplay.new(session.messages)
|
|
122
122
|
refs = AnswerRefs.new(session.messages, cwd: session.working_directory)
|
|
123
123
|
after_turn = { type: :after_turn, status: canceled ? "canceled" : "completed",
|
|
@@ -7,7 +7,7 @@ module Samagotchi
|
|
|
7
7
|
# with, the used memories it publishes, and the turn-end warm-up of the
|
|
8
8
|
# next one (TurnStages::Warmup, built here). Writes @next_turn_waiting;
|
|
9
9
|
# reads @model_settings, @kernel, @prompt_warmup, @thinking_notices,
|
|
10
|
-
# @turn_state, @turn_warmup.
|
|
10
|
+
# @turn_state, @reminder_queue, @turn_warmup.
|
|
11
11
|
module TurnHelpersPart
|
|
12
12
|
# The turn's settings for the kernel (LLM::TurnSettings): vision,
|
|
13
13
|
# sampling and thinking, the thinking resolved before the hooks run.
|
|
@@ -40,13 +40,13 @@ module Samagotchi
|
|
|
40
40
|
private :turn_warmup
|
|
41
41
|
|
|
42
42
|
# The stage over the kernel and the Engine's PromptWarmup (built in
|
|
43
|
-
# #initialize, once the kernel
|
|
43
|
+
# #initialize, once the kernel and the reminder queue are). Its one
|
|
44
|
+
# callable is the system prompt, built late (side effects); the
|
|
45
|
+
# host's probe goes with each call (#next_turn_waiting, set after).
|
|
44
46
|
def build_turn_warmup
|
|
45
|
-
TurnStages::Warmup.new(
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
reminders_due: -> { reminders_due? }, next_turn_waiting: -> { next_turn_waiting&.call }
|
|
49
|
-
)
|
|
47
|
+
TurnStages::Warmup.new(prompt_warmup: @prompt_warmup, kernel: @kernel, turn_state: @turn_state,
|
|
48
|
+
model_settings: @model_settings, reminder_queue: @reminder_queue,
|
|
49
|
+
system_prompt: ->(model) { system_prompt(model) })
|
|
50
50
|
end
|
|
51
51
|
private :build_turn_warmup
|
|
52
52
|
|
|
@@ -11,7 +11,7 @@ module Samagotchi
|
|
|
11
11
|
# The anchors' stage (TurnStages::VerifyAnchors).
|
|
12
12
|
attr_reader :verify_anchors
|
|
13
13
|
|
|
14
|
-
def build_verify_anchors = TurnStages::VerifyAnchors.new
|
|
14
|
+
def build_verify_anchors = TurnStages::VerifyAnchors.new
|
|
15
15
|
end
|
|
16
16
|
end
|
|
17
17
|
end
|