samagotchi 0.4.0 → 0.5.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 +80 -1
- data/README.md +13 -2
- data/bin/chi +29 -39
- data/docs/cli.md +135 -73
- data/docs/configuration.md +15 -20
- data/docs/hooks.md +1 -1
- data/docs/memory.md +40 -0
- data/docs/plugins.md +50 -0
- data/docs/releasing.md +9 -6
- data/docs/sessions.md +3 -3
- data/lib/samagotchi/bootstrap/config_writer.rb +1 -2
- data/lib/samagotchi/bridge/sse_writer.rb +0 -3
- data/lib/samagotchi/bridge/turn_accumulator.rb +1 -0
- data/lib/samagotchi/bridge.rb +16 -11
- data/lib/samagotchi/bundles/skills/manifest.yml +10 -0
- data/lib/samagotchi/bundles/skills/plugin.rb +419 -0
- data/lib/samagotchi/bundles/system/config_modification_protocol.md +7 -8
- data/lib/samagotchi/bundles/system/identity.md +5 -0
- data/lib/samagotchi/bundles/system/manifest.yml +5 -5
- data/lib/samagotchi/bundles/system/memory_guide.md +26 -0
- data/lib/samagotchi/bundles/system/self_map.md +2 -1
- data/lib/samagotchi/client.rb +16 -20
- data/lib/samagotchi/config.rb +40 -100
- data/lib/samagotchi/engine.rb +50 -354
- data/lib/samagotchi/kernel_loop.rb +33 -44
- data/lib/samagotchi/live_versions.rb +7 -1
- data/lib/samagotchi/llm/errors.rb +17 -0
- data/lib/samagotchi/llm/http.rb +4 -18
- data/lib/samagotchi/llm/openai_chat.rb +17 -0
- data/lib/samagotchi/model_profile.rb +4 -10
- data/lib/samagotchi/note_command.rb +2 -1
- data/lib/samagotchi/reply_wait.rb +48 -4
- data/lib/samagotchi/self_report.rb +20 -2
- data/lib/samagotchi/send_command.rb +84 -6
- data/lib/samagotchi/session.rb +4 -2
- data/lib/samagotchi/session_manager.rb +18 -37
- data/lib/samagotchi/system_prompt.rb +403 -0
- data/lib/samagotchi/terminal_ui/attach_launcher.rb +5 -3
- data/lib/samagotchi/terminal_ui/attached_loop.rb +120 -83
- data/lib/samagotchi/terminal_ui/attached_view.rb +27 -12
- data/lib/samagotchi/terminal_ui/event_renderer.rb +23 -7
- data/lib/samagotchi/terminal_ui/formatting.rb +32 -22
- data/lib/samagotchi/terminal_ui/input_support.rb +3 -4
- data/lib/samagotchi/terminal_ui/plain_surface.rb +13 -7
- data/lib/samagotchi/terminal_ui/status_row.rb +81 -0
- data/lib/samagotchi/terminal_ui/surface.rb +1 -1
- data/lib/samagotchi/terminal_ui.rb +95 -690
- data/lib/samagotchi/thinking.rb +11 -0
- data/lib/samagotchi/tool_activity.rb +52 -2
- data/lib/samagotchi/tool_runner.rb +3 -0
- data/lib/samagotchi/tools/execute.rb +3 -3
- data/lib/samagotchi/tools/output_guardrails.rb +8 -7
- data/lib/samagotchi/tools/read.rb +4 -4
- data/lib/samagotchi/update_command.rb +2 -1
- data/lib/samagotchi/version.rb +1 -1
- data/lib/samagotchi/web/app.rb +170 -35
- data/lib/samagotchi/web/lan.rb +99 -0
- data/lib/samagotchi/web/message_parts.rb +15 -11
- data/lib/samagotchi/web/public/activity.js +7 -0
- data/lib/samagotchi/web/public/app.js +99 -54
- data/lib/samagotchi/web/public/chat_view.js +5 -1
- data/lib/samagotchi/web/public/index.html +163 -17
- data/lib/samagotchi/web/public/model_pick.js +136 -0
- data/lib/samagotchi/web/public/model_picker.js +224 -0
- data/lib/samagotchi/web/public/notify.js +10 -0
- data/lib/samagotchi/web/public/stage_model.js +110 -0
- data/lib/samagotchi/web/public/stage_view.js +580 -0
- data/lib/samagotchi/web/public/timing.js +6 -2
- data/lib/samagotchi/web/public/turn_events.js +9 -5
- data/lib/samagotchi/web/public/turn_model.js +11 -3
- data/lib/samagotchi/web/public/turn_view.js +74 -19
- data/lib/samagotchi/web/qr.rb +40 -0
- data/lib/samagotchi/web/server.rb +101 -11
- data/lib/samagotchi/web/token.rb +97 -0
- metadata +27 -3
- data/lib/samagotchi/terminal_ui/legacy_surface.rb +0 -111
|
@@ -6,17 +6,19 @@ require_relative "surface"
|
|
|
6
6
|
|
|
7
7
|
module Samagotchi
|
|
8
8
|
class TerminalUI
|
|
9
|
-
#
|
|
9
|
+
# Both TUIs' Surface when a live region can't be drawn (output or
|
|
10
10
|
# input not a terminal, TERM=dumb, or a Reline the seam doesn't support):
|
|
11
11
|
# append-only output. Committed text and the notes, status and hints rows
|
|
12
12
|
# print as lines. The activity slot is dropped, because redrawing it in
|
|
13
13
|
# place needs cursor movement (the turn's lines still print as they end).
|
|
14
|
-
# The prompt is Reline's
|
|
14
|
+
# The prompt is Reline's own, so output may cross it; the editor slot
|
|
15
|
+
# prints the prompt of a plain read (the REPL's ? off a terminal).
|
|
15
16
|
class PlainSurface
|
|
16
17
|
include Surface
|
|
17
18
|
|
|
18
|
-
# @param out [IO]
|
|
19
|
-
|
|
19
|
+
# @param out [IO, nil] nil writes to $stdout as it is at each write
|
|
20
|
+
# (specs swap it after the UI is built)
|
|
21
|
+
def initialize(out: nil)
|
|
20
22
|
@out = out
|
|
21
23
|
@lock = Monitor.new
|
|
22
24
|
end
|
|
@@ -27,15 +29,15 @@ module Samagotchi
|
|
|
27
29
|
def columns = IO.console&.winsize&.last || 80
|
|
28
30
|
|
|
29
31
|
def commit(text)
|
|
30
|
-
synchronize {
|
|
32
|
+
synchronize { out.puts(text) }
|
|
31
33
|
end
|
|
32
34
|
|
|
33
35
|
def set_slot(name, rows)
|
|
34
36
|
check_slot!(name)
|
|
35
|
-
raise ArgumentError, "Reline draws the editor slot" if name == :editor
|
|
36
37
|
return if name == :activity
|
|
38
|
+
return synchronize { out.print(Array(rows).join("\n")) && out.flush } if name == :editor
|
|
37
39
|
|
|
38
|
-
synchronize { lay_out(rows, width: columns).each { |row|
|
|
40
|
+
synchronize { lay_out(rows, width: columns).each { |row| out.puts(row) } }
|
|
39
41
|
end
|
|
40
42
|
|
|
41
43
|
# Nothing printed can be taken back.
|
|
@@ -46,6 +48,10 @@ module Samagotchi
|
|
|
46
48
|
end
|
|
47
49
|
|
|
48
50
|
def close; end
|
|
51
|
+
|
|
52
|
+
private
|
|
53
|
+
|
|
54
|
+
def out = @out || $stdout
|
|
49
55
|
end
|
|
50
56
|
end
|
|
51
57
|
end
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "formatting"
|
|
4
|
+
|
|
5
|
+
module Samagotchi
|
|
6
|
+
class TerminalUI
|
|
7
|
+
# The status row under the prompt, the same for both TUIs:
|
|
8
|
+
# `status> model=… | ↳ parent | ctx=12.3% (under20) | mem: … | muted: …`.
|
|
9
|
+
# A UI feeds it what it learns (attached mode from the Bridge's events,
|
|
10
|
+
# the REPL from its Engine's) through #update, and the row is redrawn in
|
|
11
|
+
# the surface's status slot only when its text changes.
|
|
12
|
+
class StatusRow
|
|
13
|
+
include Formatting
|
|
14
|
+
|
|
15
|
+
# Memory names shown before ", +N".
|
|
16
|
+
MEMORY_LIMIT = 8
|
|
17
|
+
# What the row shows:
|
|
18
|
+
# model, default_model the model in use, and the config's default
|
|
19
|
+
# (named beside another model)
|
|
20
|
+
# served [served, asked]: what the server said it
|
|
21
|
+
# served for the name asked (ServedModel)
|
|
22
|
+
# parent_id the session that delegated this one
|
|
23
|
+
# context the kernel's estimate {est_pct:, bucket:}
|
|
24
|
+
# used_memories the memories the session read
|
|
25
|
+
# preloaded its --memory list (shown until a turn
|
|
26
|
+
# records them as used)
|
|
27
|
+
# muted its --mute list
|
|
28
|
+
FIELDS = %i[model default_model served parent_id context used_memories preloaded muted].freeze
|
|
29
|
+
|
|
30
|
+
# @param surface [Surface] with #columns
|
|
31
|
+
def initialize(surface)
|
|
32
|
+
@surface = surface
|
|
33
|
+
@values = { used_memories: [], preloaded: [], muted: [] }
|
|
34
|
+
@shown = nil
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# The surface it draws on (the REPL swaps in a live region): the row
|
|
38
|
+
# is drawn there at the next change.
|
|
39
|
+
def surface=(surface)
|
|
40
|
+
@surface = surface
|
|
41
|
+
@shown = nil
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def [](field) = @values[field]
|
|
45
|
+
|
|
46
|
+
# Change some fields; the row is redrawn when its text changed.
|
|
47
|
+
def update(**fields)
|
|
48
|
+
unknown = fields.keys - FIELDS
|
|
49
|
+
raise ArgumentError, "unknown status field(s): #{unknown.join(", ")}" if unknown.any?
|
|
50
|
+
|
|
51
|
+
@values.merge!(fields)
|
|
52
|
+
refresh
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Draw the row unless it shows that already (status.line: off draws
|
|
56
|
+
# nothing).
|
|
57
|
+
def refresh
|
|
58
|
+
return unless status_line_enabled?
|
|
59
|
+
|
|
60
|
+
rows = rows(@surface.columns - 1)
|
|
61
|
+
return if rows == @shown
|
|
62
|
+
|
|
63
|
+
@shown = rows
|
|
64
|
+
rows.empty? ? @surface.clear_slot(:status) : @surface.set_slot(:status, rows)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# @return [Array<String>] the row cut to +width+ (none with nothing to say)
|
|
68
|
+
def rows(width)
|
|
69
|
+
served, served_for = @values[:served]
|
|
70
|
+
model = @values[:model]
|
|
71
|
+
parent = @values[:parent_id]
|
|
72
|
+
segments = [model ? status_model_text(model, @values[:default_model], served: served, served_for: served_for) : "",
|
|
73
|
+
parent ? "↳ #{parent.to_s[0, 8]}" : "",
|
|
74
|
+
status_context_text(estimate: @values[:context]),
|
|
75
|
+
status_memory_text(Array(@values[:used_memories]) | Array(@values[:preloaded]), MEMORY_LIMIT),
|
|
76
|
+
status_memory_text(@values[:muted], MEMORY_LIMIT, label: "muted")].reject(&:empty?)
|
|
77
|
+
status_rows(segments, width)
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
@@ -15,7 +15,7 @@ module Samagotchi
|
|
|
15
15
|
#
|
|
16
16
|
# The slots, top down around the prompt: +activity+ (spinner, thinking
|
|
17
17
|
# preview), +editor+ (the prompt), +status+, +notes+ (question choices),
|
|
18
|
-
# +hints+. An implementation without a live region (
|
|
18
|
+
# +hints+. An implementation without a live region (PlainSurface) may
|
|
19
19
|
# print a slot's rows as plain output instead, so the rows stay on screen.
|
|
20
20
|
#
|
|
21
21
|
# Instead of rows, a slot may hold content that lays itself out: anything
|