aia 1.1.1 → 2.0.0.0.pre.beta2
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/.envrc +9 -1
- data/.loki +11 -0
- data/.reek.yml +160 -0
- data/.rubocop.yml +116 -0
- data/.rubocop_strict.yml +15 -0
- data/.version +1 -1
- data/CHANGELOG.md +269 -55
- data/IMPLEMENTATION_PLAN.md +506 -0
- data/README.md +267 -239
- data/Rakefile +5 -5
- data/_typos.toml +10 -0
- data/aia.gemspec +92 -0
- data/architecture_review.md +314 -0
- data/bin/aia +16 -0
- data/config/aia.yml +13 -0
- data/docs/AGENTS.md +40 -0
- data/docs/advanced-prompting.md +67 -3
- data/docs/cli-reference.md +312 -56
- data/docs/configuration.md +130 -19
- data/docs/contributing.md +56 -2
- data/docs/directives-reference.md +593 -78
- data/docs/faq.md +85 -3
- data/docs/guides/available-models.md +1 -1
- data/docs/guides/basic-usage.md +6 -6
- data/docs/guides/chat.md +40 -16
- data/docs/guides/crew.md +239 -0
- data/docs/guides/executable-prompts.md +1 -1
- data/docs/guides/index.md +1 -0
- data/docs/guides/models.md +15 -0
- data/docs/index.md +29 -2
- data/docs/installation.md +44 -17
- data/docs/mcp-integration.md +40 -0
- data/docs/prompt_management.md +85 -86
- data/docs/security.md +47 -0
- data/docs/special_projects_guide.md +386 -0
- data/docs/tools-and-mcp-examples.md +23 -0
- data/docs/workflows-and-pipelines.md +84 -7
- data/examples/.gitignore +1 -0
- data/examples/00_setup_aia.sh +27 -44
- data/examples/11_multi_model.sh +4 -14
- data/examples/12_token_usage.sh +3 -12
- data/examples/18_tools.sh +10 -2
- data/examples/22_chat_mode.sh +0 -10
- data/examples/23_verify.sh +139 -0
- data/examples/24_decompose.sh +139 -0
- data/examples/25_spawn.sh +139 -0
- data/examples/26_debate.sh +97 -0
- data/examples/27_mention_routing.sh +157 -0
- data/examples/28_model_switching.sh +106 -0
- data/examples/29_agent_harness.sh +177 -0
- data/examples/README.md +65 -0
- data/examples/advanced_multi_robot_capabilities_without_examples.md +106 -0
- data/examples/aia_config.yml +1 -1
- data/examples/aia_config_orchestrator.yml +45 -0
- data/examples/common.sh +18 -6
- data/examples/context/tech_stack.md +2 -2
- data/examples/prompts_dir/roles/orchestrator.md +21 -0
- data/examples/requirements/sinatra_taskflow_app.md +139 -0
- data/examples/rules/01_classify_ruby.rb +16 -0
- data/examples/rules/02_prefer_claude_for_code.rb +19 -0
- data/examples/rules/03_gate_prompt_length.rb +19 -0
- data/examples/rules/04_tool_selection.rb +41 -0
- data/examples/rules/README.md +30 -0
- data/examples/run_all.sh +48 -15
- data/examples/tools/word_count_tool.rb +1 -1
- data/lib/AGENTS.md +57 -0
- data/lib/aia/chat_loop.rb +263 -167
- data/lib/aia/config/cli_parser.rb +217 -145
- data/lib/aia/config/defaults.yml +62 -33
- data/lib/aia/config/mcp_parser.rb +52 -51
- data/lib/aia/config/model_spec.rb +34 -2
- data/lib/aia/config/validator.rb +171 -216
- data/lib/aia/config.rb +111 -145
- data/lib/aia/content_extractor.rb +155 -0
- data/lib/aia/cost_calculator.rb +39 -0
- data/lib/aia/crew.rb +164 -0
- data/lib/aia/debate_handler.rb +174 -0
- data/lib/aia/delegate_handler.rb +116 -0
- data/lib/aia/directive.rb +43 -26
- data/lib/aia/directive_processor.rb +16 -7
- data/lib/aia/directives/configuration_directives.rb +214 -60
- data/lib/aia/directives/context_directives.rb +67 -52
- data/lib/aia/directives/execution_directives.rb +141 -4
- data/lib/aia/directives/model_directives.rb +163 -141
- data/lib/aia/directives/trakflow_directives.rb +62 -0
- data/lib/aia/directives/utility_directives.rb +227 -30
- data/lib/aia/directives/web_and_file_directives.rb +126 -77
- data/lib/aia/errors.rb +15 -0
- data/lib/aia/fact_asserter.rb +27 -0
- data/lib/aia/fzf.rb +9 -31
- data/lib/aia/handler_context.rb +17 -0
- data/lib/aia/handler_protocol.rb +19 -0
- data/lib/aia/history_transfer.rb +55 -0
- data/lib/aia/input_collector.rb +3 -3
- data/lib/aia/layered_orchestrator.rb +471 -0
- data/lib/aia/logger.rb +45 -25
- data/lib/aia/mcp_config_normalizer.rb +35 -0
- data/lib/aia/mcp_connection_manager.rb +315 -0
- data/lib/aia/mcp_discovery.rb +44 -0
- data/lib/aia/mcp_grouper.rb +33 -0
- data/lib/aia/mcp_server_config.rb +30 -0
- data/lib/aia/mcp_utility.rb +60 -0
- data/lib/aia/mention_router.rb +217 -0
- data/lib/aia/model_alias_registry.rb +97 -0
- data/lib/aia/model_switch_handler.rb +100 -0
- data/lib/aia/network_builder.rb +160 -0
- data/lib/aia/network_memory_manager.rb +55 -0
- data/lib/aia/patches/ruby_llm_streaming_error.rb +43 -0
- data/lib/aia/patches/ruby_llm_tool_error.rb +96 -0
- data/lib/aia/pipeline_orchestrator.rb +272 -0
- data/lib/aia/plugin_loader.rb +170 -0
- data/lib/aia/plugin_monitor.rb +211 -0
- data/lib/aia/prompt_decomposer.rb +159 -0
- data/lib/aia/prompt_handler.rb +56 -82
- data/lib/aia/robot_builder.rb +51 -0
- data/lib/aia/robot_factory.rb +338 -0
- data/lib/aia/robot_namer.rb +110 -0
- data/lib/aia/session.rb +87 -17
- data/lib/aia/session_tracker.rb +207 -0
- data/lib/aia/similarity_scorer.rb +41 -0
- data/lib/aia/skill_utils.rb +105 -1
- data/lib/aia/spawn_handler.rb +129 -0
- data/lib/aia/spawn_spec_parser.rb +65 -0
- data/lib/aia/special_mode_handler.rb +322 -0
- data/lib/aia/speech.rb +67 -0
- data/lib/aia/startup_coordinator.rb +151 -0
- data/lib/aia/streaming_runner.rb +172 -0
- data/lib/aia/system_prompt_assembler.rb +92 -0
- data/lib/aia/task_coordinator.rb +207 -0
- data/lib/aia/task_decomposer.rb +57 -0
- data/lib/aia/task_executor.rb +51 -0
- data/lib/aia/tfidf_math.rb +27 -0
- data/lib/aia/timing.rb +15 -0
- data/lib/aia/tool_filter/tfidf.rb +116 -0
- data/lib/aia/tool_filter/wordnet_expander.rb +127 -0
- data/lib/aia/tool_filter.rb +83 -0
- data/lib/aia/tool_filter_registry.rb +30 -0
- data/lib/aia/tool_filter_strategy.rb +146 -0
- data/lib/aia/tool_introspection.rb +17 -0
- data/lib/aia/tool_loader.rb +216 -0
- data/lib/aia/tool_utility.rb +30 -0
- data/lib/aia/tools/delegate_to_foreman_tool.rb +70 -0
- data/lib/aia/tools/recruit_robot_tool.rb +60 -0
- data/lib/aia/tools/reskill_robot_tool.rb +44 -0
- data/lib/aia/tools/task_board_tool.rb +115 -0
- data/lib/aia/trakflow_bridge.rb +175 -0
- data/lib/aia/turn_state.rb +95 -0
- data/lib/aia/ui_presenter.rb +182 -206
- data/lib/aia/utility.rb +136 -87
- data/lib/aia/{history_manager.rb → variable_input_collector.rb} +9 -9
- data/lib/aia/verification_network.rb +57 -0
- data/lib/aia.rb +124 -63
- data/mkdocs.yml +1 -0
- metadata +187 -58
- data/justfile +0 -215
- data/lib/aia/adapter/chat_execution.rb +0 -242
- data/lib/aia/adapter/error_handler.rb +0 -68
- data/lib/aia/adapter/gem_activator.rb +0 -57
- data/lib/aia/adapter/mcp_connector.rb +0 -274
- data/lib/aia/adapter/modality_handlers.rb +0 -167
- data/lib/aia/adapter/model_registry.rb +0 -81
- data/lib/aia/adapter/multi_model_chat.rb +0 -218
- data/lib/aia/adapter/provider_configurator.rb +0 -59
- data/lib/aia/adapter/tool_filter.rb +0 -85
- data/lib/aia/adapter/tool_loader.rb +0 -90
- data/lib/aia/chat_processor_service.rb +0 -178
- data/lib/aia/prompt_pipeline.rb +0 -183
- data/lib/aia/ruby_llm_adapter.rb +0 -95
- data/lib/extensions/openstruct_merge.rb +0 -48
- data/lib/extensions/ruby_llm/.irbrc +0 -56
- data/lib/extensions/ruby_llm/modalities.rb +0 -36
- data/lib/extensions/ruby_llm/provider_fix.rb +0 -79
- data/lib/refinements/string.rb +0 -16
- data/main.just +0 -76
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# lib/aia/trakflow_bridge.rb
|
|
4
|
+
#
|
|
5
|
+
# Bridge between AIA and TrakFlow task tracking.
|
|
6
|
+
# Uses the trak_flow gem directly as a Ruby library —
|
|
7
|
+
# no MCP server or LLM intermediation needed.
|
|
8
|
+
|
|
9
|
+
require "trak_flow"
|
|
10
|
+
|
|
11
|
+
module AIA
|
|
12
|
+
class TrakFlowBridge
|
|
13
|
+
def initialize
|
|
14
|
+
@db = connect_database
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Whether a TrakFlow project is initialized and the database is accessible.
|
|
18
|
+
#
|
|
19
|
+
# @return [Boolean]
|
|
20
|
+
def available?
|
|
21
|
+
!@db.nil?
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Create a TrakFlow plan from a pipeline of prompt IDs.
|
|
25
|
+
# Each step blocks the next, enforcing sequential execution.
|
|
26
|
+
#
|
|
27
|
+
# @param pipeline [Array<String>] prompt IDs in pipeline order
|
|
28
|
+
# @return [String, nil] summary of created plan
|
|
29
|
+
# :reek:TooManyStatements -- plan build: one child task per pipeline step, chained by blocking dependencies
|
|
30
|
+
def create_plan_from_pipeline(pipeline)
|
|
31
|
+
return nil unless available?
|
|
32
|
+
|
|
33
|
+
plan_title = "Pipeline: #{pipeline.join(' → ')}"
|
|
34
|
+
plan = TrakFlow::Models::Task.new(title: plan_title, plan: true, type: "task")
|
|
35
|
+
plan = @db.create_task(plan)
|
|
36
|
+
|
|
37
|
+
prev_step = nil
|
|
38
|
+
pipeline.each_with_index do |prompt_id, i|
|
|
39
|
+
step = @db.create_child_task(plan.id, {
|
|
40
|
+
title: "Step #{i + 1}: #{prompt_id}",
|
|
41
|
+
type: "task"
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
if prev_step
|
|
45
|
+
@db.add_dependency(TrakFlow::Models::Dependency.new(
|
|
46
|
+
source_id: prev_step.id,
|
|
47
|
+
target_id: step.id,
|
|
48
|
+
type: "blocks"
|
|
49
|
+
))
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
prev_step = step
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
"Plan '#{plan_title}' created with #{pipeline.size} steps."
|
|
56
|
+
rescue StandardError => e
|
|
57
|
+
$stderr.puts "Warning: TrakFlow plan creation failed: #{e.message}"
|
|
58
|
+
nil
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Update a task's status in TrakFlow.
|
|
62
|
+
#
|
|
63
|
+
# @param step_name [String] task title to find
|
|
64
|
+
# @param status [Symbol] :started, :completed, or :failed
|
|
65
|
+
# @param reason [String, nil] reason for failure
|
|
66
|
+
def update_step_status(step_name, status, reason: nil)
|
|
67
|
+
return unless available?
|
|
68
|
+
|
|
69
|
+
task = find_task_by_title(step_name)
|
|
70
|
+
return unless task
|
|
71
|
+
|
|
72
|
+
case status
|
|
73
|
+
when :started
|
|
74
|
+
task.status = "in_progress"
|
|
75
|
+
when :completed
|
|
76
|
+
task.close!(reason: reason || "Completed")
|
|
77
|
+
when :failed
|
|
78
|
+
task.status = "blocked"
|
|
79
|
+
task.append_trace("blocked", reason) if reason
|
|
80
|
+
else
|
|
81
|
+
return
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
@db.update_task(task)
|
|
85
|
+
rescue StandardError => e
|
|
86
|
+
$stderr.puts "Warning: TrakFlow status update failed: #{e.message}"
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# List ready tasks (tasks with no open blockers).
|
|
90
|
+
#
|
|
91
|
+
# @return [String, nil] formatted list of ready tasks
|
|
92
|
+
def check_ready_tasks
|
|
93
|
+
return nil unless available?
|
|
94
|
+
|
|
95
|
+
tasks = @db.ready_tasks
|
|
96
|
+
return nil if tasks.empty?
|
|
97
|
+
|
|
98
|
+
lines = tasks.map { |t| " - [#{t.id}] #{t.title} (#{t.status})" }
|
|
99
|
+
"Ready tasks (#{tasks.size}):\n#{lines.join("\n")}"
|
|
100
|
+
rescue StandardError => e
|
|
101
|
+
$stderr.puts "Warning: TrakFlow ready tasks query failed: #{e.message}"
|
|
102
|
+
nil
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# Get a summary of the current TrakFlow project state.
|
|
106
|
+
#
|
|
107
|
+
# @return [String, nil] project summary
|
|
108
|
+
def project_summary
|
|
109
|
+
return nil unless available?
|
|
110
|
+
|
|
111
|
+
all = @db.list_tasks({})
|
|
112
|
+
by_status = all.group_by(&:status)
|
|
113
|
+
|
|
114
|
+
lines = ["TrakFlow Project Summary (#{all.size} tasks):"]
|
|
115
|
+
by_status.sort.each do |status, tasks|
|
|
116
|
+
lines << " #{status}: #{tasks.size}"
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
ready = @db.ready_tasks
|
|
120
|
+
lines << " ready (unblocked): #{ready.size}" unless ready.empty?
|
|
121
|
+
|
|
122
|
+
lines.join("\n")
|
|
123
|
+
rescue StandardError => e
|
|
124
|
+
$stderr.puts "Warning: TrakFlow summary failed: #{e.message}"
|
|
125
|
+
nil
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# Create a task in TrakFlow.
|
|
129
|
+
#
|
|
130
|
+
# @param title [String] task title
|
|
131
|
+
# @param description [String, nil] task description
|
|
132
|
+
# @param labels [Array<String>] labels to attach
|
|
133
|
+
# @return [String, nil] confirmation message
|
|
134
|
+
def create_task(title, description: nil, labels: [])
|
|
135
|
+
return nil unless available?
|
|
136
|
+
|
|
137
|
+
task = TrakFlow::Models::Task.new(
|
|
138
|
+
title: title,
|
|
139
|
+
description: description,
|
|
140
|
+
type: "task"
|
|
141
|
+
)
|
|
142
|
+
task = @db.create_task(task)
|
|
143
|
+
|
|
144
|
+
labels.each do |label_name|
|
|
145
|
+
@db.add_label(TrakFlow::Models::Label.new(task_id: task.id, name: label_name))
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
"Task created: [#{task.id}] #{title}"
|
|
149
|
+
rescue StandardError => e
|
|
150
|
+
$stderr.puts "Warning: TrakFlow task creation failed: #{e.message}"
|
|
151
|
+
nil
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
attr_reader :db
|
|
155
|
+
|
|
156
|
+
private
|
|
157
|
+
|
|
158
|
+
# Connect to the TrakFlow database if a project is initialized.
|
|
159
|
+
def connect_database
|
|
160
|
+
return nil unless TrakFlow.initialized?
|
|
161
|
+
|
|
162
|
+
db = TrakFlow::Storage::Database.new(TrakFlow.database_path)
|
|
163
|
+
db.connect
|
|
164
|
+
db
|
|
165
|
+
rescue StandardError
|
|
166
|
+
nil
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
# Find a task by its title (partial match).
|
|
170
|
+
def find_task_by_title(title)
|
|
171
|
+
tasks = @db.list_tasks(title: title)
|
|
172
|
+
tasks.first
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
end
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# lib/aia/turn_state.rb
|
|
4
|
+
#
|
|
5
|
+
# Request-scoped state object for inter-component signaling.
|
|
6
|
+
# Replaces ad-hoc instance variable flags on AIA.config.
|
|
7
|
+
#
|
|
8
|
+
# Only one special mode may be requested per turn (mutual exclusion).
|
|
9
|
+
# Use TurnState#request(mode, **opts) to enqueue a mode — this clears
|
|
10
|
+
# all other force_* flags before setting the new one. Assigning the
|
|
11
|
+
# attr_accessors directly bypasses mutual exclusion (for backward compat
|
|
12
|
+
# and direct test assertions).
|
|
13
|
+
|
|
14
|
+
module AIA
|
|
15
|
+
# :reek:TooManyInstanceVariables -- one boolean flag per exclusive mode plus spawn/mcp details; a Hash would lose the attr_accessor API
|
|
16
|
+
class TurnState
|
|
17
|
+
# Exclusive mode flags — only one may be active at a time via #request.
|
|
18
|
+
EXCLUSIVE_MODES = %i[
|
|
19
|
+
verify decompose concurrent_mcp debate delegate spawn orchestrate
|
|
20
|
+
].freeze
|
|
21
|
+
|
|
22
|
+
attr_accessor :force_verify, :force_decompose, :force_concurrent_mcp,
|
|
23
|
+
:force_debate, :force_delegate, :force_spawn, :spawn_type,
|
|
24
|
+
:spawn_spec, :force_orchestrate, :active_mcp_servers
|
|
25
|
+
|
|
26
|
+
def initialize
|
|
27
|
+
clear!
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Request a special mode for this turn.
|
|
31
|
+
# Clears all other exclusive force_* flags before activating the new mode,
|
|
32
|
+
# enforcing mutual exclusion at the point of enqueue.
|
|
33
|
+
#
|
|
34
|
+
# @param mode [Symbol] one of EXCLUSIVE_MODES
|
|
35
|
+
# @param type [String, nil] specialist type (only relevant for :spawn)
|
|
36
|
+
# @raise [ArgumentError] if mode is not one of EXCLUSIVE_MODES
|
|
37
|
+
def request(mode, type: nil)
|
|
38
|
+
unless EXCLUSIVE_MODES.include?(mode)
|
|
39
|
+
raise ArgumentError, "Unknown TurnState mode: #{mode.inspect}. Valid: #{EXCLUSIVE_MODES.join(', ')}"
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
clear_exclusive_flags!
|
|
43
|
+
|
|
44
|
+
case mode
|
|
45
|
+
when :verify then @force_verify = true
|
|
46
|
+
when :decompose then @force_decompose = true
|
|
47
|
+
when :concurrent_mcp then @force_concurrent_mcp = true
|
|
48
|
+
when :debate then @force_debate = true
|
|
49
|
+
when :delegate then @force_delegate = true
|
|
50
|
+
when :spawn then @force_spawn = true
|
|
51
|
+
@spawn_type = type
|
|
52
|
+
when :orchestrate then @force_orchestrate = true
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def clear!
|
|
57
|
+
@force_verify = false
|
|
58
|
+
@force_decompose = false
|
|
59
|
+
@force_concurrent_mcp = false
|
|
60
|
+
@force_debate = false
|
|
61
|
+
@force_delegate = false
|
|
62
|
+
@force_spawn = false
|
|
63
|
+
@spawn_type = nil
|
|
64
|
+
@spawn_spec = nil
|
|
65
|
+
@force_orchestrate = false
|
|
66
|
+
@active_mcp_servers = nil
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Returns which exclusive mode is currently active, or nil if none.
|
|
70
|
+
def active_mode
|
|
71
|
+
return :verify if @force_verify
|
|
72
|
+
return :decompose if @force_decompose
|
|
73
|
+
return :concurrent_mcp if @force_concurrent_mcp
|
|
74
|
+
return :debate if @force_debate
|
|
75
|
+
return :delegate if @force_delegate
|
|
76
|
+
return :spawn if @force_spawn
|
|
77
|
+
return :orchestrate if @force_orchestrate
|
|
78
|
+
nil
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
private
|
|
82
|
+
|
|
83
|
+
def clear_exclusive_flags!
|
|
84
|
+
@force_verify = false
|
|
85
|
+
@force_decompose = false
|
|
86
|
+
@force_concurrent_mcp = false
|
|
87
|
+
@force_debate = false
|
|
88
|
+
@force_delegate = false
|
|
89
|
+
@force_spawn = false
|
|
90
|
+
@spawn_type = nil
|
|
91
|
+
@spawn_spec = nil
|
|
92
|
+
@force_orchestrate = false
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|