samagotchi 0.2.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 +7 -0
- data/CHANGELOG.md +43 -0
- data/LICENSE +21 -0
- data/README.md +126 -0
- data/bin/chi +1140 -0
- data/docs/architecture.md +299 -0
- data/docs/cli.md +490 -0
- data/docs/configuration.md +494 -0
- data/docs/desktop.md +97 -0
- data/docs/guardrails.md +218 -0
- data/docs/hooks.md +309 -0
- data/docs/internals/background-tasks.md +26 -0
- data/docs/internals/context-telemetry.md +36 -0
- data/docs/internals/gemma4-contract.md +23 -0
- data/docs/internals/tool-guardrails.md +45 -0
- data/docs/memory.md +85 -0
- data/docs/plugins.md +819 -0
- data/docs/releasing.md +135 -0
- data/docs/sessions.md +155 -0
- data/lib/samagotchi/bridge/bounded_queue.rb +70 -0
- data/lib/samagotchi/bridge/card_store.rb +126 -0
- data/lib/samagotchi/bridge/event_id.rb +25 -0
- data/lib/samagotchi/bridge/ring_buffer.rb +63 -0
- data/lib/samagotchi/bridge/sse_writer.rb +248 -0
- data/lib/samagotchi/bridge/turn_accumulator.rb +189 -0
- data/lib/samagotchi/bridge.rb +993 -0
- data/lib/samagotchi/bridge_client/event_stream.rb +158 -0
- data/lib/samagotchi/bridge_client/sse_parser.rb +51 -0
- data/lib/samagotchi/bridge_client.rb +330 -0
- data/lib/samagotchi/bundle_needs.rb +97 -0
- data/lib/samagotchi/bundles/btw/manifest.yml +10 -0
- data/lib/samagotchi/bundles/btw/plugin.rb +100 -0
- data/lib/samagotchi/bundles/guardrails/guardrails/rules.yml +82 -0
- data/lib/samagotchi/bundles/guardrails/guardrails.md +14 -0
- data/lib/samagotchi/bundles/guardrails/manifest.yml +8 -0
- data/lib/samagotchi/bundles/known-names/hooks/known_names.rb +210 -0
- data/lib/samagotchi/bundles/known-names/known_names.md +3 -0
- data/lib/samagotchi/bundles/known-names/manifest.yml +14 -0
- data/lib/samagotchi/bundles/loop-guard/manifest.yml +10 -0
- data/lib/samagotchi/bundles/loop-guard/plugin.rb +158 -0
- data/lib/samagotchi/bundles/mcp/manifest.yml +11 -0
- data/lib/samagotchi/bundles/mcp/plugin.rb +631 -0
- data/lib/samagotchi/bundles/system/config_modification_protocol.md +149 -0
- data/lib/samagotchi/bundles/system/delegated.md +10 -0
- data/lib/samagotchi/bundles/system/identity.md +7 -0
- data/lib/samagotchi/bundles/system/manifest.yml +11 -0
- data/lib/samagotchi/bundles/system/memory_guide.md +107 -0
- data/lib/samagotchi/bundles/system/self_map.md +55 -0
- data/lib/samagotchi/cancellation_controller.rb +78 -0
- data/lib/samagotchi/client.rb +429 -0
- data/lib/samagotchi/commands/registry.rb +112 -0
- data/lib/samagotchi/config.rb +910 -0
- data/lib/samagotchi/context_note.rb +77 -0
- data/lib/samagotchi/context_quote.rb +21 -0
- data/lib/samagotchi/context_usage.rb +66 -0
- data/lib/samagotchi/context_window.rb +76 -0
- data/lib/samagotchi/debug_log.rb +110 -0
- data/lib/samagotchi/desktop/macos/App.swift +102 -0
- data/lib/samagotchi/desktop/macos/ChiRunner.swift +201 -0
- data/lib/samagotchi/desktop/macos/Hotkey.swift +42 -0
- data/lib/samagotchi/desktop/macos/Info.plist.erb +42 -0
- data/lib/samagotchi/desktop/macos/Panel.swift +383 -0
- data/lib/samagotchi/desktop/macos.rb +255 -0
- data/lib/samagotchi/desktop.rb +21 -0
- data/lib/samagotchi/desktop_command.rb +143 -0
- data/lib/samagotchi/engine.rb +2807 -0
- data/lib/samagotchi/guardrails/approval.rb +125 -0
- data/lib/samagotchi/guardrails/approvals.rb +177 -0
- data/lib/samagotchi/guardrails/context.rb +71 -0
- data/lib/samagotchi/guardrails/gate.rb +125 -0
- data/lib/samagotchi/guardrails/load_failures.rb +46 -0
- data/lib/samagotchi/guardrails/protected_paths.rb +77 -0
- data/lib/samagotchi/guardrails/rules.rb +199 -0
- data/lib/samagotchi/guardrails/targets.rb +119 -0
- data/lib/samagotchi/guardrails/verdict.rb +134 -0
- data/lib/samagotchi/guardrails.rb +18 -0
- data/lib/samagotchi/hooks/bundle_loader.rb +158 -0
- data/lib/samagotchi/hooks/loader.rb +162 -0
- data/lib/samagotchi/hooks/registry.rb +261 -0
- data/lib/samagotchi/hooks.rb +30 -0
- data/lib/samagotchi/host_registry.rb +315 -0
- data/lib/samagotchi/idle_client.rb +147 -0
- data/lib/samagotchi/idle_recap.rb +549 -0
- data/lib/samagotchi/idle_reminders.rb +101 -0
- data/lib/samagotchi/idle_scheduler.rb +76 -0
- data/lib/samagotchi/image_store.rb +393 -0
- data/lib/samagotchi/installed_gem.rb +38 -0
- data/lib/samagotchi/kernel_loop.rb +1017 -0
- data/lib/samagotchi/launch_mode.rb +34 -0
- data/lib/samagotchi/llm/backend.rb +28 -0
- data/lib/samagotchi/llm/chat_loop.rb +450 -0
- data/lib/samagotchi/llm/errors.rb +329 -0
- data/lib/samagotchi/llm/http.rb +412 -0
- data/lib/samagotchi/llm/model_result.rb +72 -0
- data/lib/samagotchi/llm/native_backend.rb +50 -0
- data/lib/samagotchi/llm/native_tool_normalizer.rb +277 -0
- data/lib/samagotchi/llm/openai_chat.rb +403 -0
- data/lib/samagotchi/llm/usage.rb +79 -0
- data/lib/samagotchi/log.rb +200 -0
- data/lib/samagotchi/log_line.rb +127 -0
- data/lib/samagotchi/log_path.rb +31 -0
- data/lib/samagotchi/log_subscriber.rb +163 -0
- data/lib/samagotchi/memory_bundle/builder.rb +364 -0
- data/lib/samagotchi/memory_bundle/index_updater.rb +123 -0
- data/lib/samagotchi/memory_bundle/installer.rb +528 -0
- data/lib/samagotchi/memory_bundle/listing.rb +72 -0
- data/lib/samagotchi/memory_bundle/manifest.rb +225 -0
- data/lib/samagotchi/memory_bundle/merger.rb +52 -0
- data/lib/samagotchi/memory_bundle/placeholder.rb +37 -0
- data/lib/samagotchi/memory_bundle/provenance.rb +257 -0
- data/lib/samagotchi/memory_bundle/source.rb +153 -0
- data/lib/samagotchi/memory_bundle/status.rb +107 -0
- data/lib/samagotchi/memory_bundle/system_bundle.rb +161 -0
- data/lib/samagotchi/memory_bundle/uninstaller.rb +128 -0
- data/lib/samagotchi/memory_bundle.rb +17 -0
- data/lib/samagotchi/memory_paths.rb +101 -0
- data/lib/samagotchi/model_overlay.rb +53 -0
- data/lib/samagotchi/model_profile.rb +309 -0
- data/lib/samagotchi/muted_memories.rb +66 -0
- data/lib/samagotchi/note_command.rb +163 -0
- data/lib/samagotchi/output_formatter.rb +100 -0
- data/lib/samagotchi/owner_lock.rb +110 -0
- data/lib/samagotchi/pending_input_queue.rb +48 -0
- data/lib/samagotchi/plugin/api.rb +362 -0
- data/lib/samagotchi/plugin/context.rb +193 -0
- data/lib/samagotchi/plugin/loader.rb +126 -0
- data/lib/samagotchi/plugin/service.rb +117 -0
- data/lib/samagotchi/plugin/sessions.rb +150 -0
- data/lib/samagotchi/plugin/side_question.rb +60 -0
- data/lib/samagotchi/plugin/tool_result.rb +24 -0
- data/lib/samagotchi/project_scope.rb +25 -0
- data/lib/samagotchi/prompt.rb +119 -0
- data/lib/samagotchi/prompt_literal_guard.rb +70 -0
- data/lib/samagotchi/recap_store.rb +92 -0
- data/lib/samagotchi/reminder_store.rb +165 -0
- data/lib/samagotchi/self_report.rb +195 -0
- data/lib/samagotchi/send_command.rb +170 -0
- data/lib/samagotchi/served_model.rb +32 -0
- data/lib/samagotchi/session.rb +508 -0
- data/lib/samagotchi/session_commands.rb +527 -0
- data/lib/samagotchi/session_delete_command.rb +105 -0
- data/lib/samagotchi/session_manager.rb +1049 -0
- data/lib/samagotchi/session_metrics.rb +466 -0
- data/lib/samagotchi/session_observer.rb +117 -0
- data/lib/samagotchi/terminal_ui/attach_launcher.rb +118 -0
- data/lib/samagotchi/terminal_ui/attached_loop.rb +1037 -0
- data/lib/samagotchi/terminal_ui/attached_view.rb +264 -0
- data/lib/samagotchi/terminal_ui/event_renderer.rb +192 -0
- data/lib/samagotchi/terminal_ui/formatting.rb +291 -0
- data/lib/samagotchi/terminal_ui/image_input.rb +36 -0
- data/lib/samagotchi/terminal_ui/input_support.rb +324 -0
- data/lib/samagotchi/terminal_ui/legacy_surface.rb +111 -0
- data/lib/samagotchi/terminal_ui/line_reader.rb +113 -0
- data/lib/samagotchi/terminal_ui/live_region.rb +36 -0
- data/lib/samagotchi/terminal_ui/plain_surface.rb +51 -0
- data/lib/samagotchi/terminal_ui/question_prompt.rb +153 -0
- data/lib/samagotchi/terminal_ui/question_slot.rb +131 -0
- data/lib/samagotchi/terminal_ui/reline_seam.rb +216 -0
- data/lib/samagotchi/terminal_ui/repl_input.rb +138 -0
- data/lib/samagotchi/terminal_ui/screen.rb +316 -0
- data/lib/samagotchi/terminal_ui/surface.rb +47 -0
- data/lib/samagotchi/terminal_ui/thinking_line.rb +101 -0
- data/lib/samagotchi/terminal_ui.rb +1992 -0
- data/lib/samagotchi/thinking_ticker.rb +110 -0
- data/lib/samagotchi/thought_stream_splitter.rb +149 -0
- data/lib/samagotchi/token_usage.rb +88 -0
- data/lib/samagotchi/tool_activity.rb +216 -0
- data/lib/samagotchi/tool_call_parser.rb +637 -0
- data/lib/samagotchi/tool_declarations.rb +561 -0
- data/lib/samagotchi/tool_runner.rb +211 -0
- data/lib/samagotchi/tools/args.rb +259 -0
- data/lib/samagotchi/tools/ask_user_question.rb +152 -0
- data/lib/samagotchi/tools/builtins.rb +122 -0
- data/lib/samagotchi/tools/cancel_reminder.rb +21 -0
- data/lib/samagotchi/tools/delegate.rb +167 -0
- data/lib/samagotchi/tools/delegate_result.rb +53 -0
- data/lib/samagotchi/tools/delegate_wait.rb +153 -0
- data/lib/samagotchi/tools/edit.rb +155 -0
- data/lib/samagotchi/tools/execute.rb +214 -0
- data/lib/samagotchi/tools/list_reminders.rb +20 -0
- data/lib/samagotchi/tools/list_sessions.rb +74 -0
- data/lib/samagotchi/tools/memory.rb +256 -0
- data/lib/samagotchi/tools/output_guardrails.rb +93 -0
- data/lib/samagotchi/tools/peers.rb +18 -0
- data/lib/samagotchi/tools/read.rb +182 -0
- data/lib/samagotchi/tools/register_reminder.rb +53 -0
- data/lib/samagotchi/tools/registry.rb +60 -0
- data/lib/samagotchi/tools/send_note.rb +49 -0
- data/lib/samagotchi/tools/task_create.rb +29 -0
- data/lib/samagotchi/tools/task_get.rb +39 -0
- data/lib/samagotchi/tools/task_list.rb +43 -0
- data/lib/samagotchi/tools/task_runtime.rb +311 -0
- data/lib/samagotchi/tools/task_stop.rb +29 -0
- data/lib/samagotchi/tools/task_wait.rb +104 -0
- data/lib/samagotchi/tools/tool_path.rb +18 -0
- data/lib/samagotchi/tools/web_fetch.rb +163 -0
- data/lib/samagotchi/tools/write.rb +26 -0
- data/lib/samagotchi/turn_flow.rb +242 -0
- data/lib/samagotchi/turn_note.rb +76 -0
- data/lib/samagotchi/turn_tally.rb +101 -0
- data/lib/samagotchi/version.rb +7 -0
- data/lib/samagotchi/vision_context.rb +132 -0
- data/lib/samagotchi/vision_support.rb +109 -0
- data/lib/samagotchi/web/app.rb +1349 -0
- data/lib/samagotchi/web/markdown_renderer.rb +107 -0
- data/lib/samagotchi/web/message_parts.rb +169 -0
- data/lib/samagotchi/web/public/activity.js +100 -0
- data/lib/samagotchi/web/public/annotations.js +67 -0
- data/lib/samagotchi/web/public/app.js +2382 -0
- data/lib/samagotchi/web/public/card.js +74 -0
- data/lib/samagotchi/web/public/chat_view.js +360 -0
- data/lib/samagotchi/web/public/chunk_router.js +25 -0
- data/lib/samagotchi/web/public/command_complete.js +39 -0
- data/lib/samagotchi/web/public/composer_size.js +19 -0
- data/lib/samagotchi/web/public/copy.js +142 -0
- data/lib/samagotchi/web/public/ctx.js +35 -0
- data/lib/samagotchi/web/public/data.js +256 -0
- data/lib/samagotchi/web/public/format.js +232 -0
- data/lib/samagotchi/web/public/hold.js +78 -0
- data/lib/samagotchi/web/public/images.js +77 -0
- data/lib/samagotchi/web/public/index.html +568 -0
- data/lib/samagotchi/web/public/init_row.js +60 -0
- data/lib/samagotchi/web/public/model_pick.js +23 -0
- data/lib/samagotchi/web/public/question_card.js +100 -0
- data/lib/samagotchi/web/public/route.js +17 -0
- data/lib/samagotchi/web/public/scope.js +36 -0
- data/lib/samagotchi/web/public/scroll.js +24 -0
- data/lib/samagotchi/web/public/sentences.js +88 -0
- data/lib/samagotchi/web/public/sessions_list.js +60 -0
- data/lib/samagotchi/web/public/strip.js +25 -0
- data/lib/samagotchi/web/public/tally.js +37 -0
- data/lib/samagotchi/web/public/thinking_ticker.js +79 -0
- data/lib/samagotchi/web/public/timing.js +185 -0
- data/lib/samagotchi/web/public/turn_events.js +209 -0
- data/lib/samagotchi/web/public/turn_model.js +204 -0
- data/lib/samagotchi/web/public/turn_view.js +587 -0
- data/lib/samagotchi/web/server.rb +183 -0
- data/lib/samagotchi/web/session_hub.rb +329 -0
- data/lib/samagotchi/web/session_summary.rb +85 -0
- data/lib/samagotchi/worker.rb +635 -0
- data/lib/samagotchi/worker_idle_exit.rb +87 -0
- data/lib/samagotchi.rb +12 -0
- metadata +374 -0
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "session"
|
|
4
|
+
require_relative "session_manager"
|
|
5
|
+
require_relative "context_quote"
|
|
6
|
+
|
|
7
|
+
module Samagotchi
|
|
8
|
+
# `chi send`: put text into sessions as the user's message, the same as
|
|
9
|
+
# typing it in the attached TUI or the web composer; the other half of
|
|
10
|
+
# `chi note`. Fire and forget: it returns once the message is queued, and
|
|
11
|
+
# the answer shows in whatever is attached. For a script:
|
|
12
|
+
# pbpaste | chi send -m "is this the same bug?" 3fa2
|
|
13
|
+
class SendCommand
|
|
14
|
+
CLIENT_ID = "cli:send"
|
|
15
|
+
|
|
16
|
+
USAGE = <<~TEXT
|
|
17
|
+
Usage: chi send [-m TEXT] (ID|PREFIX)...
|
|
18
|
+
Sends a message to each session, as if typed in it: a turn starts,
|
|
19
|
+
or a running one picks it up. A stopped session's worker starts.
|
|
20
|
+
-m TEXT the message; stdin, when piped too, goes above it as a
|
|
21
|
+
quote (context); without -m, stdin is the message
|
|
22
|
+
Only sessions on this machine. Answers show in the attached TUI
|
|
23
|
+
or web page, not here.
|
|
24
|
+
Find ids with: chi sessions list --live [--scope=all] [--format tsv]
|
|
25
|
+
TEXT
|
|
26
|
+
|
|
27
|
+
# @param argv [Array<String>] the arguments after "send"
|
|
28
|
+
def initialize(argv, stdin: $stdin, stdout: $stdout, stderr: $stderr, state_dir: nil)
|
|
29
|
+
@argv = argv.dup
|
|
30
|
+
@stdin = stdin
|
|
31
|
+
@stdout = stdout
|
|
32
|
+
@stderr = stderr
|
|
33
|
+
@state_dir = state_dir || Session.default_state_dir
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# @return [Integer] exit status: 0 all sent, 1 any refused or failed,
|
|
37
|
+
# 2 usage
|
|
38
|
+
def run
|
|
39
|
+
options = parse or return 2
|
|
40
|
+
return 0 if options[:help]
|
|
41
|
+
|
|
42
|
+
prompt = compose(utf8(read_stdin), utf8(options[:message]))
|
|
43
|
+
unless prompt
|
|
44
|
+
usage_error("no message: pass -m TEXT or pipe it in")
|
|
45
|
+
return 2
|
|
46
|
+
end
|
|
47
|
+
begin
|
|
48
|
+
prompt = SessionManager.checked_text(prompt, noun: "message")
|
|
49
|
+
rescue SessionManager::NoteRejected => e
|
|
50
|
+
@stderr.puts("chi send: #{e.message}")
|
|
51
|
+
return 1
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# One id at a time, so each line follows the order of the ids given.
|
|
55
|
+
seen = {}
|
|
56
|
+
results = options[:ids].uniq.map do |given|
|
|
57
|
+
id = resolve(given)
|
|
58
|
+
next false unless id
|
|
59
|
+
next true if seen[id]
|
|
60
|
+
|
|
61
|
+
seen[id] = true
|
|
62
|
+
deliver(id, prompt)
|
|
63
|
+
end
|
|
64
|
+
results.all? ? 0 : 1
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
private
|
|
68
|
+
|
|
69
|
+
def parse
|
|
70
|
+
options = { ids: [] }
|
|
71
|
+
until @argv.empty?
|
|
72
|
+
arg = @argv.shift
|
|
73
|
+
case arg
|
|
74
|
+
when "-h", "--help", "help"
|
|
75
|
+
@stdout.puts(USAGE)
|
|
76
|
+
return { help: true }
|
|
77
|
+
when "-m", "--message"
|
|
78
|
+
options[:message] = @argv.shift or return usage_error("#{arg} needs a value")
|
|
79
|
+
when /\A--message=(.*)\z/m then options[:message] = Regexp.last_match(1)
|
|
80
|
+
# Starting a turn in every live session at once is too easy to do
|
|
81
|
+
# by accident.
|
|
82
|
+
when "--all" then return usage_error("there is no --all: name the sessions")
|
|
83
|
+
when /\A-/ then return usage_error("unknown option #{arg}")
|
|
84
|
+
else options[:ids] << arg
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
return usage_error("give session ids") if options[:ids].empty?
|
|
88
|
+
|
|
89
|
+
options
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# With both, stdin is the context quoted above the message; with one,
|
|
93
|
+
# it goes in as is. nil when both are blank.
|
|
94
|
+
def compose(context, message)
|
|
95
|
+
context = nil if context.to_s.strip.empty?
|
|
96
|
+
message = nil if message.to_s.strip.empty?
|
|
97
|
+
return message || context unless context && message
|
|
98
|
+
|
|
99
|
+
"#{ContextQuote.block(context)}#{message}"
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# Only a pipe or a file is read. A terminal means nobody piped anything
|
|
103
|
+
# in, and a socket a launcher or an agent's shell passes down may never
|
|
104
|
+
# close: with -m, waiting on either would hang a script. (A pipe the
|
|
105
|
+
# caller never closes still hangs, as it would for cat.)
|
|
106
|
+
def read_stdin
|
|
107
|
+
return nil if @stdin.respond_to?(:tty?) && @stdin.tty?
|
|
108
|
+
if @stdin.respond_to?(:stat)
|
|
109
|
+
stat = @stdin.stat
|
|
110
|
+
return nil unless stat.pipe? || stat.file?
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
@stdin.read
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def resolve(given)
|
|
117
|
+
id = Session.resolve_id(given, state_dir: @state_dir)
|
|
118
|
+
Session.load(id, state_dir: @state_dir)
|
|
119
|
+
id
|
|
120
|
+
rescue ArgumentError => e
|
|
121
|
+
message = e.is_a?(Session::AmbiguousId) ? e.message : "no session #{given}"
|
|
122
|
+
error_line("chi send: #{message}")
|
|
123
|
+
nil
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
# @return [Boolean] whether the message was queued
|
|
127
|
+
def deliver(id, prompt)
|
|
128
|
+
short = id[0, 8]
|
|
129
|
+
owner = SessionManager.session_owner(id, state_dir: @state_dir)
|
|
130
|
+
running = owner && Session.load(id, state_dir: @state_dir).status == Session::STATUS_RUNNING
|
|
131
|
+
result = SessionManager.deliver_turn(id, prompt: prompt, client_id: CLIENT_ID, state_dir: @state_dir)
|
|
132
|
+
unless result[:status] == :accepted
|
|
133
|
+
@stdout.puts("#{short} failed: #{result.dig(:ack, "detail") || "could not queue it"}")
|
|
134
|
+
return false
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
note = if owner.nil? then " (started its worker)"
|
|
138
|
+
elsif running then " (the running turn picks it up)"
|
|
139
|
+
end
|
|
140
|
+
@stdout.puts("#{short} sent#{note}")
|
|
141
|
+
true
|
|
142
|
+
rescue SessionManager::OwnedByTUI
|
|
143
|
+
@stdout.puts("#{short} refused: it is open in a chi REPL; messages need attached mode")
|
|
144
|
+
false
|
|
145
|
+
rescue StandardError => e
|
|
146
|
+
@stdout.puts("#{short} failed: #{e.message}")
|
|
147
|
+
false
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
# The text as UTF-8 whatever the locale says: with no LANG/LC_* (an app
|
|
151
|
+
# started from Finder, launchd) stdin reads as US-ASCII and ARGV as
|
|
152
|
+
# binary. Invalid bytes become U+FFFD rather than an error.
|
|
153
|
+
def utf8(text)
|
|
154
|
+
text&.dup&.force_encoding(Encoding::UTF_8)&.scrub
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
# stderr isn't buffered, stdout is when it's a pipe: flush the lines
|
|
158
|
+
# already printed, so the output keeps the order of the ids given.
|
|
159
|
+
def error_line(text)
|
|
160
|
+
@stdout.flush
|
|
161
|
+
@stderr.puts(text)
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def usage_error(message)
|
|
165
|
+
error_line("chi send: #{message}")
|
|
166
|
+
@stderr.puts(USAGE)
|
|
167
|
+
nil
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Samagotchi
|
|
4
|
+
# The model a server says it served, which can differ from the name asked
|
|
5
|
+
# for: a single-model llama.cpp answers any name with the model it loaded.
|
|
6
|
+
# Servers name it in /props (llama.cpp's model_alias, before any turn) and
|
|
7
|
+
# in each response's `model` field (see the loops' :generation_completed).
|
|
8
|
+
module ServedModel
|
|
9
|
+
module_function
|
|
10
|
+
|
|
11
|
+
# @param props [Client::ServerProps, nil] a /props probe
|
|
12
|
+
# @return [String, nil] llama.cpp's model_alias when the probe answered
|
|
13
|
+
def from_props(props)
|
|
14
|
+
return nil unless props&.answered? && props.body.is_a?(Hash)
|
|
15
|
+
|
|
16
|
+
name = props.body["model_alias"]
|
|
17
|
+
name.is_a?(String) && !name.strip.empty? ? name : nil
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Whether +served+ is another model than +asked+. Names that are equal
|
|
21
|
+
# (any case) or where one extends the other (a provider dropping
|
|
22
|
+
# `:free`, or adding a date) are the same model; unknown names never
|
|
23
|
+
# differ.
|
|
24
|
+
def differs?(asked, served)
|
|
25
|
+
asked = asked.to_s.strip.downcase
|
|
26
|
+
served = served.to_s.strip.downcase
|
|
27
|
+
return false if asked.empty? || served.empty?
|
|
28
|
+
|
|
29
|
+
!(asked.start_with?(served) || served.start_with?(asked))
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|