samagotchi 0.152.0 → 0.154.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 +45 -1
- data/README.md +2 -3
- data/bin/chi +23 -24
- data/docs/architecture.md +30 -33
- data/docs/broadcast.md +5 -5
- data/docs/bundle-authoring.md +1 -1
- data/docs/bundles.md +93 -12
- data/docs/cli.md +83 -99
- data/docs/configuration.md +46 -40
- data/docs/context.md +3 -3
- data/docs/desktop.md +1 -1
- data/docs/guardrails.md +15 -15
- data/docs/hooks.md +13 -12
- data/docs/internals/anthropic.md +3 -3
- data/docs/internals/attached-context.md +5 -2
- data/docs/internals/background-tasks.md +3 -4
- data/docs/internals/block-renderers.md +4 -0
- data/docs/internals/bridge.md +3 -3
- data/docs/internals/context-telemetry.md +1 -1
- data/docs/internals/engine.md +42 -12
- data/docs/internals/objectives.md +6 -5
- data/docs/internals/participants.md +8 -8
- data/docs/internals/prompt-caching.md +8 -4
- data/docs/internals/remote-sessions.md +7 -7
- data/docs/internals/web-frontend.md +20 -17
- data/docs/internals/web-push.md +1 -1
- data/docs/memory.md +2 -2
- data/docs/plugins.md +52 -43
- data/docs/releasing.md +1 -1
- data/docs/sessions.md +25 -25
- data/docs/sub-agent.md +2 -2
- data/docs/system-one.md +1 -1
- data/docs/testing.md +18 -8
- data/lib/samagotchi/answer_text.rb +34 -0
- data/lib/samagotchi/bridge.rb +43 -32
- data/lib/samagotchi/bridge_client.rb +10 -9
- data/lib/samagotchi/broadcast/recipients.rb +2 -2
- data/lib/samagotchi/broadcast/triage.rb +1 -1
- data/lib/samagotchi/broadcast_command.rb +5 -5
- data/lib/samagotchi/bundle_command/try/command.rb +1 -1
- data/lib/samagotchi/bundle_command/try/run.rb +1 -1
- data/lib/samagotchi/bundle_command.rb +2 -2
- data/lib/samagotchi/bundles/decision-card/manifest.yml +4 -4
- data/lib/samagotchi/bundles/decision-card/plugin.rb +1 -9
- data/lib/samagotchi/bundles/dev/manifest.yml +2 -2
- data/lib/samagotchi/bundles/system/config_modification_protocol.md +3 -4
- data/lib/samagotchi/bundles/system/manifest.yml +3 -3
- data/lib/samagotchi/bundles/system/self_map.md +1 -1
- data/lib/samagotchi/bundles/web-search/manifest.yml +13 -0
- data/lib/samagotchi/bundles/web-search/plugin.rb +174 -0
- data/lib/samagotchi/child_move.rb +3 -3
- data/lib/samagotchi/commands/registry.rb +6 -6
- data/lib/samagotchi/composer_route.rb +4 -5
- data/lib/samagotchi/config.rb +14 -12
- data/lib/samagotchi/context_candidate_choice.rb +1 -1
- data/lib/samagotchi/context_candidates.rb +4 -3
- data/lib/samagotchi/continue_offer.rb +1 -1
- data/lib/samagotchi/debug_log.rb +1 -1
- data/lib/samagotchi/degrade.rb +75 -0
- data/lib/samagotchi/desktop/macos/ChiRunner.swift +2 -2
- data/lib/samagotchi/engine/cards.rb +87 -0
- data/lib/samagotchi/engine/context_judge.rb +138 -0
- data/lib/samagotchi/engine/events.rb +131 -0
- data/lib/samagotchi/engine/guardrails.rb +87 -0
- data/lib/samagotchi/engine/hooks.rb +119 -0
- data/lib/samagotchi/engine/messages.rb +124 -0
- data/lib/samagotchi/engine/model_settings.rb +127 -0
- data/lib/samagotchi/engine/models.rb +261 -0
- data/lib/samagotchi/engine/objectives.rb +116 -0
- data/lib/samagotchi/engine/participants.rb +86 -0
- data/lib/samagotchi/engine/plugins.rb +208 -0
- data/lib/samagotchi/engine/questions.rb +98 -0
- data/lib/samagotchi/engine/recap.rb +130 -0
- data/lib/samagotchi/engine/session.rb +131 -0
- data/lib/samagotchi/engine/side_requests.rb +135 -0
- data/lib/samagotchi/engine/steering.rb +134 -0
- data/lib/samagotchi/engine/toolkit.rb +269 -0
- data/lib/samagotchi/engine/turn_end.rb +180 -0
- data/lib/samagotchi/engine/turn_helpers.rb +160 -0
- data/lib/samagotchi/engine/verify.rb +153 -0
- data/lib/samagotchi/engine.rb +63 -2642
- data/lib/samagotchi/grants.rb +575 -0
- data/lib/samagotchi/guardrail_wiring.rb +2 -2
- data/lib/samagotchi/guardrails/context.rb +2 -3
- data/lib/samagotchi/guardrails/parent_approvals.rb +2 -2
- data/lib/samagotchi/guardrails/parent_policy.rb +2 -2
- data/lib/samagotchi/guardrails/review_boundary.rb +4 -3
- data/lib/samagotchi/hook_routes.rb +3 -3
- data/lib/samagotchi/idle_recap.rb +4 -5
- data/lib/samagotchi/idle_reminders.rb +3 -4
- data/lib/samagotchi/iteration_limit.rb +2 -2
- data/lib/samagotchi/kernel_loop.rb +10 -11
- data/lib/samagotchi/launch_mode.rb +13 -32
- data/lib/samagotchi/level_setting_command.rb +3 -2
- data/lib/samagotchi/llm_context_command.rb +3 -2
- data/lib/samagotchi/llm_context_stale.rb +2 -2
- data/lib/samagotchi/log.rb +7 -7
- data/lib/samagotchi/log_line.rb +1 -1
- data/lib/samagotchi/log_path.rb +1 -1
- data/lib/samagotchi/message_parts.rb +3 -2
- data/lib/samagotchi/note_command.rb +1 -1
- data/lib/samagotchi/note_delivery.rb +18 -8
- data/lib/samagotchi/objectives.rb +24 -3
- data/lib/samagotchi/objectives_check.rb +8 -27
- data/lib/samagotchi/objectives_command.rb +4 -69
- data/lib/samagotchi/objectives_edit.rb +87 -0
- data/lib/samagotchi/output_formatter.rb +7 -1
- data/lib/samagotchi/owner_lock.rb +7 -1
- data/lib/samagotchi/parent_answers_command.rb +5 -4
- data/lib/samagotchi/participant_exposure.rb +42 -0
- data/lib/samagotchi/participant_mode.rb +1 -1
- data/lib/samagotchi/participant_name.rb +1 -1
- data/lib/samagotchi/participants.rb +17 -17
- data/lib/samagotchi/participants_watch.rb +1 -1
- data/lib/samagotchi/pending_input_queue.rb +2 -2
- data/lib/samagotchi/plugin/api.rb +3 -2
- data/lib/samagotchi/plugin/context.rb +21 -7
- data/lib/samagotchi/plugin/peer.rb +2 -1
- data/lib/samagotchi/plugin/sessions.rb +6 -4
- data/lib/samagotchi/plugin_tasks.rb +1 -2
- data/lib/samagotchi/private_files.rb +29 -0
- data/lib/samagotchi/project_env.rb +2 -2
- data/lib/samagotchi/question_desk.rb +8 -7
- data/lib/samagotchi/recap_command.rb +2 -1
- data/lib/samagotchi/recap_setup.rb +1 -1
- data/lib/samagotchi/recap_store.rb +1 -1
- data/lib/samagotchi/redact.rb +86 -0
- data/lib/samagotchi/reminder_queue.rb +2 -2
- data/lib/samagotchi/remote_attach_command.rb +1 -1
- data/lib/samagotchi/reply_wait/poll.rb +2 -2
- data/lib/samagotchi/review_start.rb +1 -1
- data/lib/samagotchi/run_options.rb +6 -6
- data/lib/samagotchi/self_report.rb +42 -39
- data/lib/samagotchi/send_command/busy.rb +1 -1
- data/lib/samagotchi/send_command.rb +4 -1
- data/lib/samagotchi/session.rb +11 -2
- data/lib/samagotchi/session_access/contract.rb +3 -3
- data/lib/samagotchi/session_access/local.rb +9 -9
- data/lib/samagotchi/session_access/remote.rb +17 -7
- data/lib/samagotchi/session_access.rb +4 -4
- data/lib/samagotchi/session_archive_command.rb +2 -2
- data/lib/samagotchi/session_chain.rb +8 -6
- data/lib/samagotchi/session_commands.rb +45 -48
- data/lib/samagotchi/session_continue.rb +1 -1
- data/lib/samagotchi/session_delete_command.rb +4 -4
- data/lib/samagotchi/session_manager.rb +59 -36
- data/lib/samagotchi/session_metrics.rb +2 -2
- data/lib/samagotchi/session_model_settings.rb +3 -2
- data/lib/samagotchi/session_participants.rb +1 -1
- data/lib/samagotchi/session_retention.rb +3 -3
- data/lib/samagotchi/sessions_command.rb +4 -4
- data/lib/samagotchi/share_command.rb +10 -10
- data/lib/samagotchi/steer.rb +1 -1
- data/lib/samagotchi/system_prompt.rb +102 -109
- data/lib/samagotchi/task_watch.rb +1 -1
- data/lib/samagotchi/terminal_ui/attach_launcher.rb +72 -10
- data/lib/samagotchi/terminal_ui/attached_loop/composer.rb +12 -9
- data/lib/samagotchi/terminal_ui/attached_loop/exit_commands.rb +16 -0
- data/lib/samagotchi/terminal_ui/attached_loop/questions.rb +2 -3
- data/lib/samagotchi/terminal_ui/attached_loop.rb +17 -8
- data/lib/samagotchi/terminal_ui/attached_view.rb +2 -3
- data/lib/samagotchi/terminal_ui/event_renderer.rb +3 -5
- data/lib/samagotchi/terminal_ui/formatting.rb +7 -7
- data/lib/samagotchi/terminal_ui/input_support.rb +1 -7
- data/lib/samagotchi/terminal_ui/line_reader.rb +2 -2
- data/lib/samagotchi/terminal_ui/live_region.rb +2 -2
- data/lib/samagotchi/terminal_ui/log_tail.rb +135 -0
- data/lib/samagotchi/terminal_ui/one_shot_sink.rb +2 -2
- data/lib/samagotchi/terminal_ui/plain_surface.rb +1 -1
- data/lib/samagotchi/terminal_ui/question_prompt.rb +4 -5
- data/lib/samagotchi/terminal_ui/reline_seam.rb +3 -3
- data/lib/samagotchi/terminal_ui/status_row.rb +7 -8
- data/lib/samagotchi/terminal_ui.rb +142 -1387
- data/lib/samagotchi/title_command.rb +2 -2
- data/lib/samagotchi/tool_runner.rb +14 -16
- data/lib/samagotchi/toolkit.rb +8 -5
- data/lib/samagotchi/toolkit_binding.rb +30 -5
- data/lib/samagotchi/toolkit_command.rb +2 -1
- data/lib/samagotchi/toolkit_report_command.rb +9 -5
- data/lib/samagotchi/toolkit_suggest.rb +12 -6
- data/lib/samagotchi/tools/builtin_calls.rb +14 -10
- data/lib/samagotchi/tools/deferred_tools.rb +2 -2
- data/lib/samagotchi/tools/delegate.rb +3 -1
- data/lib/samagotchi/tools/delegate_cursor.rb +3 -3
- data/lib/samagotchi/tools/delegate_wait.rb +1 -1
- data/lib/samagotchi/tools/objectives_tool.rb +2 -2
- data/lib/samagotchi/tools/registry.rb +44 -20
- data/lib/samagotchi/tools/send_note.rb +2 -1
- data/lib/samagotchi/tools/tool_index.rb +27 -21
- data/lib/samagotchi/turn_endings.rb +2 -2
- data/lib/samagotchi/turn_flow.rb +4 -5
- data/lib/samagotchi/update_hint.rb +2 -2
- data/lib/samagotchi/version.rb +1 -1
- data/lib/samagotchi/web/app.rb +39 -50
- data/lib/samagotchi/web/participant_access.rb +2 -2
- data/lib/samagotchi/web/participant_review.rb +5 -5
- data/lib/samagotchi/web/participant_stream_filter.rb +8 -8
- data/lib/samagotchi/web/participant_view.rb +2 -82
- data/lib/samagotchi/web/participants_admin.rb +1 -1
- data/lib/samagotchi/web/public/app.js +61 -357
- data/lib/samagotchi/web/public/block_host.js +35 -8
- data/lib/samagotchi/web/public/block_renderers.css +9 -5
- data/lib/samagotchi/web/public/chains.js +2 -2
- data/lib/samagotchi/web/public/claim_link.js +4 -4
- data/lib/samagotchi/web/public/composer_mode.js +110 -0
- data/lib/samagotchi/web/public/format.js +3 -3
- data/lib/samagotchi/web/public/owner_claim.js +81 -0
- data/lib/samagotchi/web/public/owner_verify.js +112 -0
- data/lib/samagotchi/web/public/session_fields.js +3 -3
- data/lib/samagotchi/web/public/strip_grip.js +3 -3
- data/lib/samagotchi/web/public/strip_hidden.js +65 -0
- data/lib/samagotchi/web/public/version_notices.js +132 -0
- data/lib/samagotchi/web/push/store.rb +1 -1
- data/lib/samagotchi/web/session_access_routes.rb +5 -4
- data/lib/samagotchi/web/session_control.rb +12 -8
- data/lib/samagotchi/web/session_create.rb +1 -1
- data/lib/samagotchi/web/session_hub.rb +2 -2
- data/lib/samagotchi/web/session_show.rb +2 -2
- data/lib/samagotchi/web/session_summary.rb +1 -1
- data/lib/samagotchi/worker.rb +106 -9
- data/lib/samagotchi/worker_link.rb +3 -3
- data/lib/samagotchi/working_set_command.rb +3 -2
- metadata +36 -6
- data/lib/samagotchi/terminal_ui/between_turns.rb +0 -138
- data/lib/samagotchi/terminal_ui/repl_input.rb +0 -152
- data/lib/samagotchi/web/grants.rb +0 -575
- data/lib/samagotchi/web/participant_exposure.rb +0 -44
- data/lib/samagotchi/web/private_files.rb +0 -31
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Samagotchi
|
|
4
|
+
class Engine
|
|
5
|
+
# Verify and Revise anchors at a turn's end: the opening's stamp, a Revise
|
|
6
|
+
# turn's draft checked, a Verify turn's quote checked against its source
|
|
7
|
+
# session and its verdict recorded. No ivars of its own: it reads the turn,
|
|
8
|
+
# and the sessions it loads through Engine methods.
|
|
9
|
+
module VerifyPart
|
|
10
|
+
# The turn's anchors, stamped on its opening message (the prompt, or a
|
|
11
|
+
# wake turn's note) in the messages it keeps: display metadata, never
|
|
12
|
+
# in the prompt (LLM::ChatLoop#plain keeps them, no wire sends them).
|
|
13
|
+
# A Verify turn's claim however it ended; a Revise turn's draft only
|
|
14
|
+
# once it completed with an answer (#revision_target). Returns the
|
|
15
|
+
# stamped ReviseAnchor (the end event's revises), or nil.
|
|
16
|
+
def stamp_opening(messages, turn, outcome)
|
|
17
|
+
return unless messages.is_a?(Array)
|
|
18
|
+
|
|
19
|
+
revises = revision_target(messages, turn, outcome)
|
|
20
|
+
fields = { verify: turn.verify&.to_h, revises: revises&.to_h }.compact
|
|
21
|
+
return if fields.empty?
|
|
22
|
+
|
|
23
|
+
opening = messages.reverse.find do |message|
|
|
24
|
+
Steer.turn_prompt?(message) && (message[:turn_id] || message["turn_id"]).to_s == turn.id
|
|
25
|
+
end
|
|
26
|
+
return unless opening
|
|
27
|
+
|
|
28
|
+
opening.merge!(fields)
|
|
29
|
+
revises
|
|
30
|
+
end
|
|
31
|
+
private :stamp_opening
|
|
32
|
+
|
|
33
|
+
# The turn a Revise turn revised (D6: "this turn revised that one"):
|
|
34
|
+
# only a completed turn with an answer (AnswerTail) has revised
|
|
35
|
+
# anything. A draft no prompt in the messages carries is no target (a
|
|
36
|
+
# stale page, a rolled-back turn); one a stamped turn already revised
|
|
37
|
+
# is re-targeted to its stack's top, the newest version, which the
|
|
38
|
+
# person meant ("this draft").
|
|
39
|
+
def revision_target(messages, turn, outcome)
|
|
40
|
+
return unless turn.revises && outcome == "completed"
|
|
41
|
+
|
|
42
|
+
slice = AnswerTail.turn_slice(messages, turn.id)
|
|
43
|
+
return unless slice&.any? { |message| AnswerTail.answer?(message) }
|
|
44
|
+
|
|
45
|
+
target = turn.revises.turn_id
|
|
46
|
+
seen = [turn.id]
|
|
47
|
+
until seen.include?(target)
|
|
48
|
+
return reject_revise_anchor(turn.revises, :turn_missing) unless AnswerTail.turn_slice(messages, target)
|
|
49
|
+
|
|
50
|
+
seen << target
|
|
51
|
+
newer = messages.reverse.find do |message|
|
|
52
|
+
Steer.turn_prompt?(message) && ReviseAnchor.from(message[:revises] || message["revises"])&.turn_id == target
|
|
53
|
+
end
|
|
54
|
+
return ReviseAnchor.new(turn_id: target) unless newer
|
|
55
|
+
|
|
56
|
+
target = (newer[:turn_id] || newer["turn_id"]).to_s
|
|
57
|
+
end
|
|
58
|
+
reject_revise_anchor(turn.revises, :cycle)
|
|
59
|
+
end
|
|
60
|
+
private :revision_target
|
|
61
|
+
|
|
62
|
+
def reject_revise_anchor(anchor, reason)
|
|
63
|
+
Log.warn(:turn, "revise_anchor_rejected", turn_id: anchor.turn_id, reason:)
|
|
64
|
+
nil
|
|
65
|
+
end
|
|
66
|
+
private :reject_revise_anchor
|
|
67
|
+
|
|
68
|
+
def verified_anchor(session, anchor)
|
|
69
|
+
return unless anchor
|
|
70
|
+
|
|
71
|
+
source = verify_anchor_source_session(session, anchor)
|
|
72
|
+
return unless source
|
|
73
|
+
|
|
74
|
+
turn = AnswerTail.turn_slice(Array(source.messages), anchor.turn_id)
|
|
75
|
+
return reject_verify_anchor(anchor, :turn_missing) unless turn
|
|
76
|
+
|
|
77
|
+
reply = turn.reverse.find { |message| AnswerTail.answer?(message) }
|
|
78
|
+
return reject_verify_anchor(anchor, :reply_missing) unless reply
|
|
79
|
+
|
|
80
|
+
quote_text = verify_comparison_text(anchor.quote)
|
|
81
|
+
quoted = !quote_text.empty? && verify_quote_in?(quote_text, (reply[:content] || reply["content"]).to_s, source)
|
|
82
|
+
return reject_verify_anchor(anchor, :quote_missing) unless quoted
|
|
83
|
+
|
|
84
|
+
anchor
|
|
85
|
+
end
|
|
86
|
+
private :verified_anchor
|
|
87
|
+
|
|
88
|
+
# Whether +quote_text+ is in +answer+ as the model wrote it, or as the
|
|
89
|
+
# pages show it: a page quotes its own text, which reads the session's
|
|
90
|
+
# folder relative, the home folder as ~ and a secret shape as
|
|
91
|
+
# [redacted] (a participant's page gets it so, Redact;
|
|
92
|
+
# the owner's page rewrites its quote the same way, claim_link.js
|
|
93
|
+
# normalizeClaim, so claim links match both pages). +source+ is the
|
|
94
|
+
# session whose folder that is.
|
|
95
|
+
def verify_quote_in?(quote_text, answer, source)
|
|
96
|
+
return true if verify_comparison_text(answer).include?(quote_text)
|
|
97
|
+
|
|
98
|
+
viewer = Redact::Viewer.new(cwd: source.working_directory)
|
|
99
|
+
verify_comparison_text(Redact.text(answer, viewer)).include?(quote_text)
|
|
100
|
+
end
|
|
101
|
+
private :verify_quote_in?
|
|
102
|
+
|
|
103
|
+
def verify_anchor_source_session(session, anchor)
|
|
104
|
+
return session unless session.verify_fresh
|
|
105
|
+
|
|
106
|
+
fresh = session.verify_fresh
|
|
107
|
+
return reject_verify_anchor(anchor, :fresh_anchor_mismatch) unless fresh.anchor == anchor
|
|
108
|
+
return reject_verify_anchor(anchor, :fresh_parent_missing) unless session.parent_id
|
|
109
|
+
|
|
110
|
+
Session.load(session.parent_id, state_dir: session_state_dir)
|
|
111
|
+
rescue ArgumentError, SystemCallError, IOError => e
|
|
112
|
+
Log.warn(:turn, "verify_anchor_rejected", turn_id: anchor.turn_id, reason: :source_session_unavailable,
|
|
113
|
+
error: e.class.name)
|
|
114
|
+
nil
|
|
115
|
+
end
|
|
116
|
+
private :verify_anchor_source_session
|
|
117
|
+
|
|
118
|
+
def verify_comparison_text(text)
|
|
119
|
+
OutputFormatter.strip_markup(text)
|
|
120
|
+
.gsub(/!\[([^\]]*)\]\([^)]+\)/, '\1')
|
|
121
|
+
.gsub(/\[([^\]]+)\]\([^)]+\)/, '\1')
|
|
122
|
+
.gsub(/^[ \t]*(?:\#{1,6}[ \t]+|>[ \t]?|[-+*][ \t]+|\d+[.)][ \t]+)/, "")
|
|
123
|
+
.gsub(/(\*\*|__|~~|`+)(.+?)\1/m, '\2')
|
|
124
|
+
.gsub(/(?<!\w)\*(\S(?:.*?\S)?)\*(?!\w)/m, '\1')
|
|
125
|
+
.gsub(/(?<!\w)_(\S(?:.*?\S)?)_(?!\w)/m, '\1')
|
|
126
|
+
.tr("|", " ") # a table row's cells; the page copies them without the pipes
|
|
127
|
+
.gsub(/\s+/, " ")
|
|
128
|
+
.strip
|
|
129
|
+
end
|
|
130
|
+
private :verify_comparison_text
|
|
131
|
+
|
|
132
|
+
def reject_verify_anchor(anchor, reason)
|
|
133
|
+
Log.warn(:turn, "verify_anchor_rejected", turn_id: anchor.turn_id, reason:)
|
|
134
|
+
nil
|
|
135
|
+
end
|
|
136
|
+
private :reject_verify_anchor
|
|
137
|
+
|
|
138
|
+
def record_verdict(turn, outcome)
|
|
139
|
+
return unless outcome == "completed" && turn.verify
|
|
140
|
+
|
|
141
|
+
answer = AnswerTail.find(turn.session.messages, turn_id: turn.id)
|
|
142
|
+
parsed = Verdict.parse(answer && (answer[:content] || answer["content"]))
|
|
143
|
+
return unless parsed
|
|
144
|
+
|
|
145
|
+
record = { anchor: turn.verify.to_h, verdict: parsed.verdict, reason: parsed.reason,
|
|
146
|
+
by: turn.origin.author, check_turn_id: turn.id, at: Time.now.iso8601(3) }
|
|
147
|
+
turn.session.verdicts = turn.session.verdicts + [record]
|
|
148
|
+
record
|
|
149
|
+
end
|
|
150
|
+
private :record_verdict
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
end
|