anima-core 1.0.2 → 1.1.1
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/.gitattributes +1 -0
- data/.reek.yml +51 -0
- data/README.md +63 -29
- data/anima-core.gemspec +4 -1
- data/app/channels/session_channel.rb +30 -11
- data/app/decorators/tool_call_decorator.rb +32 -3
- data/app/decorators/tool_decorator.rb +57 -0
- data/app/decorators/tool_response_decorator.rb +12 -4
- data/app/decorators/web_get_tool_decorator.rb +102 -0
- data/app/jobs/agent_request_job.rb +93 -23
- data/app/jobs/mneme_job.rb +51 -0
- data/app/jobs/passive_recall_job.rb +29 -0
- data/app/models/concerns/event/broadcasting.rb +4 -0
- data/app/models/event.rb +10 -0
- data/app/models/goal.rb +27 -0
- data/app/models/goal_pinned_event.rb +11 -0
- data/app/models/pinned_event.rb +41 -0
- data/app/models/session.rb +402 -6
- data/app/models/snapshot.rb +76 -0
- data/bin/jobs +5 -0
- data/config/initializers/event_subscribers.rb +12 -3
- data/config/initializers/fts5_schema_dump.rb +21 -0
- data/config/queue.yml +0 -1
- data/db/migrate/20260321080000_create_mneme_schema.rb +32 -0
- data/db/migrate/20260321120000_create_pinned_events.rb +27 -0
- data/db/migrate/20260321140000_create_events_fts_index.rb +77 -0
- data/db/migrate/20260321140100_add_recalled_event_ids_to_sessions.rb +10 -0
- data/lib/agent_loop.rb +63 -20
- data/lib/analytical_brain/runner.rb +158 -65
- data/lib/analytical_brain/tools/assign_nickname.rb +76 -0
- data/lib/analytical_brain/tools/finish_goal.rb +6 -1
- data/lib/anima/cli.rb +32 -9
- data/lib/anima/installer.rb +11 -24
- data/lib/anima/settings.rb +59 -0
- data/lib/anima/spinner.rb +75 -0
- data/lib/anima/version.rb +1 -1
- data/lib/environment_probe.rb +4 -4
- data/lib/events/bounce_back.rb +37 -0
- data/lib/events/subscribers/persister.rb +19 -0
- data/lib/events/subscribers/subagent_message_router.rb +102 -0
- data/lib/events/subscribers/transient_broadcaster.rb +36 -0
- data/lib/events/tool_call.rb +5 -3
- data/lib/llm/client.rb +19 -9
- data/lib/mneme/compressed_viewport.rb +200 -0
- data/lib/mneme/l2_runner.rb +138 -0
- data/lib/mneme/passive_recall.rb +69 -0
- data/lib/mneme/runner.rb +254 -0
- data/lib/mneme/search.rb +150 -0
- data/lib/mneme/tools/attach_events_to_goals.rb +107 -0
- data/lib/mneme/tools/everything_ok.rb +24 -0
- data/lib/mneme/tools/save_snapshot.rb +68 -0
- data/lib/mneme.rb +29 -0
- data/lib/providers/anthropic.rb +57 -13
- data/lib/shell_session.rb +194 -63
- data/lib/tasks/fts5.rake +6 -0
- data/lib/tools/base.rb +2 -1
- data/lib/tools/bash.rb +4 -2
- data/lib/tools/registry.rb +22 -3
- data/lib/tools/remember.rb +179 -0
- data/lib/tools/request_feature.rb +3 -1
- data/lib/tools/spawn_specialist.rb +21 -9
- data/lib/tools/spawn_subagent.rb +22 -11
- data/lib/tools/subagent_prompts.rb +20 -3
- data/lib/tools/web_get.rb +21 -10
- data/lib/tui/app.rb +222 -125
- data/lib/tui/decorators/base_decorator.rb +165 -0
- data/lib/tui/decorators/bash_decorator.rb +20 -0
- data/lib/tui/decorators/edit_decorator.rb +19 -0
- data/lib/tui/decorators/read_decorator.rb +24 -0
- data/lib/tui/decorators/think_decorator.rb +36 -0
- data/lib/tui/decorators/web_get_decorator.rb +19 -0
- data/lib/tui/decorators/write_decorator.rb +19 -0
- data/lib/tui/flash.rb +139 -0
- data/lib/tui/formatting.rb +28 -0
- data/lib/tui/height_map.rb +93 -0
- data/lib/tui/message_store.rb +97 -8
- data/lib/tui/performance_logger.rb +90 -0
- data/lib/tui/screens/chat.rb +358 -133
- data/templates/config.toml +47 -0
- data/templates/soul.md +1 -1
- metadata +83 -4
- data/CHANGELOG.md +0 -80
- data/Gemfile +0 -17
- data/lib/tools/return_result.rb +0 -81
data/templates/config.toml
CHANGED
|
@@ -39,6 +39,10 @@ mcp_response = 60
|
|
|
39
39
|
# Web fetch request timeout.
|
|
40
40
|
web_request = 10
|
|
41
41
|
|
|
42
|
+
# Per-tool-call timeout. The agent can override per call via the timeout parameter.
|
|
43
|
+
# Also used as the default deadline for orphan detection in heal_orphaned_tool_calls!.
|
|
44
|
+
tool = 180
|
|
45
|
+
|
|
42
46
|
# ─── Shell ──────────────────────────────────────────────────────
|
|
43
47
|
|
|
44
48
|
[shell]
|
|
@@ -94,6 +98,9 @@ soul = "{{ANIMA_HOME}}/soul.md"
|
|
|
94
98
|
|
|
95
99
|
[session]
|
|
96
100
|
|
|
101
|
+
# View mode for new sessions: "basic", "verbose", or "debug".
|
|
102
|
+
default_view_mode = "basic"
|
|
103
|
+
|
|
97
104
|
# Regenerate session name every N messages.
|
|
98
105
|
name_generation_interval = 30
|
|
99
106
|
|
|
@@ -114,3 +121,43 @@ blocking_on_agent_message = false
|
|
|
114
121
|
|
|
115
122
|
# Number of recent events to include in the analytical brain's context window.
|
|
116
123
|
event_window = 20
|
|
124
|
+
|
|
125
|
+
# ─── Mneme (Memory Department) ──────────────────────────────────
|
|
126
|
+
|
|
127
|
+
[mneme]
|
|
128
|
+
|
|
129
|
+
# Maximum tokens per Mneme LLM response.
|
|
130
|
+
max_tokens = 2048
|
|
131
|
+
|
|
132
|
+
# Fraction of the main viewport token budget allocated to Mneme's viewport.
|
|
133
|
+
# Mneme sees roughly this fraction of the total context when triggered.
|
|
134
|
+
viewport_fraction = 0.33
|
|
135
|
+
|
|
136
|
+
# Fraction of the main viewport token budget reserved for Level 1 snapshots
|
|
137
|
+
# (hourly summaries). Snapshots appear above the sliding window.
|
|
138
|
+
l1_budget_fraction = 0.15
|
|
139
|
+
|
|
140
|
+
# Fraction of the main viewport token budget reserved for Level 2 snapshots
|
|
141
|
+
# (daily/weekly meta-summaries). Displayed above L1 snapshots.
|
|
142
|
+
l2_budget_fraction = 0.05
|
|
143
|
+
|
|
144
|
+
# Number of uncovered Level 1 snapshots that triggers Level 2 compression.
|
|
145
|
+
l2_snapshot_threshold = 5
|
|
146
|
+
|
|
147
|
+
# Fraction of the main viewport token budget reserved for pinned events.
|
|
148
|
+
# Pinned events appear between snapshots and the sliding window in the Goals section.
|
|
149
|
+
pinned_budget_fraction = 0.05
|
|
150
|
+
|
|
151
|
+
# ─── Recall (Associative Memory) ─────────────────────────────────
|
|
152
|
+
|
|
153
|
+
[recall]
|
|
154
|
+
|
|
155
|
+
# Maximum search results returned per FTS5 query.
|
|
156
|
+
max_results = 5
|
|
157
|
+
|
|
158
|
+
# Fraction of the main viewport token budget reserved for recalled memories.
|
|
159
|
+
# Recalled memories appear between snapshots and the sliding window.
|
|
160
|
+
budget_fraction = 0.05
|
|
161
|
+
|
|
162
|
+
# Maximum tokens per individual recall snippet.
|
|
163
|
+
max_snippet_tokens = 512
|
data/templates/soul.md
CHANGED
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.
|
|
4
|
+
version: 1.1.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Yevhenii Hurin
|
|
@@ -9,6 +9,20 @@ bindir: exe
|
|
|
9
9
|
cert_chain: []
|
|
10
10
|
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: certifi
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - ">="
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '0'
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - ">="
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '0'
|
|
12
26
|
- !ruby/object:Gem::Dependency
|
|
13
27
|
name: draper
|
|
14
28
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -121,6 +135,20 @@ dependencies:
|
|
|
121
135
|
- - "~>"
|
|
122
136
|
- !ruby/object:Gem::Version
|
|
123
137
|
version: '1.4'
|
|
138
|
+
- !ruby/object:Gem::Dependency
|
|
139
|
+
name: reverse_markdown
|
|
140
|
+
requirement: !ruby/object:Gem::Requirement
|
|
141
|
+
requirements:
|
|
142
|
+
- - "~>"
|
|
143
|
+
- !ruby/object:Gem::Version
|
|
144
|
+
version: '3.0'
|
|
145
|
+
type: :runtime
|
|
146
|
+
prerelease: false
|
|
147
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
148
|
+
requirements:
|
|
149
|
+
- - "~>"
|
|
150
|
+
- !ruby/object:Gem::Version
|
|
151
|
+
version: '3.0'
|
|
124
152
|
- !ruby/object:Gem::Dependency
|
|
125
153
|
name: solid_cable
|
|
126
154
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -177,6 +205,20 @@ dependencies:
|
|
|
177
205
|
- - "~>"
|
|
178
206
|
- !ruby/object:Gem::Version
|
|
179
207
|
version: '4.0'
|
|
208
|
+
- !ruby/object:Gem::Dependency
|
|
209
|
+
name: toon-ruby
|
|
210
|
+
requirement: !ruby/object:Gem::Requirement
|
|
211
|
+
requirements:
|
|
212
|
+
- - "~>"
|
|
213
|
+
- !ruby/object:Gem::Version
|
|
214
|
+
version: '0.1'
|
|
215
|
+
type: :runtime
|
|
216
|
+
prerelease: false
|
|
217
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
218
|
+
requirements:
|
|
219
|
+
- - "~>"
|
|
220
|
+
- !ruby/object:Gem::Version
|
|
221
|
+
version: '0.1'
|
|
180
222
|
- !ruby/object:Gem::Dependency
|
|
181
223
|
name: websocket-client-simple
|
|
182
224
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -198,9 +240,8 @@ executables:
|
|
|
198
240
|
extensions: []
|
|
199
241
|
extra_rdoc_files: []
|
|
200
242
|
files:
|
|
243
|
+
- ".gitattributes"
|
|
201
244
|
- ".reek.yml"
|
|
202
|
-
- CHANGELOG.md
|
|
203
|
-
- Gemfile
|
|
204
245
|
- LICENSE.txt
|
|
205
246
|
- Procfile
|
|
206
247
|
- Procfile.dev
|
|
@@ -221,17 +262,24 @@ files:
|
|
|
221
262
|
- app/decorators/event_decorator.rb
|
|
222
263
|
- app/decorators/system_message_decorator.rb
|
|
223
264
|
- app/decorators/tool_call_decorator.rb
|
|
265
|
+
- app/decorators/tool_decorator.rb
|
|
224
266
|
- app/decorators/tool_response_decorator.rb
|
|
225
267
|
- app/decorators/user_message_decorator.rb
|
|
268
|
+
- app/decorators/web_get_tool_decorator.rb
|
|
226
269
|
- app/jobs/agent_request_job.rb
|
|
227
270
|
- app/jobs/analytical_brain_job.rb
|
|
228
271
|
- app/jobs/application_job.rb
|
|
229
272
|
- app/jobs/count_event_tokens_job.rb
|
|
273
|
+
- app/jobs/mneme_job.rb
|
|
274
|
+
- app/jobs/passive_recall_job.rb
|
|
230
275
|
- app/models/application_record.rb
|
|
231
276
|
- app/models/concerns/event/broadcasting.rb
|
|
232
277
|
- app/models/event.rb
|
|
233
278
|
- app/models/goal.rb
|
|
279
|
+
- app/models/goal_pinned_event.rb
|
|
280
|
+
- app/models/pinned_event.rb
|
|
234
281
|
- app/models/session.rb
|
|
282
|
+
- app/models/snapshot.rb
|
|
235
283
|
- bin/jobs
|
|
236
284
|
- bin/rails
|
|
237
285
|
- bin/rake
|
|
@@ -245,6 +293,7 @@ files:
|
|
|
245
293
|
- config/environments/production.rb
|
|
246
294
|
- config/environments/test.rb
|
|
247
295
|
- config/initializers/event_subscribers.rb
|
|
296
|
+
- config/initializers/fts5_schema_dump.rb
|
|
248
297
|
- config/initializers/inflections.rb
|
|
249
298
|
- config/puma.rb
|
|
250
299
|
- config/queue.yml
|
|
@@ -270,6 +319,10 @@ files:
|
|
|
270
319
|
- db/migrate/20260315144837_add_completed_at_to_goals.rb
|
|
271
320
|
- db/migrate/20260315191105_add_active_workflow_to_sessions.rb
|
|
272
321
|
- db/migrate/20260316094817_add_interrupt_requested_to_sessions.rb
|
|
322
|
+
- db/migrate/20260321080000_create_mneme_schema.rb
|
|
323
|
+
- db/migrate/20260321120000_create_pinned_events.rb
|
|
324
|
+
- db/migrate/20260321140000_create_events_fts_index.rb
|
|
325
|
+
- db/migrate/20260321140100_add_recalled_event_ids_to_sessions.rb
|
|
273
326
|
- db/queue_schema.rb
|
|
274
327
|
- db/seeds.rb
|
|
275
328
|
- exe/anima
|
|
@@ -279,6 +332,7 @@ files:
|
|
|
279
332
|
- lib/analytical_brain.rb
|
|
280
333
|
- lib/analytical_brain/runner.rb
|
|
281
334
|
- lib/analytical_brain/tools/activate_skill.rb
|
|
335
|
+
- lib/analytical_brain/tools/assign_nickname.rb
|
|
282
336
|
- lib/analytical_brain/tools/deactivate_skill.rb
|
|
283
337
|
- lib/analytical_brain/tools/deactivate_workflow.rb
|
|
284
338
|
- lib/analytical_brain/tools/everything_is_ready.rb
|
|
@@ -294,15 +348,19 @@ files:
|
|
|
294
348
|
- lib/anima/config_migrator.rb
|
|
295
349
|
- lib/anima/installer.rb
|
|
296
350
|
- lib/anima/settings.rb
|
|
351
|
+
- lib/anima/spinner.rb
|
|
297
352
|
- lib/anima/version.rb
|
|
298
353
|
- lib/credential_store.rb
|
|
299
354
|
- lib/environment_probe.rb
|
|
300
355
|
- lib/events/agent_message.rb
|
|
301
356
|
- lib/events/base.rb
|
|
357
|
+
- lib/events/bounce_back.rb
|
|
302
358
|
- lib/events/bus.rb
|
|
303
359
|
- lib/events/subscriber.rb
|
|
304
360
|
- lib/events/subscribers/message_collector.rb
|
|
305
361
|
- lib/events/subscribers/persister.rb
|
|
362
|
+
- lib/events/subscribers/subagent_message_router.rb
|
|
363
|
+
- lib/events/subscribers/transient_broadcaster.rb
|
|
306
364
|
- lib/events/system_message.rb
|
|
307
365
|
- lib/events/tool_call.rb
|
|
308
366
|
- lib/events/tool_response.rb
|
|
@@ -313,18 +371,28 @@ files:
|
|
|
313
371
|
- lib/mcp/health_check.rb
|
|
314
372
|
- lib/mcp/secrets.rb
|
|
315
373
|
- lib/mcp/stdio_transport.rb
|
|
374
|
+
- lib/mneme.rb
|
|
375
|
+
- lib/mneme/compressed_viewport.rb
|
|
376
|
+
- lib/mneme/l2_runner.rb
|
|
377
|
+
- lib/mneme/passive_recall.rb
|
|
378
|
+
- lib/mneme/runner.rb
|
|
379
|
+
- lib/mneme/search.rb
|
|
380
|
+
- lib/mneme/tools/attach_events_to_goals.rb
|
|
381
|
+
- lib/mneme/tools/everything_ok.rb
|
|
382
|
+
- lib/mneme/tools/save_snapshot.rb
|
|
316
383
|
- lib/providers/anthropic.rb
|
|
317
384
|
- lib/shell_session.rb
|
|
318
385
|
- lib/skills/definition.rb
|
|
319
386
|
- lib/skills/registry.rb
|
|
387
|
+
- lib/tasks/fts5.rake
|
|
320
388
|
- lib/tools/base.rb
|
|
321
389
|
- lib/tools/bash.rb
|
|
322
390
|
- lib/tools/edit.rb
|
|
323
391
|
- lib/tools/mcp_tool.rb
|
|
324
392
|
- lib/tools/read.rb
|
|
325
393
|
- lib/tools/registry.rb
|
|
394
|
+
- lib/tools/remember.rb
|
|
326
395
|
- lib/tools/request_feature.rb
|
|
327
|
-
- lib/tools/return_result.rb
|
|
328
396
|
- lib/tools/spawn_specialist.rb
|
|
329
397
|
- lib/tools/spawn_subagent.rb
|
|
330
398
|
- lib/tools/subagent_prompts.rb
|
|
@@ -333,8 +401,19 @@ files:
|
|
|
333
401
|
- lib/tools/write.rb
|
|
334
402
|
- lib/tui/app.rb
|
|
335
403
|
- lib/tui/cable_client.rb
|
|
404
|
+
- lib/tui/decorators/base_decorator.rb
|
|
405
|
+
- lib/tui/decorators/bash_decorator.rb
|
|
406
|
+
- lib/tui/decorators/edit_decorator.rb
|
|
407
|
+
- lib/tui/decorators/read_decorator.rb
|
|
408
|
+
- lib/tui/decorators/think_decorator.rb
|
|
409
|
+
- lib/tui/decorators/web_get_decorator.rb
|
|
410
|
+
- lib/tui/decorators/write_decorator.rb
|
|
411
|
+
- lib/tui/flash.rb
|
|
412
|
+
- lib/tui/formatting.rb
|
|
413
|
+
- lib/tui/height_map.rb
|
|
336
414
|
- lib/tui/input_buffer.rb
|
|
337
415
|
- lib/tui/message_store.rb
|
|
416
|
+
- lib/tui/performance_logger.rb
|
|
338
417
|
- lib/tui/screens/chat.rb
|
|
339
418
|
- lib/workflows/definition.rb
|
|
340
419
|
- lib/workflows/registry.rb
|
data/CHANGELOG.md
DELETED
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
## [Unreleased]
|
|
2
|
-
|
|
3
|
-
### Added
|
|
4
|
-
- `anima update` command — upgrades the gem and merges new config keys into existing `config.toml` without overwriting user-customized values — `--migrate-only` flag to skip gem upgrade (#155)
|
|
5
|
-
- Directory-based skills format — `skills/skill-name/SKILL.md` with optional `references/` and `examples/` subdirectories alongside flat `.md` files (#152)
|
|
6
|
-
- Import 6 marketplace skills: activerecord, rspec, draper-decorators, dragonruby, ratatui-ruby, mcp-server (#152)
|
|
7
|
-
- Tmux-style focus switching — `Ctrl+A ↑` enters chat scrolling mode with yellow border, `Escape` returns to input; arrow keys and Page Up/Down scroll chat, mouse scroll works in both modes (#87)
|
|
8
|
-
- Bash-style input history — press ↑ at top of input to recall previous messages, ↓ to navigate forward; original draft restored when exiting history (#87)
|
|
9
|
-
- Real-time event broadcasting via `Event::Broadcasting` concern — `after_create_commit` and `after_update_commit` callbacks broadcast decorated payloads with database ID and action type to the session's ActionCable stream (#91)
|
|
10
|
-
- TUI `MessageStore` ID-indexed updates — events with `action: "update"` replace existing entries in-place (O(1) lookup) without changing display order
|
|
11
|
-
- `CountEventTokensJob` triggers broadcast — uses `update!` so token count updates push to connected clients in real time
|
|
12
|
-
- Connection status constants in `CableClient` — replaces magic strings with named constants for protocol message types
|
|
13
|
-
|
|
14
|
-
### Changed
|
|
15
|
-
- Connection status indicator simplified — emoji-only `🟢` for normal state, descriptive text only for abnormal states (#80)
|
|
16
|
-
- `STATUS_STYLES` structure simplified from `{label, fg, bg}` to `{label, color}` (#80)
|
|
17
|
-
- `ActionCableBridge` removed — broadcasting moved from EventBus subscriber to AR callbacks, eliminating the timing gap where events were broadcast before persistence
|
|
18
|
-
- `SessionChannel` history includes event IDs for client-side correlation
|
|
19
|
-
|
|
20
|
-
### Fixed
|
|
21
|
-
- TUI showed empty chat on reconnect — message store was cleared _after_ history arrived because `confirm_subscription` comes after `transmit` in Action Cable protocol; now clears on "subscribing" before history (#82)
|
|
22
|
-
|
|
23
|
-
## [0.2.1] - 2026-03-13
|
|
24
|
-
|
|
25
|
-
### Added
|
|
26
|
-
- TUI view mode switching via `Ctrl+a → v` — cycle between Basic, Verbose, and Debug (#75)
|
|
27
|
-
- Draper EventDecorator hierarchy — structured data decorators for all event types (#74)
|
|
28
|
-
- Decorators return structured hashes (not strings) for transport-layer filtering (#86)
|
|
29
|
-
- Basic mode tool call counter — inline `🔧 Tools: X/Y ✓` aggregation (#73)
|
|
30
|
-
- Verbose view mode rendering — timestamps, tool call previews, system messages (#76)
|
|
31
|
-
- Tool call previews: bash `$ command`, web_get `GET url`, generic JSON fallback
|
|
32
|
-
- Tool response display: truncated to 3 lines, `↩` success / `❌` failure indicators
|
|
33
|
-
- Debug view mode — token counts per message, full tool args/responses, tool use IDs (#77)
|
|
34
|
-
- Estimated token indicator (`~` prefix) for events not yet counted by background job
|
|
35
|
-
- View mode persisted on Session model — survives TUI disconnect/reconnect
|
|
36
|
-
- Mode changes broadcast to all connected clients with re-decorated viewport
|
|
37
|
-
|
|
38
|
-
### Fixed
|
|
39
|
-
- Newlines in LLM responses collapsed into single line in rendered view modes
|
|
40
|
-
- Loading state stuck after view mode switch — input blocked with "Thinking..."
|
|
41
|
-
|
|
42
|
-
## [0.2.0] - 2026-03-10
|
|
43
|
-
|
|
44
|
-
### Added
|
|
45
|
-
- Client-server architecture — Brain (Rails + Puma) runs as persistent service, TUI connects via WebSocket
|
|
46
|
-
- Action Cable infrastructure with Solid Cable adapter for Brain/TUI WebSocket communication
|
|
47
|
-
- `SessionChannel` — WebSocket channel for session management, message relay, and session switching
|
|
48
|
-
- Graceful TUI reconnection with exponential backoff (up to 10 attempts, max 30s delay)
|
|
49
|
-
- `AgentRequestJob` — background job for LLM agent loops with retry logic for transient failures (network errors, rate limits, server errors)
|
|
50
|
-
- Provider error hierarchy — `TransientError`, `RateLimitError`, `ServerError` for retry classification; `AuthenticationError` for immediate discard
|
|
51
|
-
- `AgentLoop#run` — retry-safe entry point for job callers; lets errors propagate for external retry handling
|
|
52
|
-
- `AgentLoop` service — decouples LLM orchestration from TUI; callable from background jobs, Action Cable channels, or TUI directly
|
|
53
|
-
- Session and event persistence to SQLite — conversations survive TUI restart
|
|
54
|
-
- `Session` model — owns an ordered event stream
|
|
55
|
-
- `Event` model — polymorphic type, JSON payload, auto-incrementing position
|
|
56
|
-
- `Events::Subscribers::Persister` — writes all events to SQLite as they flow through the bus
|
|
57
|
-
- TUI resumes last session on startup, `Ctrl+a > n` creates a new session
|
|
58
|
-
- Event system using Rails Structured Event Reporter (`Rails.event`)
|
|
59
|
-
- Five event types: `system_message`, `user_message`, `agent_message`, `tool_call`, `tool_response`
|
|
60
|
-
- `Events::Bus` — thin wrapper around `Rails.event` for emitting and subscribing to Anima events
|
|
61
|
-
- `Events::Subscribers::MessageCollector` — in-memory subscriber that collects displayable messages
|
|
62
|
-
- Chat screen refactored from raw array to event-driven architecture
|
|
63
|
-
- TUI chat screen with LLM integration — in-memory message array, threaded API calls
|
|
64
|
-
- Chat input with character validation, backspace, Enter to submit
|
|
65
|
-
- Loading indicator — "Thinking" status bar mode, grayed-out input during LLM calls
|
|
66
|
-
- New session command (`Ctrl+a > n`) clears conversation
|
|
67
|
-
- Error handling — API failures displayed inline as chat messages
|
|
68
|
-
- Anthropic API subscription token authentication
|
|
69
|
-
- LLM client (raw HTTP to Anthropic API)
|
|
70
|
-
- TUI scaffold with RatatuiRuby — tmux-style `Ctrl+a` command mode, sidebar, status bar
|
|
71
|
-
- Headless Rails 8.1 app (API-only, no views/assets)
|
|
72
|
-
- `anima install` command — creates ~/.anima/ tree, per-environment credentials, systemd user service
|
|
73
|
-
- `anima start` command — runs db:prepare and boots Rails via Foreman
|
|
74
|
-
- Systemd user service — auto-enables and starts brain on `anima install`
|
|
75
|
-
- SQLite databases, logs, tmp, and credentials stored in ~/.anima/
|
|
76
|
-
- Environment validation (development, test, production)
|
|
77
|
-
|
|
78
|
-
## [0.0.1] - 2026-03-06
|
|
79
|
-
|
|
80
|
-
- Initial gem scaffold with CI and RubyGems publishing
|
data/Gemfile
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
source "https://rubygems.org"
|
|
4
|
-
|
|
5
|
-
# Specify your gem's dependencies in anima-core.gemspec
|
|
6
|
-
gemspec
|
|
7
|
-
|
|
8
|
-
gem "irb"
|
|
9
|
-
gem "rake", "~> 13.0"
|
|
10
|
-
|
|
11
|
-
gem "rspec", "~> 3.0"
|
|
12
|
-
gem "rspec-rails", "~> 7.0"
|
|
13
|
-
|
|
14
|
-
gem "reek", "~> 6.5"
|
|
15
|
-
gem "standard", "~> 1.3"
|
|
16
|
-
|
|
17
|
-
gem "webmock", "~> 3.23"
|
data/lib/tools/return_result.rb
DELETED
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Tools
|
|
4
|
-
# Sub-agent-only tool that delivers a completed result back to the
|
|
5
|
-
# parent session as a tool_call/tool_response pair. The parent agent
|
|
6
|
-
# sees it as if it called a tool itself — no custom event types needed.
|
|
7
|
-
#
|
|
8
|
-
# Never registered for main sessions — only sub-agents see this tool.
|
|
9
|
-
class ReturnResult < Base
|
|
10
|
-
def self.tool_name = "return_result"
|
|
11
|
-
|
|
12
|
-
def self.description = "Return your completed result to the parent agent. " \
|
|
13
|
-
"Call this when you have fulfilled the assigned task."
|
|
14
|
-
|
|
15
|
-
def self.input_schema
|
|
16
|
-
{
|
|
17
|
-
type: "object",
|
|
18
|
-
properties: {
|
|
19
|
-
result: {
|
|
20
|
-
type: "string",
|
|
21
|
-
description: "The completed deliverable to send back to the parent agent"
|
|
22
|
-
}
|
|
23
|
-
},
|
|
24
|
-
required: ["result"]
|
|
25
|
-
}
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
# @param session [Session] the sub-agent session returning a result
|
|
29
|
-
def initialize(session:, **)
|
|
30
|
-
@session = session
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
# Emits a tool_call/tool_response pair in the parent session so the
|
|
34
|
-
# parent agent sees the sub-agent result as a regular tool interaction.
|
|
35
|
-
#
|
|
36
|
-
# @param input [Hash<String, Object>] with "result" key
|
|
37
|
-
# @return [String, Hash] confirmation message, or Hash with :error key on failure
|
|
38
|
-
def execute(input)
|
|
39
|
-
result = input["result"].to_s.strip
|
|
40
|
-
return {error: "Result cannot be blank"} if result.empty?
|
|
41
|
-
|
|
42
|
-
parent = @session.parent_session
|
|
43
|
-
return {error: "No parent session — only sub-agents can return results"} unless parent
|
|
44
|
-
|
|
45
|
-
tool_use_id = "toolu_subagent_#{@session.id}"
|
|
46
|
-
task = extract_task
|
|
47
|
-
# Specialists are spawned with a name from the registry; generic sub-agents have nil name.
|
|
48
|
-
origin_tool = @session.name ? SpawnSpecialist.tool_name : SpawnSubagent.tool_name
|
|
49
|
-
|
|
50
|
-
Events::Bus.emit(Events::ToolCall.new(
|
|
51
|
-
content: "Sub-agent result (session #{@session.id})",
|
|
52
|
-
tool_name: origin_tool,
|
|
53
|
-
tool_input: {"task" => task, "session_id" => @session.id},
|
|
54
|
-
tool_use_id: tool_use_id,
|
|
55
|
-
session_id: parent.id
|
|
56
|
-
))
|
|
57
|
-
|
|
58
|
-
Events::Bus.emit(Events::ToolResponse.new(
|
|
59
|
-
content: result,
|
|
60
|
-
tool_name: origin_tool,
|
|
61
|
-
tool_use_id: tool_use_id,
|
|
62
|
-
session_id: parent.id
|
|
63
|
-
))
|
|
64
|
-
|
|
65
|
-
"Result delivered to parent session #{parent.id}."
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
private
|
|
69
|
-
|
|
70
|
-
# Extracts the original task from the sub-agent's first user message.
|
|
71
|
-
# @return [String]
|
|
72
|
-
def extract_task
|
|
73
|
-
@session.events
|
|
74
|
-
.where(event_type: "user_message")
|
|
75
|
-
.order(:id)
|
|
76
|
-
.pick(:payload)
|
|
77
|
-
&.dig("content")
|
|
78
|
-
.to_s
|
|
79
|
-
end
|
|
80
|
-
end
|
|
81
|
-
end
|