samagotchi 0.70.0 → 0.72.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 +83 -1
- data/docs/architecture.md +16 -10
- data/docs/cli.md +7 -4
- data/docs/configuration.md +24 -14
- data/docs/hooks.md +1 -1
- data/docs/internals/anthropic.md +1 -1
- data/docs/internals/background-tasks.md +2 -2
- data/docs/internals/engine.md +38 -13
- data/docs/internals/llm-context-live.md +1 -1
- data/docs/internals/prompt-caching.md +6 -0
- data/docs/plugins.md +18 -7
- data/docs/sessions.md +4 -2
- data/docs/testing.md +12 -3
- data/lib/samagotchi/bootstrap/config_writer.rb +2 -3
- data/lib/samagotchi/bridge/turn_accumulator.rb +4 -1
- data/lib/samagotchi/bridge.rb +5 -2
- data/lib/samagotchi/broadcast/scope_card.rb +2 -2
- data/lib/samagotchi/bundles/claude-peer/manifest.yml +2 -7
- data/lib/samagotchi/bundles/claude-peer/plugin.rb +2 -2
- data/lib/samagotchi/bundles/codex-peer/manifest.yml +2 -6
- data/lib/samagotchi/bundles/codex-peer/plugin.rb +2 -2
- data/lib/samagotchi/bundles/coordinator/manifest.yml +8 -6
- data/lib/samagotchi/bundles/coordinator/plugin.rb +10 -0
- data/lib/samagotchi/bundles/coordinator/skill_coordinator.md +2 -1
- 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 +7 -25
- data/lib/samagotchi/context_note.rb +2 -6
- data/lib/samagotchi/effective_model.rb +1 -1
- data/lib/samagotchi/engine.rb +91 -213
- data/lib/samagotchi/engine_peers.rb +2 -0
- data/lib/samagotchi/event_routes.rb +83 -0
- data/lib/samagotchi/hook_routes.rb +16 -37
- data/lib/samagotchi/host_config.rb +1 -1
- data/lib/samagotchi/host_keys.rb +0 -2
- data/lib/samagotchi/paths.rb +13 -0
- data/lib/samagotchi/plugin/api.rb +11 -5
- data/lib/samagotchi/plugin/peer.rb +5 -8
- data/lib/samagotchi/prompt_files.rb +2 -4
- data/lib/samagotchi/session.rb +2 -1
- data/lib/samagotchi/session_manager.rb +6 -16
- data/lib/samagotchi/session_model_settings.rb +227 -0
- data/lib/samagotchi/session_setup.rb +2 -1
- data/lib/samagotchi/sessions_command.rb +12 -3
- data/lib/samagotchi/system_prompt.rb +18 -13
- data/lib/samagotchi/terminal_ui/attached_loop.rb +36 -15
- data/lib/samagotchi/terminal_ui/formatting.rb +4 -0
- data/lib/samagotchi/tool_activity.rb +20 -1
- data/lib/samagotchi/tool_declarations.rb +4 -0
- data/lib/samagotchi/tool_output_cut.rb +11 -2
- data/lib/samagotchi/toolkit.rb +60 -22
- data/lib/samagotchi/toolkit_binding.rb +7 -5
- data/lib/samagotchi/toolkit_command.rb +28 -5
- data/lib/samagotchi/tools/builtins.rb +2 -1
- data/lib/samagotchi/tools/delegate.rb +32 -6
- data/lib/samagotchi/tools/list_sessions.rb +2 -2
- data/lib/samagotchi/tools/peers.rb +5 -2
- data/lib/samagotchi/tools/register_reminder.rb +1 -0
- data/lib/samagotchi/tools/registry.rb +13 -2
- data/lib/samagotchi/tools/task_wait.rb +4 -6
- data/lib/samagotchi/tools/tool_index.rb +15 -4
- data/lib/samagotchi/turn_note.rb +4 -1
- data/lib/samagotchi/version.rb +1 -1
- data/lib/samagotchi/web/app.rb +18 -17
- data/lib/samagotchi/web/message_parts.rb +1 -1
- data/lib/samagotchi/web/public/answer_refs.js +1 -0
- data/lib/samagotchi/web/public/app.js +20 -18
- data/lib/samagotchi/web/public/bubbles.js +1 -1
- data/lib/samagotchi/web/public/cards_place.js +6 -10
- data/lib/samagotchi/web/public/chains.js +1 -1
- data/lib/samagotchi/web/public/chip_popover.js +3 -1
- data/lib/samagotchi/web/public/composer.js +13 -6
- data/lib/samagotchi/web/public/context_chips.js +25 -12
- data/lib/samagotchi/web/public/data.js +5 -1
- data/lib/samagotchi/web/public/format.js +5 -0
- data/lib/samagotchi/web/public/index.html +1 -0
- data/lib/samagotchi/web/public/sessions_list.js +2 -3
- data/lib/samagotchi/web/public/stage_frame.js +1 -1
- data/lib/samagotchi/web/public/stage_view.js +8 -2
- data/lib/samagotchi/web/public/stream_handlers.js +6 -3
- data/lib/samagotchi/web/public/timing.js +1 -1
- data/lib/samagotchi/web/public/toolkit_chip.js +3 -1
- data/lib/samagotchi/web/public/turn_html.js +55 -3
- data/lib/samagotchi/web/session_hub.rb +8 -0
- metadata +3 -1
|
@@ -11,6 +11,7 @@ import { activityDiffTemplate } from "./diff_view.js";
|
|
|
11
11
|
import { clip, steerSender } from "./format.js";
|
|
12
12
|
import { rowTitleRef } from "./refs.js";
|
|
13
13
|
import { readLinesTemplate } from "./read_view.js";
|
|
14
|
+
import { handedOverId } from "./task_stop.js";
|
|
14
15
|
import { STOPPED_LINE_CLASS, cancelLineText, formatDuration } from "./timing.js";
|
|
15
16
|
import { emptyAnswerLine } from "./turn_events.js";
|
|
16
17
|
|
|
@@ -73,12 +74,63 @@ function llmEditTemplate(row) {
|
|
|
73
74
|
return html`<div class="activity-edit" title=${hover}>${line}</div>`;
|
|
74
75
|
}
|
|
75
76
|
|
|
77
|
+
// What a done row shows of its output inline: its first INLINE_CHARS, else
|
|
78
|
+
// for an execute's result and a task_wait with its log's last lines its
|
|
79
|
+
// last ones (a test run's summary, a failing exit line). An execute drops a
|
|
80
|
+
// bare success "exit: 0" (the mark says it) and, with no stderr block, the
|
|
81
|
+
// lone "stdout:" label. A guardrail deny, an approval refused or an
|
|
82
|
+
// execute's error has its reason first, a hand-over its task_id: the head.
|
|
83
|
+
// A gate-corrected call's `ran as:` line shows on hover only.
|
|
84
|
+
const INLINE_CHARS = 300;
|
|
85
|
+
// The JS twin of ToolOutputCut::EXIT_LINE (tool_output_cut.rb): an exit line, then maybe a hint; a
|
|
86
|
+
// signal-killed command's has no number ("exit: ").
|
|
87
|
+
const EXIT_LINE = /\nexit: (?:-?\d+)?[^\n]*(?:\n\([^\n]*\))?$/;
|
|
88
|
+
// A bare success exit line; group 1 is the hint line after it, if any.
|
|
89
|
+
const SUCCESS_EXIT_LINE = /\nexit: 0(\n\([^\n]*\))?$/;
|
|
90
|
+
const EXECUTE_BLOCK = /(?:^|\n)(?:stdout|stderr):\n/;
|
|
91
|
+
const OUTPUT_TAIL = /^output_tail:$/m;
|
|
92
|
+
// A gate-corrected call's first line (ToolRunner#changed_call_line) and the "[tool]" lead after it, which
|
|
93
|
+
// the row's lead strip misses (it isn't first). The inline text drops both; the hover keeps them.
|
|
94
|
+
const RAN_AS_LEAD = /^ran as: [^\n]*\n(?:\[[^\]\s]+\](?:\n| ))?/;
|
|
95
|
+
|
|
96
|
+
export function inlineOutput(tool, full) {
|
|
97
|
+
const text = String(full ?? "").replace(RAN_AS_LEAD, "");
|
|
98
|
+
if (!tailMode(tool, text)) return clip(text, INLINE_CHARS + 1);
|
|
99
|
+
let shown = text;
|
|
100
|
+
if (tool === "execute") {
|
|
101
|
+
shown = shown.replace(SUCCESS_EXIT_LINE, (_, hint) => hint || "");
|
|
102
|
+
if (!text.includes("\nstderr:\n") && shown.startsWith("stdout:\n")) shown = shown.slice("stdout:\n".length);
|
|
103
|
+
}
|
|
104
|
+
shown = shown.replace(/\n+$/, "");
|
|
105
|
+
return tailClip(shown.trim() ? shown : text);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Whether a row's output shows its end (its div opens scrolled to the end).
|
|
109
|
+
export function tailMode(tool, text) {
|
|
110
|
+
if (tool === "task_wait") return OUTPUT_TAIL.test(text);
|
|
111
|
+
if (tool !== "execute" || handedOverId(text)) return false;
|
|
112
|
+
return EXECUTE_BLOCK.test(text) || EXIT_LINE.test(text);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// The text's end, as clip keeps its start: whole when it fits, else "…" and
|
|
116
|
+
// its last INLINE_CHARS, never from half an emoji, from a line's start when
|
|
117
|
+
// that keeps at least half of them (ToolOutputCut.cut_block's tail rule).
|
|
118
|
+
function tailClip(text) {
|
|
119
|
+
if (text.length <= INLINE_CHARS + 1) return text;
|
|
120
|
+
let kept = text.slice(-INLINE_CHARS);
|
|
121
|
+
const first = kept.charCodeAt(0);
|
|
122
|
+
if (first >= 0xdc00 && first <= 0xdfff) kept = kept.slice(1);
|
|
123
|
+
const nl = kept.indexOf("\n");
|
|
124
|
+
if (nl >= 0 && kept.length - nl - 1 >= INLINE_CHARS / 2) kept = kept.slice(nl + 1);
|
|
125
|
+
return `\u2026${kept}`;
|
|
126
|
+
}
|
|
127
|
+
|
|
76
128
|
// A tool row: its status mark, tool, title (else params; the full command,
|
|
77
129
|
// else the full params line, on hover), the word an exception shows, the
|
|
78
130
|
// call's duration, the full command (an execute/task_create's view, also
|
|
79
131
|
// while it runs), the output once done (its "[tool]" tag dropped, 300 chars,
|
|
80
|
-
// the rest on hover; a read
|
|
81
|
-
// closed: read_view.js), its images (+thumbs+(images) draws them) and an
|
|
132
|
+
// an execute/task_wait's last ones (inlineOutput), the rest on hover; a read
|
|
133
|
+
// of the file as-is also its numbered lines, closed: read_view.js), its images (+thumbs+(images) draws them) and an
|
|
82
134
|
// edit's collapsed diff, and a reloaded row's ✂ mark above its output. A
|
|
83
135
|
// part with nothing to say is left out. A reload renders toolRowTemplate;
|
|
84
136
|
// the live view renders toolRowInnerTemplate into its own row element
|
|
@@ -107,7 +159,7 @@ export function toolRowInnerTemplate(row, { thumbs = () => nothing, stop = nothi
|
|
|
107
159
|
const duration = formatDuration(row.duration_ms);
|
|
108
160
|
const full = row.status === "running" ? "" : String(row.output || "").replace(/^\[[^\]]*\]\s*/, "");
|
|
109
161
|
const output = full
|
|
110
|
-
? html`<div class
|
|
162
|
+
? html`<div class=${tailMode(row.tool, full) ? "activity-output tail" : "activity-output"} title=${full}>${inlineOutput(row.tool, full)}</div>`
|
|
111
163
|
: nothing;
|
|
112
164
|
const status = statusParts(row.status, { noMatch: !!row.no_match });
|
|
113
165
|
return html`${statusMarkTemplate(status)}<span class="activity-tool">${toolName(row)}</span>${params}${stop}${alias}${statusWordTemplate(status)}${duration ? html`<span class="activity-duration">${duration}</span>` : nothing}${commandBlockTemplate(row.view, row.title)}${llmEditTemplate(row)}${output}${full ? readLinesTemplate(row) : nothing}${row.images?.length ? thumbs(row.images) : nothing}${row.diff ? activityDiffTemplate(row.diff) : nothing}`;
|
|
@@ -172,6 +172,14 @@ module Samagotchi
|
|
|
172
172
|
end
|
|
173
173
|
end
|
|
174
174
|
|
|
175
|
+
# A session's folder as the projection holds it (its file's, read at
|
|
176
|
+
# the last scan or touch): what a live read that loads no session
|
|
177
|
+
# file checks refs against. nil for a session the hub hasn't seen.
|
|
178
|
+
# @return [String, nil]
|
|
179
|
+
def working_directory(id)
|
|
180
|
+
@monitor.synchronize { @sessions[id]&.session&.working_directory }
|
|
181
|
+
end
|
|
182
|
+
|
|
175
183
|
# Register a sink (#call(event)). With +snapshot:+ the current
|
|
176
184
|
# projection comes back with the handle, taken in the same step, so
|
|
177
185
|
# every event after it is newer than it.
|
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.72.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Dmitry Dedov
|
|
@@ -279,6 +279,7 @@ files:
|
|
|
279
279
|
- lib/samagotchi/empty_answer_retry.rb
|
|
280
280
|
- lib/samagotchi/engine.rb
|
|
281
281
|
- lib/samagotchi/engine_peers.rb
|
|
282
|
+
- lib/samagotchi/event_routes.rb
|
|
282
283
|
- lib/samagotchi/events.rb
|
|
283
284
|
- lib/samagotchi/extension_load.rb
|
|
284
285
|
- lib/samagotchi/file_ref.rb
|
|
@@ -459,6 +460,7 @@ files:
|
|
|
459
460
|
- lib/samagotchi/session_inbox.rb
|
|
460
461
|
- lib/samagotchi/session_manager.rb
|
|
461
462
|
- lib/samagotchi/session_metrics.rb
|
|
463
|
+
- lib/samagotchi/session_model_settings.rb
|
|
462
464
|
- lib/samagotchi/session_observer.rb
|
|
463
465
|
- lib/samagotchi/session_retention.rb
|
|
464
466
|
- lib/samagotchi/session_setting.rb
|