samagotchi 0.77.0 → 0.78.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 +26 -1
- data/docs/cli.md +2 -1
- data/docs/configuration.md +10 -6
- data/docs/internals/anthropic.md +73 -5
- data/docs/internals/engine.md +1 -0
- data/docs/internals/prompt-caching.md +3 -1
- data/docs/sessions.md +1 -0
- data/lib/samagotchi/broadcast/recipients.rb +2 -2
- data/lib/samagotchi/bundles/system/manifest.yml +1 -1
- data/lib/samagotchi/child_move.rb +2 -2
- data/lib/samagotchi/child_reports.rb +2 -2
- data/lib/samagotchi/children_status.rb +2 -2
- data/lib/samagotchi/llm/anthropic_assembly.rb +14 -0
- data/lib/samagotchi/llm/anthropic_messages.rb +210 -13
- data/lib/samagotchi/llm/anthropic_wire.rb +22 -0
- data/lib/samagotchi/llm/chat_loop.rb +49 -2
- data/lib/samagotchi/llm/errors.rb +6 -4
- data/lib/samagotchi/llm/http.rb +2 -1
- data/lib/samagotchi/llm/openai_chat.rb +12 -2
- data/lib/samagotchi/note_delivery.rb +2 -2
- data/lib/samagotchi/plugin/sessions.rb +2 -2
- data/lib/samagotchi/reply_wait.rb +2 -3
- data/lib/samagotchi/session_manager.rb +0 -1
- data/lib/samagotchi/session_metrics/totals.rb +4 -3
- data/lib/samagotchi/session_metrics.rb +9 -0
- data/lib/samagotchi/terminal_ui/formatting.rb +3 -0
- data/lib/samagotchi/terminal_ui.rb +2 -2
- data/lib/samagotchi/tools/delegate.rb +2 -2
- data/lib/samagotchi/tools/delegate_result.rb +2 -2
- data/lib/samagotchi/tools/list_sessions.rb +2 -2
- data/lib/samagotchi/version.rb +1 -1
- data/lib/samagotchi/web/public/app.js +217 -19
- data/lib/samagotchi/web/public/composer_fold.js +58 -0
- data/lib/samagotchi/web/public/composer_size.js +10 -0
- data/lib/samagotchi/web/public/index.html +27 -3
- data/lib/samagotchi/worker.rb +1 -0
- metadata +2 -1
|
@@ -83,6 +83,28 @@ module Samagotchi
|
|
|
83
83
|
end
|
|
84
84
|
end
|
|
85
85
|
|
|
86
|
+
# A replayed thinking block's identity, the one name the adapter and
|
|
87
|
+
# ChatLoop share for it: a thinking block's signature, a
|
|
88
|
+
# redacted_thinking block's data, or, when that is empty (Splash
|
|
89
|
+
# sends signature ""), "text:" + the SHA256 of its thinking text. nil
|
|
90
|
+
# for any other block and for one with neither (never matched).
|
|
91
|
+
# String or symbol keys.
|
|
92
|
+
def block_identity(block)
|
|
93
|
+
return nil unless block.is_a?(Hash)
|
|
94
|
+
|
|
95
|
+
case type_of(block)
|
|
96
|
+
when "thinking"
|
|
97
|
+
signature = (block["signature"] || block[:signature]).to_s
|
|
98
|
+
return signature unless signature.empty?
|
|
99
|
+
|
|
100
|
+
text = (block["thinking"] || block[:thinking]).to_s
|
|
101
|
+
text.empty? ? nil : "text:#{Digest::SHA256.hexdigest(text)}"
|
|
102
|
+
when "redacted_thinking"
|
|
103
|
+
data = (block["data"] || block[:data]).to_s
|
|
104
|
+
data.empty? ? nil : data
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
86
108
|
# +id+ as Messages takes it (^[a-zA-Z0-9_-]+$), the same in tool_use
|
|
87
109
|
# and tool_result: a valid id as it is, another with its invalid
|
|
88
110
|
# characters replaced and a short hash of it appended (so "a.b" and
|
|
@@ -7,6 +7,7 @@ require_relative "model_result"
|
|
|
7
7
|
require_relative "errors"
|
|
8
8
|
require_relative "usage"
|
|
9
9
|
require_relative "openai_chat"
|
|
10
|
+
require_relative "anthropic_wire"
|
|
10
11
|
require_relative "native_tool_normalizer"
|
|
11
12
|
require_relative "refusal_memo"
|
|
12
13
|
require_relative "stream_drops"
|
|
@@ -41,7 +42,9 @@ module Samagotchi
|
|
|
41
42
|
#
|
|
42
43
|
# Stream events match the native loop's: :generation_started (with the
|
|
43
44
|
# context window), :generation_chunk per delta, :generation_completed,
|
|
44
|
-
# :generation_retrying, the tool-call events and :pending_input_merged
|
|
45
|
+
# :generation_retrying, the tool-call events and :pending_input_merged,
|
|
46
|
+
# and :thinking_dropped after a preserved-thinking recovery
|
|
47
|
+
# (#settle_dropped_thinking!).
|
|
45
48
|
# A chunk carries `thinking:` (reasoning deltas), `text:` (answer deltas)
|
|
46
49
|
# and `content:` (both, like native raw content) plus the raw `payload:`.
|
|
47
50
|
#
|
|
@@ -348,6 +351,30 @@ module Samagotchi
|
|
|
348
351
|
# edit/write result's tool_diffs (never sent), an empty-answer
|
|
349
352
|
# note's marker (TurnNote.empty, never sent), and an answer's display
|
|
350
353
|
# and display_refs (AnswerDisplay, AnswerRefs; never sent).
|
|
354
|
+
# Removes the replayed thinking blocks a response's ThinkingDrop
|
|
355
|
+
# names (AnthropicWire.block_identity) from the model entries'
|
|
356
|
+
# anthropic_content: the edit the provider made for that request, so
|
|
357
|
+
# the next one is valid as it is. Each changed entry is replaced in
|
|
358
|
+
# place, at its index (the Run, ContextStatus and the LLM context
|
|
359
|
+
# turn hold the array and its indexes); one left with no blocks loses
|
|
360
|
+
# the key. +thinking+ (the text the UIs show) stays.
|
|
361
|
+
# @return [Integer] the blocks removed
|
|
362
|
+
def settle_dropped_thinking!(conversation, identities)
|
|
363
|
+
wanted = Array(identities)
|
|
364
|
+
removed = 0
|
|
365
|
+
conversation.each_with_index do |entry, index|
|
|
366
|
+
blocks = entry[:anthropic_content]
|
|
367
|
+
next unless blocks.is_a?(Array)
|
|
368
|
+
|
|
369
|
+
kept = blocks.reject { |block| (identity = AnthropicWire.block_identity(block)) && wanted.include?(identity) }
|
|
370
|
+
next if kept.size == blocks.size
|
|
371
|
+
|
|
372
|
+
removed += blocks.size - kept.size
|
|
373
|
+
conversation[index] = kept.empty? ? entry.except(:anthropic_content) : entry.merge(anthropic_content: kept)
|
|
374
|
+
end
|
|
375
|
+
removed
|
|
376
|
+
end
|
|
377
|
+
|
|
351
378
|
def plain(conversation)
|
|
352
379
|
conversation.map do |entry|
|
|
353
380
|
content = entry[:content].is_a?(Array) ? entry[:content] : entry[:content].to_s
|
|
@@ -649,11 +676,13 @@ module Samagotchi
|
|
|
649
676
|
|
|
650
677
|
return cut_response(iteration, thought, generation_controller.detail || {})
|
|
651
678
|
end
|
|
679
|
+
dropped = settle_thinking_drop(iteration, response.thinking_drop)
|
|
652
680
|
record_context_status(response.usage, window)
|
|
653
681
|
emit(type: :generation_completed, iteration: iteration, content_length: response.text.length,
|
|
654
682
|
thinking_chars: response.reasoning.to_s.length, served_model: response.model,
|
|
655
683
|
served_provider: response.provider, requested_model: @model_name, finish_reason: response.finish_reason,
|
|
656
|
-
**(response.usage&.cache_fields || {}), **reprefill_field(response.usage)
|
|
684
|
+
**(response.usage&.cache_fields || {}), **reprefill_field(response.usage),
|
|
685
|
+
**(dropped.positive? ? { thinking_dropped: dropped } : {}))
|
|
657
686
|
dump_response(response, iteration)
|
|
658
687
|
@loop.fire_hook(:after_generation, { type: :after_generation, iteration: iteration, response: response.text,
|
|
659
688
|
messages: AnswerDisplay.strip_all(@conversation).map(&:dup).freeze })
|
|
@@ -662,6 +691,24 @@ module Samagotchi
|
|
|
662
691
|
[e.reason, streamed, thought]
|
|
663
692
|
end
|
|
664
693
|
|
|
694
|
+
# A response the adapter got by dropping replayed thinking blocks
|
|
695
|
+
# (ChatResponse#thinking_drop): those blocks leave the stored
|
|
696
|
+
# entries (before this step adds its own, whatever its finish
|
|
697
|
+
# reason), and :thinking_dropped says how many. A drop that settles
|
|
698
|
+
# nothing (the same blocks again: they were settled, then came back)
|
|
699
|
+
# is logged once per run. Returns the blocks dropped.
|
|
700
|
+
def settle_thinking_drop(iteration, drop)
|
|
701
|
+
return 0 unless drop && !drop.identities.empty?
|
|
702
|
+
|
|
703
|
+
count = drop.identities.size
|
|
704
|
+
if @loop.settle_dropped_thinking!(@conversation, drop.identities).zero? && !@recovery_repeated
|
|
705
|
+
@recovery_repeated = true
|
|
706
|
+
Log.info(:model, "thinking_recovery_repeated", model: @model_name.to_s, how: drop.how.to_s, blocks: count)
|
|
707
|
+
end
|
|
708
|
+
emit(type: :thinking_dropped, iteration: iteration, count: count, how: drop.how)
|
|
709
|
+
count
|
|
710
|
+
end
|
|
711
|
+
|
|
665
712
|
# The request's re-prefilled tokens (KernelLoop#reprefilled_tokens).
|
|
666
713
|
def reprefill_field(usage)
|
|
667
714
|
return {} unless usage&.source == :server
|
|
@@ -38,17 +38,19 @@ module Samagotchi
|
|
|
38
38
|
# whatever status; also raised before sending)
|
|
39
39
|
# ProtocolError a body that isn't what the API promises
|
|
40
40
|
class ProviderError < StandardError
|
|
41
|
-
attr_reader :host, :status, :retry_after
|
|
41
|
+
attr_reader :host, :status, :retry_after, :diagnosis
|
|
42
42
|
attr_accessor :attempts
|
|
43
43
|
|
|
44
44
|
# @param host [String, nil] the host (or server label) that failed
|
|
45
45
|
# @param status [Integer, nil] the HTTP status, when there was one
|
|
46
46
|
# @param retry_after [Float, nil] seconds the server asked to wait
|
|
47
|
-
|
|
47
|
+
# @param diagnosis [String, nil] an optional provider diagnosis header
|
|
48
|
+
def initialize(message = nil, host: nil, status: nil, retryable: nil, retry_after: nil, diagnosis: nil, attempts: 1)
|
|
48
49
|
@host = host
|
|
49
50
|
@status = status
|
|
50
51
|
@retryable = retryable.nil? ? default_retryable? : retryable
|
|
51
52
|
@retry_after = retry_after
|
|
53
|
+
@diagnosis = diagnosis
|
|
52
54
|
@attempts = attempts
|
|
53
55
|
super(message)
|
|
54
56
|
end
|
|
@@ -402,10 +404,10 @@ module Samagotchi
|
|
|
402
404
|
# @param status [Integer]
|
|
403
405
|
# @param body [String] the response body (JSON or text)
|
|
404
406
|
# @param retry_after [String, nil] the Retry-After header
|
|
405
|
-
def from_response(status:, body:, host:, retry_after: nil)
|
|
407
|
+
def from_response(status:, body:, host:, retry_after: nil, diagnosis: nil)
|
|
406
408
|
message = error_message(body)
|
|
407
409
|
text = "#{host}: HTTP #{status}: #{message}"
|
|
408
|
-
options = { host: host, status: status }
|
|
410
|
+
options = { host: host, status: status, diagnosis: diagnosis }
|
|
409
411
|
if CONTEXT_OVERFLOW_RE.match?(message) || CONTEXT_OVERFLOW_RE.match?(body.to_s)
|
|
410
412
|
return BadRequest.new(text, context_overflow: true, **options)
|
|
411
413
|
end
|
data/lib/samagotchi/llm/http.rb
CHANGED
|
@@ -417,7 +417,8 @@ module Samagotchi
|
|
|
417
417
|
return if status.between?(200, 299)
|
|
418
418
|
|
|
419
419
|
error = ProviderErrors.from_response(status: status, body: response.body.to_s, host: @label,
|
|
420
|
-
retry_after: response["Retry-After"]
|
|
420
|
+
retry_after: response["Retry-After"],
|
|
421
|
+
diagnosis: response["anthropic-thinking-prefix-mismatch"])
|
|
421
422
|
error.hint ||= @api_key ? @api_key.hint : ApiKey.missing_hint(@label) if error.is_a?(AuthError)
|
|
422
423
|
raise error
|
|
423
424
|
end
|
|
@@ -37,12 +37,22 @@ module Samagotchi
|
|
|
37
37
|
# +stop_details+: why the provider stopped, when it says more than the
|
|
38
38
|
# finish reason (Messages' stop_details on a refusal: type, category,
|
|
39
39
|
# explanation; string keys); nil otherwise.
|
|
40
|
+
# +thinking_drop+: the replayed thinking blocks the provider dropped (or
|
|
41
|
+
# the adapter stripped) to answer a request whose history it had
|
|
42
|
+
# refused (ThinkingDrop, AnthropicMessages' binding recovery); nil
|
|
43
|
+
# otherwise.
|
|
40
44
|
ChatResponse = Data.define(:text, :reasoning, :tool_calls, :usage, :finish_reason, :model, :provider, :cut,
|
|
41
|
-
:top_logprobs, :provider_content, :stop_details) do
|
|
45
|
+
:top_logprobs, :provider_content, :stop_details, :thinking_drop) do
|
|
42
46
|
def initialize(model: nil, provider: nil, cut: nil, top_logprobs: [].freeze, provider_content: nil, stop_details: nil,
|
|
43
|
-
**fields) = super
|
|
47
|
+
thinking_drop: nil, **fields) = super
|
|
44
48
|
end
|
|
45
49
|
|
|
50
|
+
# Replayed thinking blocks a request went through without: their
|
|
51
|
+
# identities (AnthropicWire.block_identity, a frozen Array) and +how+:
|
|
52
|
+
# :drop_block (the provider dropped them, prefix_binding_mismatch) or
|
|
53
|
+
# :strip (the adapter removed them from the body).
|
|
54
|
+
ThinkingDrop = Data.define(:identities, :how)
|
|
55
|
+
|
|
46
56
|
# One alternative for an answer token: its text and log probability.
|
|
47
57
|
TokenLogprob = Data.define(:token, :logprob) do
|
|
48
58
|
# The first token's alternatives in a chat completion body's
|
|
@@ -4,8 +4,8 @@ require_relative "session"
|
|
|
4
4
|
require_relative "session_inbox"
|
|
5
5
|
|
|
6
6
|
module Samagotchi
|
|
7
|
-
# Loaded on first use:
|
|
8
|
-
#
|
|
7
|
+
# Loaded on first use: this autoload keeps SessionManager and its ~80
|
|
8
|
+
# files unloaded until the delegate/session path needs them.
|
|
9
9
|
autoload :SessionManager, File.expand_path("session_manager", __dir__)
|
|
10
10
|
|
|
11
11
|
# The one rule for putting a context note into a session, shared by
|
|
@@ -9,8 +9,8 @@ require_relative "../tools/delegate"
|
|
|
9
9
|
require_relative "../children_status"
|
|
10
10
|
|
|
11
11
|
module Samagotchi
|
|
12
|
-
# Loaded on first use:
|
|
13
|
-
#
|
|
12
|
+
# Loaded on first use: this autoload keeps SessionManager and its ~80
|
|
13
|
+
# files unloaded until the delegate/session path needs them.
|
|
14
14
|
autoload :SessionManager, File.expand_path("../session_manager", __dir__)
|
|
15
15
|
|
|
16
16
|
module Plugin
|
|
@@ -6,9 +6,8 @@ require_relative "session_inbox"
|
|
|
6
6
|
require_relative "worker_sidecar"
|
|
7
7
|
|
|
8
8
|
module Samagotchi
|
|
9
|
-
# Loaded on first use:
|
|
10
|
-
#
|
|
11
|
-
# otherwise).
|
|
9
|
+
# Loaded on first use: this autoload keeps SessionManager and its ~80
|
|
10
|
+
# files unloaded until the delegate/session path needs them.
|
|
12
11
|
autoload :SessionManager, File.expand_path("session_manager", __dir__)
|
|
13
12
|
|
|
14
13
|
# Waiting for a session's next reply. A reply is the worker's
|
|
@@ -37,7 +37,6 @@ require_relative "plugin_session_state"
|
|
|
37
37
|
require_relative "context_sources"
|
|
38
38
|
require_relative "session_chain"
|
|
39
39
|
require_relative "child_move"
|
|
40
|
-
require_relative "terminal_ui"
|
|
41
40
|
|
|
42
41
|
module Samagotchi
|
|
43
42
|
# SessionManager coordinates background session processes.
|
|
@@ -8,7 +8,7 @@ module Samagotchi
|
|
|
8
8
|
# mid-turn. The tool tallies (by tool, aliased, errors) are counted per
|
|
9
9
|
# tool record, not per turn: SessionMetrics keeps those apart.
|
|
10
10
|
class Totals < Data.define(
|
|
11
|
-
:cancellations, :iterations, :gen_ms, :retries, :cuts, :capped,
|
|
11
|
+
:cancellations, :iterations, :gen_ms, :retries, :cuts, :capped, :thinking_dropped,
|
|
12
12
|
:prompt_sum, :completion_sum, :cached_sum, :cache_write_sum, :reprefill_sum, :reasoning_sum,
|
|
13
13
|
:cost_sum, :cost_estimate_sum, :decode_ms_sum, :decode_tokens_sum,
|
|
14
14
|
# The newest speeds a record has, and where the decode one came from.
|
|
@@ -19,7 +19,8 @@ module Samagotchi
|
|
|
19
19
|
# The record keys each sum adds up (a turn record's own names).
|
|
20
20
|
RECORD_SUMS = {
|
|
21
21
|
prompt_sum: :prompt_tokens_sum, completion_sum: :completion_tokens, iterations: :iterations,
|
|
22
|
-
gen_ms: :gen_ms, retries: :retries, cuts: :cuts, capped: :capped,
|
|
22
|
+
gen_ms: :gen_ms, retries: :retries, cuts: :cuts, capped: :capped, thinking_dropped: :thinking_dropped,
|
|
23
|
+
cached_sum: :cached_tokens_sum,
|
|
23
24
|
cache_write_sum: :cache_write_tokens_sum, reprefill_sum: :reprefill_tokens_sum,
|
|
24
25
|
reasoning_sum: :reasoning_tokens, cost_sum: :cost, cost_estimate_sum: :cost_estimate,
|
|
25
26
|
decode_ms_sum: :decode_ms, decode_tokens_sum: :decode_tokens
|
|
@@ -28,7 +29,7 @@ module Samagotchi
|
|
|
28
29
|
# The running turn's (TurnState) counters each sum adds while it runs.
|
|
29
30
|
TURN_SUMS = {
|
|
30
31
|
iterations: :iteration_count, gen_ms: :gen_latency_accum, retries: :retries, cuts: :cuts,
|
|
31
|
-
capped: :capped, prompt_sum: :prompt_sum, completion_sum: :completion_sum, cached_sum: :cached_sum,
|
|
32
|
+
capped: :capped, thinking_dropped: :thinking_dropped, prompt_sum: :prompt_sum, completion_sum: :completion_sum, cached_sum: :cached_sum,
|
|
32
33
|
cache_write_sum: :cache_write_sum, reprefill_sum: :reprefill_sum, reasoning_sum: :reasoning_sum,
|
|
33
34
|
cost_sum: :cost_sum, cost_estimate_sum: :cost_estimate_sum, decode_ms_sum: :decode_ms_sum,
|
|
34
35
|
decode_tokens_sum: :decode_tokens_sum
|
|
@@ -144,6 +144,9 @@ module Samagotchi
|
|
|
144
144
|
# (finish_reason length). `retries` counts the network's only.
|
|
145
145
|
:cuts,
|
|
146
146
|
:capped,
|
|
147
|
+
# Replayed thinking blocks a preserved-thinking recovery dropped
|
|
148
|
+
# (:generation_completed's thinking_dropped, ChatLoop).
|
|
149
|
+
:thinking_dropped,
|
|
147
150
|
:model,
|
|
148
151
|
# The model the turn ran on (asked host:model, :generation_started's
|
|
149
152
|
# model_ref; the first generation's), and whether its open generation
|
|
@@ -505,6 +508,7 @@ module Samagotchi
|
|
|
505
508
|
retries: totals.retries,
|
|
506
509
|
cuts: totals.cuts,
|
|
507
510
|
capped: totals.capped,
|
|
511
|
+
thinking_dropped: totals.thinking_dropped,
|
|
508
512
|
started_at: @started_at,
|
|
509
513
|
last_activity_at: @last_activity_at,
|
|
510
514
|
# From the session's first start (an earlier process's too), to now.
|
|
@@ -589,6 +593,7 @@ module Samagotchi
|
|
|
589
593
|
retries: 0,
|
|
590
594
|
cuts: 0,
|
|
591
595
|
capped: 0,
|
|
596
|
+
thinking_dropped: 0,
|
|
592
597
|
model: nil,
|
|
593
598
|
model_ref: nil,
|
|
594
599
|
gen_switch: false,
|
|
@@ -679,12 +684,15 @@ module Samagotchi
|
|
|
679
684
|
end
|
|
680
685
|
end
|
|
681
686
|
|
|
687
|
+
# A generation's cut, output cap and dropped thinking blocks, into the turn.
|
|
682
688
|
def count_cut(event)
|
|
683
689
|
@mutex.synchronize do
|
|
684
690
|
next unless @turn
|
|
685
691
|
|
|
686
692
|
@turn.cuts += 1 if event[:stopped_by] && event[:stopped_by].to_s != "steer"
|
|
687
693
|
@turn.capped += 1 if event[:finish_reason].to_s == "length"
|
|
694
|
+
dropped = event[:thinking_dropped]
|
|
695
|
+
@turn.thinking_dropped += dropped if dropped.is_a?(Integer) && dropped.positive?
|
|
688
696
|
end
|
|
689
697
|
end
|
|
690
698
|
|
|
@@ -872,6 +880,7 @@ module Samagotchi
|
|
|
872
880
|
}
|
|
873
881
|
fields[:cache_write_tokens_sum] = turn.cache_write_sum if turn.cache_write_sum.positive?
|
|
874
882
|
fields[:reprefill_tokens_sum] = turn.reprefill_sum if turn.reprefill_sum.positive?
|
|
883
|
+
fields[:thinking_dropped] = turn.thinking_dropped if turn.thinking_dropped.positive?
|
|
875
884
|
fields.merge!(cost: turn.cost_sum, cost_source: "reported") if turn.cost_sum
|
|
876
885
|
fields[:cost_estimate] = turn.cost_estimate_sum if turn.cost_estimate_sum.positive?
|
|
877
886
|
fields[:switch_prefill_tokens] = turn.switch_prefill_tokens if turn.switch_prefill_tokens
|
|
@@ -600,6 +600,9 @@ module Samagotchi
|
|
|
600
600
|
# A looped session: loop-guard's cuts, or thinking that ran to the cap.
|
|
601
601
|
lines << "thinking cuts: #{snapshot[:cuts].to_i}"
|
|
602
602
|
lines << "output cap hits: #{snapshot[:capped].to_i}"
|
|
603
|
+
# Claude 5.x: replayed thinking a prefix change made the API drop.
|
|
604
|
+
dropped = snapshot[:thinking_dropped].to_i
|
|
605
|
+
lines << "thinking dropped: #{dropped} blocks (preserved-thinking recovery)" if dropped.positive?
|
|
603
606
|
context = snapshot[:context] || {}
|
|
604
607
|
if context[:used_tokens]
|
|
605
608
|
pct = context_pct_text(context, snapshot[:llm_context])
|
|
@@ -42,8 +42,8 @@ require_relative "children_status"
|
|
|
42
42
|
require_relative "log"
|
|
43
43
|
|
|
44
44
|
module Samagotchi
|
|
45
|
-
# Loaded on first use:
|
|
46
|
-
#
|
|
45
|
+
# Loaded on first use: this autoload keeps SessionManager and its ~80
|
|
46
|
+
# files unloaded until the delegate/session path needs them.
|
|
47
47
|
autoload :SessionManager, File.expand_path("session_manager", __dir__)
|
|
48
48
|
|
|
49
49
|
# The in-process terminal front end (`chi --no-shared`, `chi scratch`,
|
|
@@ -10,8 +10,8 @@ require_relative "delegate_wait"
|
|
|
10
10
|
require_relative "../child_reports"
|
|
11
11
|
|
|
12
12
|
module Samagotchi
|
|
13
|
-
# Loaded on first use:
|
|
14
|
-
#
|
|
13
|
+
# Loaded on first use: this autoload keeps SessionManager and its ~80
|
|
14
|
+
# files unloaded until the delegate/session path needs them.
|
|
15
15
|
autoload :SessionManager, File.expand_path("../session_manager", __dir__)
|
|
16
16
|
|
|
17
17
|
module Tools
|
|
@@ -6,8 +6,8 @@ require_relative "delegate"
|
|
|
6
6
|
require_relative "delegate_wait"
|
|
7
7
|
|
|
8
8
|
module Samagotchi
|
|
9
|
-
# Loaded on first use:
|
|
10
|
-
#
|
|
9
|
+
# Loaded on first use: this autoload keeps SessionManager and its ~80
|
|
10
|
+
# files unloaded until the delegate/session path needs them.
|
|
11
11
|
autoload :SessionManager, File.expand_path("../session_manager", __dir__)
|
|
12
12
|
|
|
13
13
|
module Tools
|
|
@@ -6,8 +6,8 @@ require_relative "../session"
|
|
|
6
6
|
require_relative "peers"
|
|
7
7
|
|
|
8
8
|
module Samagotchi
|
|
9
|
-
# Loaded on first use:
|
|
10
|
-
#
|
|
9
|
+
# Loaded on first use: this autoload keeps SessionManager and its ~80
|
|
10
|
+
# files unloaded until the delegate/session path needs them.
|
|
11
11
|
autoload :SessionManager, File.expand_path("../session_manager", __dir__)
|
|
12
12
|
|
|
13
13
|
module Tools
|