anima-core 1.0.1 → 1.0.2
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/.reek.yml +14 -0
- data/CHANGELOG.md +1 -0
- data/README.md +159 -107
- data/app/channels/session_channel.rb +15 -0
- data/app/decorators/agent_message_decorator.rb +6 -0
- data/app/decorators/event_decorator.rb +41 -7
- data/app/decorators/tool_call_decorator.rb +59 -2
- data/app/decorators/tool_response_decorator.rb +24 -2
- data/app/decorators/user_message_decorator.rb +6 -0
- data/app/jobs/agent_request_job.rb +8 -0
- data/db/migrate/20260316094817_add_interrupt_requested_to_sessions.rb +5 -0
- data/lib/agent_loop.rb +8 -2
- data/lib/analytical_brain/runner.rb +1 -19
- data/lib/anima/cli.rb +32 -0
- data/lib/anima/config_migrator.rb +205 -0
- data/lib/anima/installer.rb +2 -118
- data/lib/anima/settings.rb +1 -1
- data/lib/anima/version.rb +1 -1
- data/lib/llm/client.rb +83 -6
- data/lib/tools/think.rb +57 -0
- data/lib/tui/app.rb +8 -2
- data/lib/tui/cable_client.rb +8 -0
- data/lib/tui/screens/chat.rb +40 -0
- data/templates/config.toml +116 -0
- metadata +5 -1
data/lib/llm/client.rb
CHANGED
|
@@ -15,6 +15,9 @@ module LLM
|
|
|
15
15
|
# registry.register(Tools::WebGet)
|
|
16
16
|
# client.chat_with_tools(messages, registry: registry, session_id: session.id)
|
|
17
17
|
class Client
|
|
18
|
+
# Synthetic tool_result message when a tool is skipped due to user interrupt.
|
|
19
|
+
INTERRUPT_MESSAGE = "Stopped by user"
|
|
20
|
+
|
|
18
21
|
# @return [Providers::Anthropic] the underlying API provider
|
|
19
22
|
attr_reader :provider
|
|
20
23
|
|
|
@@ -61,11 +64,14 @@ module LLM
|
|
|
61
64
|
# Emits {Events::ToolCall} and {Events::ToolResponse} events for each
|
|
62
65
|
# tool interaction so they're persisted and visible in the event stream.
|
|
63
66
|
#
|
|
67
|
+
# When the user interrupts via Escape, remaining tools receive synthetic
|
|
68
|
+
# "Stopped by user" results and the loop exits without another LLM call.
|
|
69
|
+
#
|
|
64
70
|
# @param messages [Array<Hash>] conversation messages in Anthropic format
|
|
65
71
|
# @param registry [Tools::Registry] registered tools to make available
|
|
66
72
|
# @param session_id [Integer, String] session ID for emitted events
|
|
67
73
|
# @param options [Hash] additional API parameters (e.g. +system:+)
|
|
68
|
-
# @return [String] the assistant's final text response
|
|
74
|
+
# @return [String, nil] the assistant's final text response, or nil when interrupted
|
|
69
75
|
# @raise [Providers::Anthropic::Error] on API errors
|
|
70
76
|
def chat_with_tools(messages, registry:, session_id:, **options)
|
|
71
77
|
messages = messages.dup
|
|
@@ -95,6 +101,11 @@ module LLM
|
|
|
95
101
|
{role: "assistant", content: response["content"]},
|
|
96
102
|
{role: "user", content: tool_results}
|
|
97
103
|
]
|
|
104
|
+
|
|
105
|
+
if interrupted?(session_id)
|
|
106
|
+
clear_interrupt!(session_id)
|
|
107
|
+
return nil
|
|
108
|
+
end
|
|
98
109
|
else
|
|
99
110
|
return extract_text(response)
|
|
100
111
|
end
|
|
@@ -122,20 +133,43 @@ module LLM
|
|
|
122
133
|
end
|
|
123
134
|
|
|
124
135
|
# Executes all tool_use blocks from a response, emitting events for each.
|
|
136
|
+
# Checks for user interrupt between tools — remaining tools receive
|
|
137
|
+
# synthetic results to satisfy the Anthropic API's tool_use/tool_result
|
|
138
|
+
# pairing requirement (a missing result permanently breaks the conversation).
|
|
125
139
|
#
|
|
126
140
|
# @param response [Hash] Anthropic API response with tool_use content blocks
|
|
127
141
|
# @param registry [Tools::Registry] tool registry for dispatch
|
|
128
142
|
# @param session_id [Integer, String] session ID for events
|
|
129
143
|
# @return [Array<Hash>] tool_result content blocks for the next API call
|
|
130
144
|
def execute_tools(response, registry, session_id)
|
|
131
|
-
extract_tool_uses(response)
|
|
132
|
-
|
|
145
|
+
tool_uses = extract_tool_uses(response)
|
|
146
|
+
results = []
|
|
147
|
+
|
|
148
|
+
tool_uses.each_with_index do |tool_use, index|
|
|
149
|
+
if interrupted?(session_id)
|
|
150
|
+
remaining = tool_uses[index..]
|
|
151
|
+
results.concat(interrupt_remaining_tools(remaining, session_id)) if remaining&.any?
|
|
152
|
+
break
|
|
153
|
+
end
|
|
154
|
+
results << execute_single_tool(tool_use, registry, session_id)
|
|
133
155
|
end
|
|
156
|
+
|
|
157
|
+
results
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
# Creates synthetic "Stopped by user" results for all tools in the list.
|
|
161
|
+
#
|
|
162
|
+
# @param tool_uses [Array<Hash>] remaining tool_use content blocks
|
|
163
|
+
# @param session_id [Integer, String] session ID for events
|
|
164
|
+
# @return [Array<Hash>] tool_result content blocks
|
|
165
|
+
def interrupt_remaining_tools(tool_uses, session_id)
|
|
166
|
+
tool_uses.map { |tool_use| interrupt_tool(tool_use, session_id) }
|
|
134
167
|
end
|
|
135
168
|
|
|
136
|
-
# Executes a single tool and always returns a tool_result — even if
|
|
137
|
-
#
|
|
138
|
-
# tool_result; a missing result
|
|
169
|
+
# Executes a single tool and always returns a tool_result — even if the
|
|
170
|
+
# tool raises. Per the Anthropic tool-use protocol, every tool_use must
|
|
171
|
+
# have a matching tool_result; a missing result permanently corrupts the
|
|
172
|
+
# conversation history and breaks the session.
|
|
139
173
|
def execute_single_tool(tool_use, registry, session_id)
|
|
140
174
|
name = tool_use["name"]
|
|
141
175
|
id = tool_use["id"]
|
|
@@ -167,6 +201,49 @@ module LLM
|
|
|
167
201
|
{type: "tool_result", tool_use_id: id, content: result_content}
|
|
168
202
|
end
|
|
169
203
|
|
|
204
|
+
# Creates a synthetic "Stopped by user" result for a tool that was not
|
|
205
|
+
# executed due to user interrupt. Emits both ToolCall and ToolResponse
|
|
206
|
+
# events so the TUI shows the interrupted tool in the event stream.
|
|
207
|
+
#
|
|
208
|
+
# @param tool_use [Hash] Anthropic tool_use content block
|
|
209
|
+
# @param session_id [Integer, String] session ID for events
|
|
210
|
+
# @return [Hash] tool_result content block
|
|
211
|
+
def interrupt_tool(tool_use, session_id)
|
|
212
|
+
name = tool_use["name"]
|
|
213
|
+
id = tool_use["id"]
|
|
214
|
+
input = tool_use["input"] || {}
|
|
215
|
+
|
|
216
|
+
Events::Bus.emit(Events::ToolCall.new(
|
|
217
|
+
content: "Skipped #{name} (interrupted)", tool_name: name,
|
|
218
|
+
tool_input: input, tool_use_id: id, session_id: session_id
|
|
219
|
+
))
|
|
220
|
+
|
|
221
|
+
Events::Bus.emit(Events::ToolResponse.new(
|
|
222
|
+
content: INTERRUPT_MESSAGE, tool_name: name, tool_use_id: id,
|
|
223
|
+
success: false, session_id: session_id
|
|
224
|
+
))
|
|
225
|
+
|
|
226
|
+
{type: "tool_result", tool_use_id: id, content: INTERRUPT_MESSAGE}
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
# Checks the database for a pending interrupt flag on the session.
|
|
230
|
+
#
|
|
231
|
+
# @param session_id [Integer, String] session to check
|
|
232
|
+
# @return [Boolean] whether the session has a pending interrupt request
|
|
233
|
+
def interrupted?(session_id)
|
|
234
|
+
Session.where(id: session_id, interrupt_requested: true).exists?
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
# Clears the interrupt flag so the agent loop can continue with pending
|
|
238
|
+
# messages. Also cleared by {AgentRequestJob#clear_interrupt} as a safety
|
|
239
|
+
# net for unexpected exits.
|
|
240
|
+
#
|
|
241
|
+
# @param session_id [Integer, String] session to clear
|
|
242
|
+
# @return [void]
|
|
243
|
+
def clear_interrupt!(session_id)
|
|
244
|
+
Session.where(id: session_id).update_all(interrupt_requested: false)
|
|
245
|
+
end
|
|
246
|
+
|
|
170
247
|
def log(level, message)
|
|
171
248
|
return unless @logger
|
|
172
249
|
|
data/lib/tools/think.rb
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Tools
|
|
4
|
+
# A deliberate reasoning space for the agent's inner voice. Creates a
|
|
5
|
+
# pause between tool calls where the agent can organize thoughts, plan
|
|
6
|
+
# next steps, or make decisions without interrupting the user.
|
|
7
|
+
#
|
|
8
|
+
# Think events bridge the gap between the analytical brain (subconscious
|
|
9
|
+
# background processing) and speech (user-facing messages). Without this
|
|
10
|
+
# tool, reasoning leaks into tool arguments as comments.
|
|
11
|
+
#
|
|
12
|
+
# Two visibility modes control how thoughts appear in the TUI:
|
|
13
|
+
# - **inner** (default) — silent reasoning, visible only in verbose/debug
|
|
14
|
+
# - **aloud** — narration shown in all view modes with a thought bubble
|
|
15
|
+
#
|
|
16
|
+
# @example Silent planning between tool calls
|
|
17
|
+
# think(thoughts: "Three auth failures — likely a config issue, not individual tests.")
|
|
18
|
+
#
|
|
19
|
+
# @example Narrating approach for the user
|
|
20
|
+
# think(thoughts: "Checking the OAuth config first.", visibility: "aloud")
|
|
21
|
+
class Think < Base
|
|
22
|
+
def self.tool_name = "think"
|
|
23
|
+
|
|
24
|
+
def self.description
|
|
25
|
+
"Express your internal reasoning between tool calls. " \
|
|
26
|
+
"Use this to analyze intermediate results, plan next steps, or make decisions before continuing. " \
|
|
27
|
+
"Set visibility to \"aloud\" when you want the user to see your thought process."
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def self.input_schema
|
|
31
|
+
{
|
|
32
|
+
type: "object",
|
|
33
|
+
properties: {
|
|
34
|
+
thoughts: {
|
|
35
|
+
type: "string",
|
|
36
|
+
description: "Your reasoning, analysis, or internal monologue"
|
|
37
|
+
},
|
|
38
|
+
visibility: {
|
|
39
|
+
type: "string",
|
|
40
|
+
enum: ["inner", "aloud"],
|
|
41
|
+
description: "\"inner\" (default) for silent reasoning; \"aloud\" to narrate for the user"
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
required: ["thoughts"]
|
|
45
|
+
}
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# @param input [Hash] with "thoughts" and optional "visibility"
|
|
49
|
+
# @return [String] acknowledgement — the value is in the call, not the result
|
|
50
|
+
def execute(input)
|
|
51
|
+
thoughts = input["thoughts"].to_s
|
|
52
|
+
return {error: "Thoughts cannot be blank"} if thoughts.strip.empty?
|
|
53
|
+
|
|
54
|
+
"OK"
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
data/lib/tui/app.rb
CHANGED
|
@@ -391,9 +391,15 @@ module TUI
|
|
|
391
391
|
return nil
|
|
392
392
|
end
|
|
393
393
|
|
|
394
|
+
# Escape key priority: unfocus chat > interrupt tools > clear input > parent session
|
|
394
395
|
if event.esc?
|
|
395
|
-
|
|
396
|
-
|
|
396
|
+
chat = @screens[:chat]
|
|
397
|
+
if chat.chat_focused
|
|
398
|
+
chat.unfocus_chat
|
|
399
|
+
elsif chat.loading? && chat.input.empty?
|
|
400
|
+
chat.interrupt_execution
|
|
401
|
+
elsif !chat.input.empty?
|
|
402
|
+
chat.clear_input
|
|
397
403
|
else
|
|
398
404
|
return_to_parent_session
|
|
399
405
|
end
|
data/lib/tui/cable_client.rb
CHANGED
|
@@ -134,6 +134,14 @@ module TUI
|
|
|
134
134
|
send_action("recall_pending", {"event_id" => event_id})
|
|
135
135
|
end
|
|
136
136
|
|
|
137
|
+
# Requests interruption of the current tool execution. The server sets
|
|
138
|
+
# an interrupt flag that the LLM client checks between tool calls.
|
|
139
|
+
#
|
|
140
|
+
# @return [void]
|
|
141
|
+
def interrupt
|
|
142
|
+
send_action("interrupt_execution", {})
|
|
143
|
+
end
|
|
144
|
+
|
|
137
145
|
# Sends an Anthropic subscription token to the brain for validation and storage.
|
|
138
146
|
# The token flows directly from TUI input to encrypted credentials — never
|
|
139
147
|
# enters the LLM context window.
|
data/lib/tui/screens/chat.rb
CHANGED
|
@@ -21,6 +21,8 @@ module TUI
|
|
|
21
21
|
RETURN_ARROW = "\u21A9"
|
|
22
22
|
ERROR_ICON = "\u274C"
|
|
23
23
|
|
|
24
|
+
THOUGHT_BUBBLE = "\u{1F4AD}"
|
|
25
|
+
|
|
24
26
|
ROLE_COLORS = {"user" => "green", "assistant" => "cyan"}.freeze
|
|
25
27
|
|
|
26
28
|
# Intentionally duplicated from Session::VIEW_MODES to keep the TUI
|
|
@@ -165,6 +167,21 @@ module TUI
|
|
|
165
167
|
@cable_client.change_view_mode(mode)
|
|
166
168
|
end
|
|
167
169
|
|
|
170
|
+
# Sends an interrupt request to the server to stop the current tool chain.
|
|
171
|
+
# Called when Escape is pressed with empty input during active processing.
|
|
172
|
+
#
|
|
173
|
+
# @return [void]
|
|
174
|
+
def interrupt_execution
|
|
175
|
+
@cable_client.interrupt
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
# Clears the input buffer. Used when Escape is pressed with non-empty input.
|
|
179
|
+
#
|
|
180
|
+
# @return [void]
|
|
181
|
+
def clear_input
|
|
182
|
+
@input_buffer.clear
|
|
183
|
+
end
|
|
184
|
+
|
|
168
185
|
# Clears the authentication_required flag after the App has consumed it.
|
|
169
186
|
# @return [void]
|
|
170
187
|
def clear_authentication_required
|
|
@@ -449,6 +466,8 @@ module TUI
|
|
|
449
466
|
render_tool_call_entry(tui, data)
|
|
450
467
|
when "tool_response"
|
|
451
468
|
render_tool_response_entry(tui, data)
|
|
469
|
+
when "think"
|
|
470
|
+
render_think_entry(tui, data)
|
|
452
471
|
when "system"
|
|
453
472
|
render_system_entry(tui, data)
|
|
454
473
|
when "system_prompt"
|
|
@@ -557,6 +576,27 @@ module TUI
|
|
|
557
576
|
lines
|
|
558
577
|
end
|
|
559
578
|
|
|
579
|
+
# Renders a think event — the agent's inner reasoning between tool calls.
|
|
580
|
+
# "aloud" thoughts use yellow (narration for the user), "inner" thoughts
|
|
581
|
+
# use dark_gray (visible only in verbose/debug, dimmed to signal internality).
|
|
582
|
+
# @param tui [RatatuiRuby] TUI rendering API
|
|
583
|
+
# @param data [Hash] structured data with "content", "visibility", optional "timestamp", "tool_use_id"
|
|
584
|
+
# @return [Array<RatatuiRuby::Widgets::Line>]
|
|
585
|
+
def render_think_entry(tui, data)
|
|
586
|
+
aloud = data["visibility"] == "aloud"
|
|
587
|
+
color = aloud ? "yellow" : "dark_gray"
|
|
588
|
+
style = tui.style(fg: color)
|
|
589
|
+
|
|
590
|
+
meta = []
|
|
591
|
+
meta << "[#{format_ns_timestamp(data["timestamp"])}]" if data["timestamp"]
|
|
592
|
+
header = meta.empty? ? THOUGHT_BUBBLE : "#{meta.join(" ")} #{THOUGHT_BUBBLE}"
|
|
593
|
+
|
|
594
|
+
content_lines = data["content"].to_s.split("\n", -1)
|
|
595
|
+
lines = [tui.line(spans: [tui.span(content: "#{header} #{content_lines.first}", style: style)])]
|
|
596
|
+
content_lines.drop(1).each { |line| lines << tui.line(spans: [tui.span(content: " #{line}", style: style)]) }
|
|
597
|
+
lines
|
|
598
|
+
end
|
|
599
|
+
|
|
560
600
|
# Formats a token count for display, with tilde prefix for estimates.
|
|
561
601
|
# @param tokens [Integer, nil] token count
|
|
562
602
|
# @param estimated [Boolean] whether the count is an estimate
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# Anima Configuration
|
|
2
|
+
#
|
|
3
|
+
# Edit settings below to customize Anima's behavior.
|
|
4
|
+
# Changes take effect immediately — no restart needed.
|
|
5
|
+
|
|
6
|
+
# ─── LLM ───────────────────────────────────────────────────────
|
|
7
|
+
|
|
8
|
+
[llm]
|
|
9
|
+
|
|
10
|
+
# Primary model for conversations.
|
|
11
|
+
model = "claude-opus-4-6"
|
|
12
|
+
|
|
13
|
+
# Lightweight model for fast tasks (e.g. session naming).
|
|
14
|
+
fast_model = "claude-haiku-4-5"
|
|
15
|
+
|
|
16
|
+
# Maximum tokens per LLM response.
|
|
17
|
+
max_tokens = 8192
|
|
18
|
+
|
|
19
|
+
# Maximum consecutive tool execution rounds per request.
|
|
20
|
+
max_tool_rounds = 500
|
|
21
|
+
|
|
22
|
+
# Context window budget — tokens reserved for conversation history.
|
|
23
|
+
# Set this based on your model's context window minus system prompt.
|
|
24
|
+
token_budget = 190_000
|
|
25
|
+
|
|
26
|
+
# ─── Timeouts (seconds) ─────────────────────────────────────────
|
|
27
|
+
|
|
28
|
+
[timeouts]
|
|
29
|
+
|
|
30
|
+
# LLM API request timeout.
|
|
31
|
+
api = 300
|
|
32
|
+
|
|
33
|
+
# Shell command execution timeout.
|
|
34
|
+
command = 30
|
|
35
|
+
|
|
36
|
+
# MCP server response timeout.
|
|
37
|
+
mcp_response = 60
|
|
38
|
+
|
|
39
|
+
# Web fetch request timeout.
|
|
40
|
+
web_request = 10
|
|
41
|
+
|
|
42
|
+
# ─── Shell ──────────────────────────────────────────────────────
|
|
43
|
+
|
|
44
|
+
[shell]
|
|
45
|
+
|
|
46
|
+
# Maximum bytes of command output before truncation.
|
|
47
|
+
max_output_bytes = 100_000
|
|
48
|
+
|
|
49
|
+
# ─── Tools ──────────────────────────────────────────────────────
|
|
50
|
+
|
|
51
|
+
[tools]
|
|
52
|
+
|
|
53
|
+
# Maximum file size for read/edit operations (bytes).
|
|
54
|
+
max_file_size = 10_485_760
|
|
55
|
+
|
|
56
|
+
# Maximum lines returned by the read tool.
|
|
57
|
+
max_read_lines = 2_000
|
|
58
|
+
|
|
59
|
+
# Maximum bytes returned by the read tool.
|
|
60
|
+
max_read_bytes = 50_000
|
|
61
|
+
|
|
62
|
+
# Maximum bytes from web GET responses.
|
|
63
|
+
max_web_response_bytes = 100_000
|
|
64
|
+
|
|
65
|
+
# ─── Environment ──────────────────────────────────────────────
|
|
66
|
+
|
|
67
|
+
[environment]
|
|
68
|
+
|
|
69
|
+
# Files to scan for in the working directory (at root and up to project_files_max_depth subdirectories deep).
|
|
70
|
+
project_files = ["CLAUDE.md", "AGENTS.md", "README.md", "CONTRIBUTING.md"]
|
|
71
|
+
|
|
72
|
+
# Maximum directory depth for project file scanning.
|
|
73
|
+
project_files_max_depth = 3
|
|
74
|
+
|
|
75
|
+
# ─── GitHub ─────────────────────────────────────────────────────
|
|
76
|
+
|
|
77
|
+
[github]
|
|
78
|
+
|
|
79
|
+
# Repository for agent feature requests (owner/repo format).
|
|
80
|
+
# Falls back to parsing git remote origin when unset.
|
|
81
|
+
repo = "hoblin/anima"
|
|
82
|
+
|
|
83
|
+
# Label applied to agent-created feature request issues.
|
|
84
|
+
label = "anima-wants"
|
|
85
|
+
|
|
86
|
+
# ─── Paths ─────────────────────────────────────────────────────
|
|
87
|
+
|
|
88
|
+
[paths]
|
|
89
|
+
|
|
90
|
+
# The agent's self-authored identity file.
|
|
91
|
+
soul = "{{ANIMA_HOME}}/soul.md"
|
|
92
|
+
|
|
93
|
+
# ─── Session ────────────────────────────────────────────────────
|
|
94
|
+
|
|
95
|
+
[session]
|
|
96
|
+
|
|
97
|
+
# Regenerate session name every N messages.
|
|
98
|
+
name_generation_interval = 30
|
|
99
|
+
|
|
100
|
+
# ─── Analytical Brain ─────────────────────────────────────────
|
|
101
|
+
|
|
102
|
+
[analytical_brain]
|
|
103
|
+
|
|
104
|
+
# Maximum tokens per analytical brain response.
|
|
105
|
+
# Must accommodate multiple tool calls (rename + goals + skills + ready).
|
|
106
|
+
max_tokens = 4096
|
|
107
|
+
|
|
108
|
+
# Run the analytical brain synchronously before the main agent on user messages.
|
|
109
|
+
# Ensures activated skills are available for the current response.
|
|
110
|
+
blocking_on_user_message = true
|
|
111
|
+
|
|
112
|
+
# Run the analytical brain asynchronously after the main agent completes.
|
|
113
|
+
blocking_on_agent_message = false
|
|
114
|
+
|
|
115
|
+
# Number of recent events to include in the analytical brain's context window.
|
|
116
|
+
event_window = 20
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: anima-core
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.0.
|
|
4
|
+
version: 1.0.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Yevhenii Hurin
|
|
@@ -269,6 +269,7 @@ files:
|
|
|
269
269
|
- db/migrate/20260315140843_create_goals.rb
|
|
270
270
|
- db/migrate/20260315144837_add_completed_at_to_goals.rb
|
|
271
271
|
- db/migrate/20260315191105_add_active_workflow_to_sessions.rb
|
|
272
|
+
- db/migrate/20260316094817_add_interrupt_requested_to_sessions.rb
|
|
272
273
|
- db/queue_schema.rb
|
|
273
274
|
- db/seeds.rb
|
|
274
275
|
- exe/anima
|
|
@@ -290,6 +291,7 @@ files:
|
|
|
290
291
|
- lib/anima/cli.rb
|
|
291
292
|
- lib/anima/cli/mcp.rb
|
|
292
293
|
- lib/anima/cli/mcp/secrets.rb
|
|
294
|
+
- lib/anima/config_migrator.rb
|
|
293
295
|
- lib/anima/installer.rb
|
|
294
296
|
- lib/anima/settings.rb
|
|
295
297
|
- lib/anima/version.rb
|
|
@@ -326,6 +328,7 @@ files:
|
|
|
326
328
|
- lib/tools/spawn_specialist.rb
|
|
327
329
|
- lib/tools/spawn_subagent.rb
|
|
328
330
|
- lib/tools/subagent_prompts.rb
|
|
331
|
+
- lib/tools/think.rb
|
|
329
332
|
- lib/tools/web_get.rb
|
|
330
333
|
- lib/tools/write.rb
|
|
331
334
|
- lib/tui/app.rb
|
|
@@ -514,6 +517,7 @@ files:
|
|
|
514
517
|
- skills/rspec/references/matchers.md
|
|
515
518
|
- skills/rspec/references/mocks.md
|
|
516
519
|
- skills/rspec/references/rails.md
|
|
520
|
+
- templates/config.toml
|
|
517
521
|
- templates/soul.md
|
|
518
522
|
- workflows/commit.md
|
|
519
523
|
- workflows/create_handoff.md
|