anima-core 0.2.0 → 0.3.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.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +34 -0
  3. data/README.md +20 -32
  4. data/anima-core.gemspec +1 -0
  5. data/app/channels/session_channel.rb +220 -26
  6. data/app/decorators/agent_message_decorator.rb +24 -0
  7. data/app/decorators/application_decorator.rb +6 -0
  8. data/app/decorators/event_decorator.rb +173 -0
  9. data/app/decorators/system_message_decorator.rb +21 -0
  10. data/app/decorators/tool_call_decorator.rb +48 -0
  11. data/app/decorators/tool_response_decorator.rb +37 -0
  12. data/app/decorators/user_message_decorator.rb +35 -0
  13. data/app/jobs/agent_request_job.rb +31 -2
  14. data/app/jobs/count_event_tokens_job.rb +14 -3
  15. data/app/models/concerns/event/broadcasting.rb +63 -0
  16. data/app/models/event.rb +36 -0
  17. data/app/models/session.rb +46 -14
  18. data/config/application.rb +1 -0
  19. data/config/initializers/event_subscribers.rb +0 -1
  20. data/config/routes.rb +0 -6
  21. data/db/cable_schema.rb +14 -2
  22. data/db/migrate/20260312170000_add_view_mode_to_sessions.rb +7 -0
  23. data/db/migrate/20260313010000_add_status_to_events.rb +8 -0
  24. data/db/migrate/20260313020000_add_processing_to_sessions.rb +7 -0
  25. data/lib/agent_loop.rb +5 -2
  26. data/lib/anima/cli.rb +1 -40
  27. data/lib/anima/version.rb +1 -1
  28. data/lib/events/subscribers/persister.rb +1 -0
  29. data/lib/events/user_message.rb +17 -0
  30. data/lib/providers/anthropic.rb +3 -13
  31. data/lib/tools/edit.rb +227 -0
  32. data/lib/tools/read.rb +152 -0
  33. data/lib/tools/write.rb +86 -0
  34. data/lib/tui/app.rb +831 -55
  35. data/lib/tui/cable_client.rb +79 -31
  36. data/lib/tui/input_buffer.rb +181 -0
  37. data/lib/tui/message_store.rb +162 -14
  38. data/lib/tui/screens/chat.rb +504 -75
  39. metadata +30 -5
  40. data/app/controllers/api/sessions_controller.rb +0 -25
  41. data/lib/events/subscribers/action_cable_bridge.rb +0 -35
  42. data/lib/tui/screens/anthropic.rb +0 -25
  43. data/lib/tui/screens/settings.rb +0 -52
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: 0.2.0
4
+ version: 0.3.0
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: draper
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: '4.0'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: '4.0'
12
26
  - !ruby/object:Gem::Dependency
13
27
  name: foreman
14
28
  requirement: !ruby/object:Gem::Requirement
@@ -155,12 +169,19 @@ files:
155
169
  - app/channels/application_cable/channel.rb
156
170
  - app/channels/application_cable/connection.rb
157
171
  - app/channels/session_channel.rb
158
- - app/controllers/api/sessions_controller.rb
159
172
  - app/controllers/application_controller.rb
173
+ - app/decorators/agent_message_decorator.rb
174
+ - app/decorators/application_decorator.rb
175
+ - app/decorators/event_decorator.rb
176
+ - app/decorators/system_message_decorator.rb
177
+ - app/decorators/tool_call_decorator.rb
178
+ - app/decorators/tool_response_decorator.rb
179
+ - app/decorators/user_message_decorator.rb
160
180
  - app/jobs/agent_request_job.rb
161
181
  - app/jobs/application_job.rb
162
182
  - app/jobs/count_event_tokens_job.rb
163
183
  - app/models/application_record.rb
184
+ - app/models/concerns/event/broadcasting.rb
164
185
  - app/models/event.rb
165
186
  - app/models/session.rb
166
187
  - bin/jobs
@@ -189,6 +210,9 @@ files:
189
210
  - db/migrate/20260308140000_remove_position_from_events.rb
190
211
  - db/migrate/20260308150000_add_token_count_to_events.rb
191
212
  - db/migrate/20260308160000_add_tool_use_id_to_events.rb
213
+ - db/migrate/20260312170000_add_view_mode_to_sessions.rb
214
+ - db/migrate/20260313010000_add_status_to_events.rb
215
+ - db/migrate/20260313020000_add_processing_to_sessions.rb
192
216
  - db/queue_schema.rb
193
217
  - db/seeds.rb
194
218
  - exe/anima
@@ -201,7 +225,6 @@ files:
201
225
  - lib/events/base.rb
202
226
  - lib/events/bus.rb
203
227
  - lib/events/subscriber.rb
204
- - lib/events/subscribers/action_cable_bridge.rb
205
228
  - lib/events/subscribers/message_collector.rb
206
229
  - lib/events/subscribers/persister.rb
207
230
  - lib/events/system_message.rb
@@ -213,14 +236,16 @@ files:
213
236
  - lib/shell_session.rb
214
237
  - lib/tools/base.rb
215
238
  - lib/tools/bash.rb
239
+ - lib/tools/edit.rb
240
+ - lib/tools/read.rb
216
241
  - lib/tools/registry.rb
217
242
  - lib/tools/web_get.rb
243
+ - lib/tools/write.rb
218
244
  - lib/tui/app.rb
219
245
  - lib/tui/cable_client.rb
246
+ - lib/tui/input_buffer.rb
220
247
  - lib/tui/message_store.rb
221
- - lib/tui/screens/anthropic.rb
222
248
  - lib/tui/screens/chat.rb
223
- - lib/tui/screens/settings.rb
224
249
  homepage: https://github.com/hoblin/anima
225
250
  licenses:
226
251
  - MIT
@@ -1,25 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Api
4
- # REST endpoint for session management. The TUI client uses this to
5
- # obtain a session ID before subscribing to the WebSocket channel.
6
- class SessionsController < ApplicationController
7
- # Returns the most recent session or creates one if none exist.
8
- #
9
- # GET /api/sessions/current
10
- # @return [JSON] { id: Integer }
11
- def current
12
- session = Session.last || Session.create!
13
- render json: {id: session.id}
14
- end
15
-
16
- # Creates a new conversation session.
17
- #
18
- # POST /api/sessions
19
- # @return [JSON] { id: Integer }
20
- def create
21
- session = Session.create!
22
- render json: {id: session.id}, status: :created
23
- end
24
- end
25
- end
@@ -1,35 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Events
4
- module Subscribers
5
- # Forwards EventBus events to Action Cable, bridging internal pub/sub
6
- # to external WebSocket clients. Each event is broadcast to the
7
- # session-specific stream (e.g. "session_42"), matching the stream
8
- # name used by {SessionChannel}.
9
- #
10
- # Only events with a valid session_id are broadcast — events without
11
- # one have no destination channel and are silently skipped.
12
- #
13
- # @example
14
- # Events::Bus.subscribe(Events::Subscribers::ActionCableBridge.instance)
15
- # # Now all events with session_id flow to "session_<id>" streams
16
- class ActionCableBridge
17
- include Events::Subscriber
18
- include Singleton
19
-
20
- # Receives a Rails.event notification hash and broadcasts the payload
21
- # to the session's Action Cable stream.
22
- #
23
- # @param event [Hash] with :payload containing event data including :session_id
24
- def emit(event)
25
- payload = event[:payload]
26
- return unless payload.is_a?(Hash)
27
-
28
- session_id = payload[:session_id]
29
- return if session_id.nil?
30
-
31
- ActionCable.server.broadcast("session_#{session_id}", payload)
32
- end
33
- end
34
- end
35
- end
@@ -1,25 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module TUI
4
- module Screens
5
- class Anthropic
6
- def render(frame, area, tui)
7
- widget = tui.paragraph(
8
- text: "Anthropic account connection will be configured here.",
9
- alignment: :center,
10
- wrap: true,
11
- block: tui.block(
12
- title: "Anthropic Connection",
13
- titles: [
14
- {content: "Esc back", position: :bottom, alignment: :center}
15
- ],
16
- borders: [:all],
17
- border_type: :rounded,
18
- border_style: {fg: "magenta"}
19
- )
20
- )
21
- frame.render_widget(widget, area)
22
- end
23
- end
24
- end
25
- end
@@ -1,52 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module TUI
4
- module Screens
5
- class Settings
6
- MENU_ITEMS = [
7
- "General",
8
- "Appearance",
9
- "Keybindings"
10
- ].freeze
11
-
12
- def initialize
13
- # Initialized on first render — requires tui context from RatatuiRuby.run block
14
- @list_state = nil
15
- end
16
-
17
- def render(frame, area, tui)
18
- @list_state ||= tui.list_state(0)
19
-
20
- list = tui.list(
21
- items: MENU_ITEMS,
22
- highlight_style: {fg: "yellow", bold: true},
23
- highlight_symbol: "> ",
24
- block: tui.block(
25
- title: "Settings",
26
- titles: [
27
- {content: "↑/↓ navigate • Esc back", position: :bottom, alignment: :center}
28
- ],
29
- borders: [:all],
30
- border_type: :rounded,
31
- border_style: {fg: "green"}
32
- )
33
- )
34
- frame.render_stateful_widget(list, area, @list_state)
35
- end
36
-
37
- def handle_event(event)
38
- return false unless @list_state
39
-
40
- if event.down? || event.j?
41
- @list_state.select_next
42
- true
43
- elsif event.up? || event.k?
44
- @list_state.select_previous
45
- true
46
- else
47
- false
48
- end
49
- end
50
- end
51
- end
52
- end