samagotchi 0.58.0 → 0.59.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 +38 -1
- data/docs/architecture.md +3 -3
- data/docs/cli.md +5 -4
- data/docs/configuration.md +35 -20
- data/docs/hooks.md +2 -2
- data/docs/internals/background-tasks.md +7 -0
- data/docs/internals/engine.md +5 -5
- data/docs/internals/prompt-caching.md +2 -2
- data/docs/internals/tool-guardrails.md +2 -1
- data/docs/plugins.md +26 -6
- data/docs/sessions.md +1 -1
- data/lib/samagotchi/bridge/turn_accumulator.rb +1 -0
- data/lib/samagotchi/bridge.rb +6 -2
- data/lib/samagotchi/bundles/slow-commands/manifest.yml +5 -4
- data/lib/samagotchi/bundles/slow-commands/plugin.rb +169 -16
- data/lib/samagotchi/bundles/system/config_modification_protocol.md +1 -1
- data/lib/samagotchi/bundles/system/manifest.yml +2 -2
- data/lib/samagotchi/config.rb +11 -5
- data/lib/samagotchi/engine.rb +26 -1
- data/lib/samagotchi/host_config.rb +3 -1
- data/lib/samagotchi/host_registry.rb +2 -1
- data/lib/samagotchi/model_settings.rb +4 -2
- data/lib/samagotchi/process_group.rb +76 -3
- data/lib/samagotchi/send_command.rb +1 -1
- data/lib/samagotchi/session_commands.rb +15 -3
- data/lib/samagotchi/steer_cut.rb +12 -8
- data/lib/samagotchi/steer_cut_after.rb +69 -0
- data/lib/samagotchi/system_prompt.rb +5 -5
- data/lib/samagotchi/terminal_ui/attached_loop.rb +1 -1
- data/lib/samagotchi/terminal_ui/formatting.rb +9 -5
- data/lib/samagotchi/terminal_ui.rb +1 -1
- data/lib/samagotchi/tool_activity.rb +18 -1
- data/lib/samagotchi/tool_declarations.rb +1 -1
- data/lib/samagotchi/tools/execute.rb +318 -70
- data/lib/samagotchi/tools/task_get.rb +2 -0
- data/lib/samagotchi/tools/task_runtime.rb +96 -13
- data/lib/samagotchi/tools/task_wait.rb +23 -5
- data/lib/samagotchi/utf8_default.rb +1 -1
- data/lib/samagotchi/version.rb +1 -1
- data/lib/samagotchi/web/public/read_view.js +3 -1
- data/lib/samagotchi/web/public/task_stop.js +25 -7
- metadata +2 -1
|
@@ -10,6 +10,9 @@ module Samagotchi
|
|
|
10
10
|
TAIL_LINES_DEFAULT = 10
|
|
11
11
|
TAIL_LINES_MAX = 100
|
|
12
12
|
POLL_INTERVAL = 0.5
|
|
13
|
+
# A handed-over execute keeps stderr in a log of its own: at most this
|
|
14
|
+
# many of its last lines follow the output tail.
|
|
15
|
+
STDERR_TAIL_LINES_MAX = 10
|
|
13
16
|
|
|
14
17
|
def self.name = NAME
|
|
15
18
|
|
|
@@ -41,7 +44,7 @@ module Samagotchi
|
|
|
41
44
|
|
|
42
45
|
if completion_pattern
|
|
43
46
|
output_tail = output_tail(record, tail_lines)
|
|
44
|
-
return format_response(record, wait_result: "pattern_matched", output_tail: output_tail) if completion_pattern.match?(output_tail)
|
|
47
|
+
return format_response(record, wait_result: "pattern_matched", output_tail: output_tail, tail_lines: tail_lines) if completion_pattern.match?(output_tail)
|
|
45
48
|
end
|
|
46
49
|
|
|
47
50
|
return cancelled_response(task_id, tail_lines, started) if cancelled.call
|
|
@@ -55,7 +58,7 @@ module Samagotchi
|
|
|
55
58
|
refreshed, = TaskRuntime.get_record(task_id)
|
|
56
59
|
return finished_response(refreshed, tail_lines) unless refreshed.fetch("status") == "running"
|
|
57
60
|
|
|
58
|
-
format_response(refreshed, wait_result: "timeout", output_tail: output_tail(refreshed, tail_lines))
|
|
61
|
+
format_response(refreshed, wait_result: "timeout", output_tail: output_tail(refreshed, tail_lines), tail_lines: tail_lines)
|
|
59
62
|
rescue StandardError => e
|
|
60
63
|
"Error: #{e.message}"
|
|
61
64
|
end
|
|
@@ -72,7 +75,8 @@ module Samagotchi
|
|
|
72
75
|
" To keep waiting: task_wait #{task_id}. If it is stuck or no longer needed: task_stop #{task_id}.",
|
|
73
76
|
"waited: #{(monotonic_time - started).round}s"
|
|
74
77
|
]
|
|
75
|
-
format_response(record, wait_result: "canceled", output_tail: output_tail(record, tail_lines),
|
|
78
|
+
format_response(record, wait_result: "canceled", output_tail: output_tail(record, tail_lines), tail_lines: tail_lines,
|
|
79
|
+
extra: note)
|
|
76
80
|
end
|
|
77
81
|
private_class_method :cancelled_response
|
|
78
82
|
|
|
@@ -81,7 +85,8 @@ module Samagotchi
|
|
|
81
85
|
def self.finished_response(record, tail_lines)
|
|
82
86
|
return format_response(record) unless TaskRuntime.stopped_by_user?(record)
|
|
83
87
|
|
|
84
|
-
format_response(record, output_tail: output_tail(record, tail_lines),
|
|
88
|
+
format_response(record, output_tail: output_tail(record, tail_lines), tail_lines: tail_lines,
|
|
89
|
+
extra: [TaskRuntime::USER_STOP_NOTE])
|
|
85
90
|
end
|
|
86
91
|
private_class_method :finished_response
|
|
87
92
|
|
|
@@ -90,7 +95,17 @@ module Samagotchi
|
|
|
90
95
|
end
|
|
91
96
|
private_class_method :output_tail
|
|
92
97
|
|
|
93
|
-
|
|
98
|
+
# The last lines of a handed-over execute's stderr log (stderr_path),
|
|
99
|
+
# "" for a task_create task (one log) or an empty stderr.
|
|
100
|
+
def self.stderr_tail(record, tail_lines)
|
|
101
|
+
path = record["stderr_path"]
|
|
102
|
+
return "" if path.to_s.empty? || tail_lines.nil?
|
|
103
|
+
|
|
104
|
+
TaskRuntime.output_tail_lines(path, [tail_lines, STDERR_TAIL_LINES_MAX].min)
|
|
105
|
+
end
|
|
106
|
+
private_class_method :stderr_tail
|
|
107
|
+
|
|
108
|
+
def self.format_response(record, wait_result: nil, output_tail: nil, tail_lines: nil, extra: [])
|
|
94
109
|
lines = [
|
|
95
110
|
"task_id: #{record.fetch("id")}",
|
|
96
111
|
"status: #{record.fetch("status")}",
|
|
@@ -98,12 +113,15 @@ module Samagotchi
|
|
|
98
113
|
"stop_reason: #{record["stop_reason"]}",
|
|
99
114
|
"output_path: #{record.fetch("output_path")}"
|
|
100
115
|
]
|
|
116
|
+
lines << "stderr_path: #{record["stderr_path"]}" if record["stderr_path"]
|
|
101
117
|
return lines.join("\n") unless output_tail
|
|
102
118
|
|
|
103
119
|
lines << "wait_result: #{wait_result}" if wait_result
|
|
104
120
|
lines.concat(extra)
|
|
105
121
|
lines << "output_tail:"
|
|
106
122
|
lines << output_tail.rstrip unless output_tail.empty?
|
|
123
|
+
stderr_tail = stderr_tail(record, tail_lines)
|
|
124
|
+
lines.concat(["stderr_tail:", stderr_tail.rstrip]) unless stderr_tail.empty?
|
|
107
125
|
lines.join("\n")
|
|
108
126
|
end
|
|
109
127
|
private_class_method :format_response
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Samagotchi
|
|
4
|
-
# chi's files (memories,
|
|
4
|
+
# chi's files (memories, AGENTS.md, sessions, config.yml) are UTF-8,
|
|
5
5
|
# whatever the locale. Under LC_ALL=C (or with no locale at all: an app
|
|
6
6
|
# started from Finder or launchd, `env -i`) Ruby reads files as US-ASCII,
|
|
7
7
|
# and a UTF-8 memory index then breaks the system prompt
|
data/lib/samagotchi/version.rb
CHANGED
|
@@ -67,8 +67,10 @@ export function readLinesHtml(row) {
|
|
|
67
67
|
const first = numbered[0].line;
|
|
68
68
|
const last = numbered.at(-1).line;
|
|
69
69
|
const label = first === last ? `line ${first}` : `lines ${first}–${last}`;
|
|
70
|
+
// A blank line of the file holds no text, only a <br>: an empty block
|
|
71
|
+
// drops out of a copied selection, a space would be copied as one.
|
|
70
72
|
const spans = lines.map(({ text, line }) => line === null
|
|
71
73
|
? `<span class="read-line read-meta">${escapeHtml(text)}</span>`
|
|
72
|
-
: `<span class="read-line" data-line="${line}">${escapeHtml(text) || "
|
|
74
|
+
: `<span class="read-line" data-line="${line}">${escapeHtml(text) || "<br>"}</span>`).join("");
|
|
73
75
|
return `<details class="activity-read"><summary>${label}</summary><pre class="read-lines"><code>${spans}</code></pre></details>`;
|
|
74
76
|
}
|
|
@@ -22,10 +22,30 @@ export function stopTarget(row, features) {
|
|
|
22
22
|
// A task_wait row's title without its wait ("npm test · up to 600s").
|
|
23
23
|
const WAIT_SUFFIX = / · up to \d+s$/;
|
|
24
24
|
|
|
25
|
-
// The
|
|
26
|
-
//
|
|
27
|
-
//
|
|
28
|
-
//
|
|
25
|
+
// The first line of an execute that was still running at its limit and
|
|
26
|
+
// went on as a task (Tools::Execute::HANDED_OVER), then its task_id line.
|
|
27
|
+
// Anchored at the start, an optional "ran as: …" line and "[execute]" lead
|
|
28
|
+
// before it: a "task_id:" line anywhere else is the command's own output.
|
|
29
|
+
// The twin of TaskRuntime.handed_over_id.
|
|
30
|
+
const HANDED_OVER = /^(?:ran as: [^\n]*\n)?(?:\[execute\]\n)?Still running at the \d+s limit:[^\n]*\ntask_id: (\S+)/;
|
|
31
|
+
|
|
32
|
+
// The task id an execute row's output hands over, else null.
|
|
33
|
+
export function handedOverId(output) {
|
|
34
|
+
return HANDED_OVER.exec(output || "")?.[1] || null;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// The task id a row of this turn started: a task_create's, or an execute's
|
|
38
|
+
// hand-over (handedOverId); else null.
|
|
39
|
+
function startedId(row) {
|
|
40
|
+
if (row.tool === "execute") return handedOverId(row.output);
|
|
41
|
+
if (row.tool !== "task_create") return null;
|
|
42
|
+
return /(?:^|\n)task_id: (\S+)/.exec(row.output || "")?.[1] || null;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// The command a task_create or a handed-over execute of this turn started
|
|
46
|
+
// +taskId+ with (its row's view), else a task_wait row's title for it (the
|
|
47
|
+
// server titles one by its task's command, also for a task from an earlier
|
|
48
|
+
// turn: ToolActivity.task_title), or null.
|
|
29
49
|
export function taskCommand(gens, taskId) {
|
|
30
50
|
let titled = null;
|
|
31
51
|
for (const gen of gens || []) {
|
|
@@ -33,9 +53,7 @@ export function taskCommand(gens, taskId) {
|
|
|
33
53
|
if (row.tool === "task_wait" && row.view?.task_id === taskId && row.title) {
|
|
34
54
|
titled ||= row.title.replace(WAIT_SUFFIX, "");
|
|
35
55
|
}
|
|
36
|
-
if (row
|
|
37
|
-
const id = /(?:^|\n)task_id: (\S+)/.exec(row.output || "")?.[1];
|
|
38
|
-
if (id === taskId) return row.view?.command || null;
|
|
56
|
+
if (startedId(row) === taskId) return row.view?.command || null;
|
|
39
57
|
}
|
|
40
58
|
}
|
|
41
59
|
return titled;
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: samagotchi
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.59.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Dmitry Dedov
|
|
@@ -430,6 +430,7 @@ files:
|
|
|
430
430
|
- lib/samagotchi/setting_explained.rb
|
|
431
431
|
- lib/samagotchi/steer.rb
|
|
432
432
|
- lib/samagotchi/steer_cut.rb
|
|
433
|
+
- lib/samagotchi/steer_cut_after.rb
|
|
433
434
|
- lib/samagotchi/system_prompt.rb
|
|
434
435
|
- lib/samagotchi/terminal_ui.rb
|
|
435
436
|
- lib/samagotchi/terminal_ui/attach_launcher.rb
|