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
data/CHANGELOG.md
CHANGED
|
@@ -1,69 +1,283 @@
|
|
|
1
1
|
# Changelog
|
|
2
|
+
|
|
3
|
+
## [Unreleased]
|
|
4
|
+
|
|
5
|
+
This section captures all changes since v1.1.0.
|
|
6
|
+
|
|
7
|
+
## [2.0.0.pre.beta2] 2026-09-09
|
|
8
|
+
|
|
9
|
+
Using robot_lab v0.2.5
|
|
10
|
+
Using lumberjack v2.1.0
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **`--[no-]thinking` flag** (`lib/aia/config/cli_parser.rb`, `lib/aia/config/defaults.yml`, `lib/aia/config.rb`, `lib/aia/streaming_runner.rb`): Controls whether raw reasoning blocks from local models (e.g. `qwen3` on Ollama) are shown. Such models stream their chain-of-thought wrapped in `<think>...</think>` tags; AIA now filters these out by default so only the final answer is displayed. Pass `--thinking` to show the reasoning. The `StreamingRunner` strips the tags inline, tracking open spans across chunk boundaries. Config key: `flags.thinking` (env: `AIA_FLAGS__THINKING`); default `false`.
|
|
15
|
+
|
|
16
|
+
- **Crews — every session is a team of robots** (`lib/aia/crew.rb`, `lib/aia/mention_router.rb`, `lib/aia/directives/execution_directives.rb`): Every chat session is now a crew (a `RobotLab::Network`), even with a single model; the lead robot is the **chief**.
|
|
17
|
+
- **`/add_recruit <name> [provider/model] [system prompt]`** (alias `/add`): Adds a persistent member to the crew that survives the session, shows in `/robots`, and answers to `@name`. Omit the model to inherit the chief's; use `-`/`inherit` to inherit explicitly. Recruits inherit the chief's local tools and connected MCP servers.
|
|
18
|
+
- **`/drop_recruit <name>`** (alias `/drop`): Removes a member; the chief cannot be dropped.
|
|
19
|
+
- **Skill assignment to recruits**: `/add_recruit` accepts `skill:<id>` tokens (comma-separate or repeat for several) that load named skills as the recruit's role/system prompt — letting the chief divide labor across the crew (e.g. a security reviewer + a performance reviewer). Unknown skill ids are reported rather than silently dropped. The chief's `recruit_robot` tool gained a matching `skills` param so it can assign roles itself.
|
|
20
|
+
- **`/reskill <name> [skill:<id>...] [system prompt]`**: Resets a member to a clean slate (fresh conversation) keeping its name and model, and applies a new skill/role. Backed by `Crew.reskill` and a `reskill_robot` chief tool. Useful for recovering an off-task member or moving the crew through phases.
|
|
21
|
+
- **`@crew` broadcast handle**: Sends a prompt to every member concurrently. `crew` is reserved as a member name.
|
|
22
|
+
- **Position-aware `@mention` routing**: A leading address (`@a @b ...`) runs the addressees concurrently; a `@name` woven into the body runs the members sequentially as a pipeline, sharing each reply into the others' context so later members build on earlier ones.
|
|
23
|
+
- **`/spawn` extended** to the explicit form `/spawn <name> <provider/model> <system prompt>` alongside the existing `/spawn` and `/spawn <type>` forms. `/spawn` remains a one-shot specialist for the next prompt; `/add_recruit` is its persistent counterpart.
|
|
24
|
+
- **Docs**: new [Crews guide](docs/guides/crew.md); README `@mention`/crew section and `docs/directives-reference.md` updated for `/add_recruit`, `/drop_recruit`, and the extended `/spawn`.
|
|
25
|
+
|
|
26
|
+
- **`--history-file` fully implemented** (`lib/aia/ui_presenter.rb`): `chat_history_file` now checks `config.output.history_file` first — uses the configured path when set, returns `nil` when `--no-history-file` is given (disabling history). `load_chat_history` and `save_chat_history` both guard against `nil` so disabling history is a clean no-op. Resolution order: `config.output.history_file` → `paths.aia_dir/chat_history` → `~/.config/aia/chat_history`.
|
|
27
|
+
|
|
28
|
+
- **`--speech-model` fully implemented** (`lib/aia/robot_factory.rb`, `lib/aia/chat_loop.rb`, `lib/aia/mention_router.rb`): `configure_audio` stores the value and passes it as the `SPEECH_MODEL` environment variable to the speak subprocess, allowing custom TTS scripts to select a model. `--voice` wires to `say -v VOICE` for the macOS `say` command.
|
|
29
|
+
|
|
30
|
+
- **`--transcription-model` fully implemented** (`lib/aia/robot_factory.rb`): `configure_audio` calls `RubyLLM.configure { |c| c.default_transcription_model = ... }` so the transcription model is active for the entire session.
|
|
31
|
+
|
|
32
|
+
- **`--speak-command CMD`** (`lib/aia/config/cli_parser.rb`, `lib/aia/config.rb`): New CLI option to set `audio.speak_command` at runtime without editing config. Enables full OpenAI TTS pipeline from the command line: `aia --speak --speak-command ~/.config/aia/tts.sh --speech-model tts-1-hd --voice nova my_prompt`.
|
|
33
|
+
|
|
34
|
+
- **Three-stage `--speak` pipeline with per-stage spinners** (`lib/aia/chat_loop.rb`, `lib/aia/mention_router.rb`): After text streams to the terminal, `--speak` now shows distinct progress feedback for each stage — `Converting to audio...` while the TTS command runs, then `Speaking...` while the audio plays. For the local macOS `say` command (which converts and plays in one step) only `Speaking...` is shown. Custom TTS scripts receive the output file path as `$2`; AIA creates the temp file and calls `afplay` itself.
|
|
35
|
+
|
|
36
|
+
- **`~/.config/aia/tts.sh`**: OpenAI TTS helper script installed at the AIA config directory. Accepts text as `$1` and output path as `$2`; reads `SPEECH_MODEL` and `AIA_AUDIO__VOICE` env vars; calls `api.openai.com/v1/audio/speech` via `curl`. Does not call `afplay` — AIA handles playback.
|
|
37
|
+
|
|
38
|
+
- **`--skill` / `-s` fully implemented**: Injects skill content into the AI context; mode-aware — in `--chat` mode skills are appended to the system prompt once (persists across all turns); in pipeline mode skills are appended to each individual prompt text after the role content.
|
|
39
|
+
- **`SkillUtils#skills_base_dir`**: New resolver centralising skills path computation — returns `skills.dir` when `skills_prefix` is unset, or `skills.dir / prefix` when prefix is set; shared by `SystemPromptAssembler` (chat mode) and `PipelineOrchestrator` (pipeline mode).
|
|
40
|
+
- **`SkillUtils#load_skills_content` / `#load_single_skill_content`**: Load and join skill bodies from one or more skill IDs; strip YAML front matter; warn and skip missing skills without aborting.
|
|
41
|
+
|
|
42
|
+
### Changed
|
|
43
|
+
|
|
44
|
+
- **`skills_prefix` default changed from `"skills"` to `nil`**: When unset and no `--skills-dir` is given, the skills directory falls back to `~/.prompts/skills`; setting `--skills-prefix` appends to `--prompts-dir` (or `AIA_PROMPTS__DIR`) rather than to a fixed default.
|
|
45
|
+
- **`--skills-prefix` path resolution** (`lib/aia/config/cli_parser.rb`): Three-branch logic — explicit `--skills-dir` + prefix → `skills_dir/prefix`; no `--skills-dir` but prefix set → `prompts_dir/prefix`; neither given → `AIA_SKILLS__DIR` or `~/.prompts/skills`.
|
|
46
|
+
- **Docs updated for skills options**: `docs/cli-reference.md` — `--skills-prefix` default and resolution, chat-vs-pipeline injection note in `--skill`; `docs/configuration.md` — `skills_prefix` default, prompt assembly order section rewritten; `docs/directives-reference.md` — `/skill` directory resolution description.
|
|
47
|
+
|
|
48
|
+
- **`.loki` asgard task runner**: Added per-project task file with quality gates (`test`, `flog`, `flay`, `rubocop`), each capturing output to `*_output.txt`; `quality` task runs all gates via `system()` and prints a per-gate pass/fail summary table; `aia` passthrough task runs `bin/aia` with arbitrary arguments from any working directory.
|
|
49
|
+
- **`.rubocop.yml`**: Project-level RuboCop configuration achieving 0 offenses — disables intentional-pattern cops (`Style/FormatStringToken`, `Style/SafeNavigationChainLength`, `Lint/DuplicateBranch`), adds test-file exclusions for cops that conflict with minitest patterns, and raises Metrics thresholds to match actual method complexity.
|
|
50
|
+
|
|
51
|
+
- **`LayeredOrchestrator`**: 3-tier agent orchestration — Tobor decomposes requirements, lead agents break them into specialist tasks, specialists produce artifacts. Activated via `/orchestrate`.
|
|
52
|
+
- **`TaskDecomposer` + `TaskExecutor`**: Break complex prompts into parallel subtasks and execute them via TrakFlow.
|
|
53
|
+
- **`OrchestratorError`, `DebateError`, `DecomposeError`**: Typed error classes for orchestration and debate failure paths (`lib/aia/errors.rb`).
|
|
54
|
+
- **`tool_filter.timeout_s` config key**: Configurable TF-IDF filter timeout; defaults to 10 seconds.
|
|
55
|
+
- **Parallel LLM calls**: Multi-model network turns now run concurrently via `Async::Barrier`.
|
|
56
|
+
- **Session cleanup**: `at_exit` hook in `AIA.run` calls `Session#cleanup!` to release MCP connections, flush caches, and close TrakFlow.
|
|
57
|
+
- **`state_setting!` DSL**: Directive subclasses declare their exclusive mode with `state_setting! :debate, :spawn, ...`; `ChatLoop` no longer maintains a hardcoded prefix list.
|
|
58
|
+
- **Demo 29**: End-to-end agent harness demo building a Sinatra/Sequel application from a requirements document.
|
|
59
|
+
- **`BATCH_MODE` support**: Demos 23–28 skip live `--chat` sessions when `BATCH_MODE=true`, enabling `run_all.sh` CI automation.
|
|
60
|
+
|
|
61
|
+
### Changed
|
|
62
|
+
|
|
63
|
+
- **TF-IDF as sole tool filter strategy**: Zvec (B), SqliteVec (C), and LSI (D) strategies removed (~2,150 LOC deleted).
|
|
64
|
+
- **`auto_tool_filter` flag**: Replaces `tool_filter_a`; enabled by default; toggled via `--[no-]auto-tool-filter`.
|
|
65
|
+
- **`robot_lab` dependency**: Updated from `~> 0.0.9` to `~> 0.1.0`.
|
|
66
|
+
- **Lazy handler instantiation**: `SpawnHandler`, `DebateHandler`, `DelegateHandler`, and `LayeredOrchestrator` are memoized and created on first use.
|
|
67
|
+
- **Lazy-require for heavy subsystems**: `VerificationNetwork`, `PromptDecomposer`, and all TrakFlow infrastructure required only when invoked.
|
|
68
|
+
- **`shared_tools` optional runtime dependencies**: `dentaku`, `sequel`, and `openweathermap` moved to dev dependencies; each tool guards its `require` with a boolean constant and exposes `available?`; `bigdecimal >= 4.0` pinned conditionally for Ruby >= 4.0.
|
|
69
|
+
- **`README.md`**: Added badges, "Why AIA?" feature comparison table, and Prompt Directives reorganized into seven category subsections.
|
|
70
|
+
|
|
71
|
+
### Removed
|
|
72
|
+
|
|
73
|
+
- **Zvec, SqliteVec, LSI tool filter strategies** and their test files.
|
|
74
|
+
- **`zvec`, `sqlite-vec`, `informers` gem dependencies** from gemspec.
|
|
75
|
+
- **KBS gem and rule engine**: `kbs` gem and all KBS infrastructure (RuleRouter, KBDefinitions, FactAsserter, DynamicRuleBuilder, RulesDSL, DecisionApplier, ExpertRouter) deleted.
|
|
76
|
+
- **`-A`/`--tool-filter-kbs` CLI flag**, `/rules` chat directive, and user-defined rule hooks.
|
|
77
|
+
- **`build_streaming_callback`**: Dead code path in `RobotFactory`.
|
|
78
|
+
|
|
79
|
+
### Fixed
|
|
80
|
+
|
|
81
|
+
- **`--no-mcp` flag ignored by `RobotBuilder`** (`lib/aia/robot_builder.rb`): Was directly mapping `config.mcp_servers` without checking `config.flags.no_mcp`; now delegates to `RobotFactory.mcp_server_configs(config)` which honours the flag — preventing MCP servers from connecting and tools from overflowing the model's 128-tool limit.
|
|
82
|
+
- **`load_extra_config` falls through on missing file in tests** (`lib/aia/config.rb`): Restored `return` after `exit 1`; tests mock `exit` as a no-op, so without the guard the method continued to `YAML.safe_load_file` on the nonexistent path and raised `Errno::ENOENT`.
|
|
83
|
+
- **`warn` → `$stderr.puts` across all lib files** (19 files): Ruby 4.0 suppresses `Kernel#warn` output by default (requires `-W` flag); messages were silently dropped — including unknown-option errors, missing-file warnings, and audio failures. Replaced all `warn` calls with `$stderr.puts` which always writes unconditionally. Test suite updated: replaced `stubs(:warn)` + `stderr_messages` patterns with `capture_io` to capture real `$stderr` output.
|
|
84
|
+
- **`--speak` produced `AudioFileOpen failed` error** (`lib/aia/config/defaults.yml`, `~/.config/aia/aia.yml`): Default `speak_command` was `afplay` (an audio file player) instead of `say` (macOS TTS); passing response text to `afplay` caused it to interpret the text as a file path and fail. Default changed to `say`; `voice` and `speech_model` defaults cleared to `nil` so `say` uses the system default voice with no API call.
|
|
85
|
+
|
|
86
|
+
- **`DebateHandler` convergence short-circuit** (`lib/aia/debate_handler.rb`): Added `all_signaled_convergence?` fast path — when all robots say `CONVERGED` after minimum rounds the debate ends immediately, without waiting for similarity scoring to catch up.
|
|
87
|
+
- **`SpecialModeHandler` keyword argument crash** (`lib/aia/special_mode_handler.rb`): `network.run(prompt)` → `network.run(message: prompt)` to match `RobotLab::Network#run`'s keyword-only API.
|
|
88
|
+
- **`ToolLoader` gem loading under Bundler** (`lib/aia/tool_loader.rb`): `Gem::LoadError` (`ScriptError`, not `StandardError`) now caught; added `eager_load_namespace_fallback` for Zeitwerk recovery; `activate_unbundled_gem` falls back to `Gem.default_dir`/`Gem.user_dir` scanning when Bundler blocks `gem name`.
|
|
89
|
+
- **Demo 18 tool overload** (`examples/18_tools.sh`): Added `--allowed-tools` to expose only 3 tools; 35+ tools caused `gpt-4.1` to narrate instead of invoke.
|
|
90
|
+
- **Demo 26/27 robot name** (`examples/26_debate.sh`, `examples/27_mention_routing.sh`): `RobotNamer` assigns "Vanguard" to `gpt-4.1-mini`, not "Quark"; corrected in both scripts.
|
|
91
|
+
- **Ollama model tag resolution** (`lib/aia/verification_network.rb`, `lib/aia/prompt_decomposer.rb`): Pass `model.internal_id` (e.g. `ollama/qwen3:latest`) to `RobotLab.build` instead of `model.name`.
|
|
92
|
+
- **Dynamic pipeline iteration** (`lib/aia/pipeline_orchestrator.rb`): Changed `config.pipeline.each` to `until config.pipeline.empty?` + `shift` so mid-run `next:`/`pipeline:` replacements are picked up immediately.
|
|
93
|
+
- **AI response written to output file twice** (`lib/aia/ui_presenter.rb`): Removed file-writing from `display_ai_response`; file output exclusively owned by `output_to_file`.
|
|
94
|
+
- **Unknown `@mention` falls through to broadcast** (`lib/aia/mention_router.rb`): Returns `true` and reports unrecognized names instead of silently broadcasting to all robots.
|
|
95
|
+
- **Custom directive classes unavailable in ERB prompts** (`lib/aia/tool_loader.rb`): `PM::Directive.register_all` now called at the end of `ToolLoader#load_tools` so tool-provided directives are registered before the first prompt render.
|
|
96
|
+
- **Demo scripts using untagged Ollama model names**: Updated to `phi4:latest` and `phi4-mini:latest`.
|
|
97
|
+
- **`/ruby` directive security gate**: `eval` now guarded by `AIA.config.flags.allow_ruby_eval`.
|
|
98
|
+
- **`RobotFactory` namer state leak**: `@namer` initialized once in `RobotFactory.setup` instead of reset on every robot build.
|
|
99
|
+
- **`at_exit` hook registered multiple times**: Moved from `Session#start` to `AIA.run`, registered exactly once per process.
|
|
100
|
+
- **GPT-5/OpenAI token parameter mismatch**: Models with `temperature: false` skip temperature; `max_tokens` translated to `max_completion_tokens` for o-series models.
|
|
101
|
+
- **Installed gem BigDecimal activation conflict** (`lib/aia.rb`): AIA activates `bigdecimal >= 4.0` before loading transitive dependencies.
|
|
102
|
+
- **Pipeline token metrics crash**: `display_metrics` uses `result.raw` instead of non-existent `result.output`.
|
|
103
|
+
- **Skill symlink path containment**: Skill resolution checks real paths against the skills directory boundary.
|
|
104
|
+
- **`--list-skills` CLI directory options**: Now honors `--prompts-dir` and `--skills-prefix` regardless of option order.
|
|
105
|
+
|
|
106
|
+
### Known Issues
|
|
107
|
+
|
|
108
|
+
- **`--skill` injection in RobotLab flow**: The RobotLab prompt execution path does not yet prepend configured skills to pipeline prompts and chat startup context.
|
|
109
|
+
- **Path-based direct skill file restrictions**: `/skill` accepts any readable file path; should be limited to markdown files to prevent arbitrary injection.
|
|
110
|
+
|
|
2
111
|
## [1.1.1] - 2026-05-01
|
|
3
112
|
|
|
4
113
|
### Bug Fixes
|
|
5
|
-
|
|
6
|
-
- **
|
|
7
|
-
- **
|
|
8
|
-
- **
|
|
114
|
+
|
|
115
|
+
- **Ollama model pipeline context preservation**: Mainline fixed adapter replacement when provider-prefixed model names (for example `ollama/qwen3`) did not match resolved local model IDs, preserving conversation history across pipeline steps.
|
|
116
|
+
- **Role front matter model isolation**: Mainline restored the active model after role loading so a role file's `model:` metadata cannot unexpectedly replace the configured model.
|
|
117
|
+
- **Custom directive loading for ERB prompts**: Mainline loads tool files before PromptManager directive registration so directive classes provided by `--tools` are available inside ERB prompts.
|
|
118
|
+
- **Demo example path resolution** (`examples/prompts_dir/project_summary`): Corrected repository-relative paths used by the example prompt.
|
|
9
119
|
|
|
10
120
|
### Improvements
|
|
11
|
-
- **Demo scripts use develop-branch binary**: `examples/common.sh` now prepends `../bin` to `PATH` when the local `bin/aia` is executable, ensuring all demo scripts exercise working-tree changes rather than the installed gem
|
|
12
121
|
|
|
13
|
-
|
|
14
|
-
- Added `test/aia/chat_loop_test.rb` — 6 tests covering `process_role_context`: early-return when no role configured, system message injection into chats, skipping chats that already have a system message, and model restoration after `fetch_role` side effects (Issue #152 regression tests)
|
|
15
|
-
- Expanded `test/aia/chat_processor_service_test.rb` with 7 additional tests: provider-prefix stripping before model comparison, full-ID alias resolution (e.g. `claude-sonnet-4` vs `claude-sonnet-4-20250514`), adapter preservation when any chat has history, adapter replacement allowed when no history exists, and the exact Issue #152 regression scenario (OpenAI model active, role front matter specifies a Claude model)
|
|
122
|
+
- **Demo scripts prefer working-tree binary** (`examples/common.sh`): Mainline demo scripts prepend `../bin` to `PATH` when local `bin/aia` is executable.
|
|
16
123
|
|
|
17
124
|
## [1.1.0] - 2026-04-23
|
|
18
125
|
|
|
19
126
|
### New Features
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
- `--skill`/`-s SKILL_IDS` CLI option prepends one or more skills to the prompt (comma-separated, repeatable); accepts skill IDs or paths
|
|
26
|
-
- `--skills-dir DIR` and `--skills-prefix PREFIX` CLI options configure the skills directory
|
|
27
|
-
- **Path-based skill resolution**: `--skill` and `/skill` now accept file-system paths in addition to named IDs
|
|
28
|
-
- Absolute paths: `--skill /path/to/skill-dir` or `--skill /path/to/skill.md`
|
|
29
|
-
- Home-relative: `--skill ~/skills/my-skill`
|
|
30
|
-
- Working-directory-relative: `--skill ./temp_skill.md`
|
|
31
|
-
- Direct `.md` files: the file content is used as-is (front matter stripped); no `SKILL.md` lookup needed
|
|
32
|
-
- **Path-based role resolution**: `--role` now accepts file-system paths in addition to role IDs
|
|
33
|
-
- Absolute and home-relative paths bypass the `~/.prompts/roles/` prefix lookup
|
|
34
|
-
- Example: `aia --role ~/custom/expert.md my_prompt`
|
|
35
|
-
- **Skills in chat-only mode**: `ChatLoop` now loads and sends configured skills to the AI at session start via `process_skill_context`, even when no pipeline prompt is specified; the AI's acknowledgment is displayed so the user can confirm the skill was applied
|
|
36
|
-
- **`AIA::SkillUtils` module**: New shared utility module (`lib/aia/skill_utils.rb`) consolidating path and skill helpers previously duplicated across four classes
|
|
37
|
-
- `path_based_id?(id)` — detects `/`, `~/`, `./`, `../` prefixes
|
|
38
|
-
- `parse_front_matter(path)` — reads and parses YAML front matter from a `.md` file; returns `{}` on any failure
|
|
39
|
-
- `find_skill_dir(skill_name, base_dir)` — resolves a skill name or path to its directory (or direct `.md` file); enforces symlink/prefix-traversal checks for ID-based lookups
|
|
40
|
-
- `safe_skill_path(path, dir)` — verifies a resolved path is contained within `dir` using `File::SEPARATOR`-terminated prefix to prevent sibling-directory attacks
|
|
41
|
-
- `skill_body(content)` — strips YAML front matter from skill file content
|
|
42
|
-
- Included by `PromptPipeline`, `PromptHandler`, `WebAndFileDirectives`, `CLIParser`, `ConfigValidator`, and `ChatLoop`
|
|
43
|
-
- **`roles` config section**: Top-level `roles.dir` config key (`~/.prompts/roles` default) alongside existing `prompts.roles_prefix`
|
|
44
|
-
- **`parse_search_terms` helper**: New private method on `AIA::Directive` base class available to all directive subclasses; splits argument tokens into `[positive_terms, negative_terms]` arrays (negative prefixes: `-`, `~`, `!`; positive: `+` or bare; all downcased)
|
|
127
|
+
|
|
128
|
+
- **Skills system** (`lib/aia/skill_utils.rb`, `lib/aia/directives/web_and_file_directives.rb`): Mainline added `SKILL.md`-based skills, `/skill`, `/skills`, `--skill`, `--list-skills`, `--skills-dir`, `--skills-prefix`, path-based skill IDs, and shared `AIA::SkillUtils` helpers.
|
|
129
|
+
- **Path-based role resolution** (`lib/aia/prompt_handler.rb`, `lib/aia/config/cli_parser.rb`, `lib/aia/config/validator.rb`): `--role` and role loading now accept file-system paths in addition to configured role IDs.
|
|
130
|
+
- **Top-level `roles` and `skills` config sections** (`lib/aia/config/defaults.yml`): Added dedicated directory configuration while preserving prompt prefix settings.
|
|
131
|
+
- **Shared search-term parsing** (`lib/aia/directive.rb`): Directive filtering now uses common positive and negative term parsing.
|
|
45
132
|
|
|
46
133
|
### Bug Fixes
|
|
47
|
-
|
|
48
|
-
- **
|
|
49
|
-
- **
|
|
134
|
+
|
|
135
|
+
- **Direct skill file resolution**: Skill loading now accepts direct `.md` file paths as well as skill directories.
|
|
136
|
+
- **Skill path-prefix containment**: Mainline added realpath boundary checks to block sibling-directory prefix attacks.
|
|
137
|
+
- **Path-based role prefixing**: Config tailoring no longer prepends the roles prefix to path-based role IDs.
|
|
50
138
|
|
|
51
139
|
### Improvements
|
|
52
|
-
- **`/available_models` filtering** now uses `parse_search_terms` for consistent positive/negative term filtering across local (Ollama, LM Studio) and cloud model listings
|
|
53
|
-
- **Standardized warning output**: Replaced `$stderr.puts` with `warn` throughout `prompt_pipeline.rb` for idiomatic Ruby error reporting
|
|
54
|
-
- **Skills CLI options moved to Prompt Options group**: `--skill`, `--skills-dir`, `--skills-prefix`, `--list-skills` now appear under `--help`'s Prompt Options section alongside `--role` and related options, rather than Model Options
|
|
55
140
|
|
|
56
|
-
|
|
57
|
-
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
-
|
|
64
|
-
-
|
|
65
|
-
-
|
|
66
|
-
-
|
|
141
|
+
- **Model and skill filtering consistency**: `/llms` and `/skills` use the shared positive/negative search term behavior.
|
|
142
|
+
- **Skills CLI option placement**: Skill-related CLI flags now appear under Prompt Options.
|
|
143
|
+
|
|
144
|
+
## [2.0.9.alpha] - 2026-03-28
|
|
145
|
+
|
|
146
|
+
### Improvements (Section 9 — Design Correctness)
|
|
147
|
+
|
|
148
|
+
- **`MCPConfigNormalizer.filter_servers` eliminated** (`lib/aia/mcp_config_normalizer.rb`, `lib/aia/robot_builder.rb`, `lib/aia/robot_factory.rb`): `filter_servers` duplicated use/skip filtering logic that `MCPDiscovery` already owns, and used a different activation source (`TurnState.active_mcp_servers` vs. `Decisions.mcp_activations`), creating a split-brain risk. Removed `filter_servers` entirely. `RobotBuilder` now passes all configured servers normalized (`Array(config.mcp_servers).map { |s| MCPConfigNormalizer.normalize(s) }`). `RobotFactory.mcp_server_configs` (used by network builders) follows the same pattern. MCPDiscovery is now the single authoritative filter.
|
|
149
|
+
- **`Utility` converted from class to module** (`lib/aia/utility.rb`): `class Utility` with only `class << self` methods is a Ruby anti-pattern. Changed to `module Utility` — semantically identical for callers (`AIA::Utility.mcp_servers?` etc.) but idiomatically correct. Nothing can be accidentally instantiated.
|
|
150
|
+
- **Banner methods returned to `Utility`** (`lib/aia/utility.rb`, `lib/aia/mcp_utility.rb`, `lib/aia/tool_utility.rb`): `banner_mcp`, `mcp_client_labels`, and `banner_tools` were mixed into `MCPUtility`/`ToolUtility` — display concerns in data-query modules. Moved all banner private methods back into `Utility`. `MCPUtility` and `ToolUtility` are now pure query interfaces with no formatting logic.
|
|
151
|
+
- **`MCPDiscovery` takes `decisions` directly** (`lib/aia/mcp_discovery.rb`, `startup_coordinator.rb`, `pipeline_orchestrator.rb`, `special_mode_handler.rb`): `MCPDiscovery` only ever used `rule_router.decisions` — passing the whole `rule_router` was over-coupling. Constructor changed to `MCPDiscovery.new(decisions)`; all three callers updated to pass `@rule_router.decisions`. Dependency is now explicit and narrow.
|
|
152
|
+
- **`history_manager.rb` shim deleted** (`lib/aia/session.rb`): The backward-compat shim (`require_relative 'variable_input_collector'`) had served its purpose. `session.rb` updated to require `variable_input_collector` directly. The Ruby-level `HistoryManager = VariableInputCollector` alias in `variable_input_collector.rb` remains for callers that reference the old constant name.
|
|
153
|
+
|
|
154
|
+
## [2.0.8.alpha] - 2026-03-28
|
|
155
|
+
|
|
156
|
+
### Improvements (Section 8 — Backlog Cleanup)
|
|
157
|
+
|
|
158
|
+
- **Consolidate `server_name` inline patterns** (`fact_asserter.rb`, `config/validator.rb`, `mcp_discovery.rb`): Replaced 5 occurrences of `server[:name] || server['name']` with `Utility.server_name(server)` (or `AIA::Utility.server_name(server)`). `Utility.server_name` already handled Hash symbol/string keys, object `.name` methods, and `to_s` fallback — the inline pattern was a redundant re-implementation. (P3-28 / 8.1)
|
|
159
|
+
- **`MCPUtility` and `ToolUtility` extracted from `Utility`** (`lib/aia/mcp_utility.rb`, `lib/aia/tool_utility.rb`, `lib/aia/utility.rb`): `Utility` was a grab-bag class mixing MCP server query methods, tool query methods, and display/banner concerns. Extracted `MCPUtility` (6 public methods: `mcp_servers?`, `mcp_server_names`, `connected_mcp_servers?`, `failed_mcp_servers`, `effective_mcp_server_names`, `server_name`; 2 private: `mcp_client_labels`, `banner_mcp`) and `ToolUtility` (4 public methods: `tools?`, `total_tool_count`, `user_tools?`, `supports_tools?`; 1 private: `banner_tools`). Both modules are included into `Utility` via `class << self include`. `utility.rb` now holds only display, banner, and model-refresh concerns. (P3-30 / 8.2)
|
|
160
|
+
- **Pin `robot_lab` and `kbs` version constraints** (`aia.gemspec`): Simplified redundant double-constraint notation (`'~> 0.0', '>= 0.0.9'`) to single pessimistic constraints: `robot_lab '~> 0.0.9'` and `kbs '~> 0.2.1'`. Semantically equivalent but cleaner. (P3-32 / 8.3)
|
|
161
|
+
- **Rename `HistoryManager` → `VariableInputCollector`** (`lib/aia/variable_input_collector.rb`, `lib/aia/history_manager.rb`, `lib/aia/input_collector.rb`): `HistoryManager` was misnamed — it only prompts for prompt variable values. New canonical name is `VariableInputCollector`. `history_manager.rb` is now a one-line shim requiring the new file. `HistoryManager = VariableInputCollector` alias preserved for backward compatibility. `lib/aia.rb` updated to require `variable_input_collector`. New test file `test/aia/variable_input_collector_test.rb` mirrors the original tests plus an alias assertion. (P3-33 / 8.4)
|
|
162
|
+
|
|
163
|
+
## [2.0.7.alpha] - 2026-03-28
|
|
164
|
+
|
|
165
|
+
### Improvements (Section 7 — MCPDiscovery Decision)
|
|
166
|
+
|
|
167
|
+
- **`MCPDiscovery` wired into `StartupCoordinator`** (`lib/aia/startup_coordinator.rb`): The startup MCP connection path now routes through `MCPDiscovery#discover` instead of the indirect `MCPConfigNormalizer.filter_servers → TurnState` bridge. `MCPDiscovery` is the canonical authority for which servers are activated at startup — reading `--mcp-use`, `--mcp-skip`, and KBS `mcp_activate` decisions directly. Each discovered server is then normalized by `MCPConfigNormalizer.normalize` before being passed to `MCPConnectionManager`. (P2-20 / 7.1)
|
|
168
|
+
- **`MCPDiscovery` bug fix** (`lib/aia/mcp_discovery.rb`): `config.mcp_use` truthiness check changed from `if config.mcp_use` to `if Array(config.mcp_use).any?`. In Ruby, `[]` is truthy, so an empty `mcp_use` list previously triggered explicit-server filtering and returned zero servers. An empty list now correctly falls through to KBS-activation or all-servers fallback. (7.1)
|
|
169
|
+
- **`MCPDiscovery` now respects `--mcp-skip`** (`lib/aia/mcp_discovery.rb`): Added `apply_skip_filter` that removes servers whose names appear in `config.mcp_skip` after the primary selection (explicit, KBS-activated, or all). Skip is applied regardless of which selection path was taken. (7.1)
|
|
170
|
+
- **Refactored `MCPDiscovery` internals** (`lib/aia/mcp_discovery.rb`): Extracted `select_servers` (selection strategy dispatcher), `apply_skip_filter` (post-selection skip), and `select_by_names` (name-list filter) private helpers. The public `discover` interface is unchanged. (7.1)
|
|
171
|
+
|
|
172
|
+
## [2.0.6.alpha] - 2026-03-28
|
|
173
|
+
|
|
174
|
+
### Improvements (Section 6 — Structural Decompositions)
|
|
175
|
+
|
|
176
|
+
- **`ConfigValidator` early-exit refactor** (`lib/aia/config/validator.rb`): Replaced all `raise AIA::EarlyExit` calls with `return :early_exit`. `tailor()` propagates the signal via `return :early_exit if <step>(config) == :early_exit`. Removed the `EarlyExit` exception class from `lib/aia/errors.rb` and the `rescue AIA::EarlyExit` clause from `lib/aia.rb`. The exception-as-goto anti-pattern is gone. (P2-18 / 6.1)
|
|
177
|
+
- **`ExpertRouter` integration** (`lib/aia/expert_router.rb`): `ExpertRouter` is now instantiated in `ChatLoop` and called as part of the turn pipeline. Verified via `test_expert_router_is_integrated_into_chat_loop`. (P2-19 / 6.2)
|
|
178
|
+
- **`TaskDecomposer` + `TaskExecutor`** (`lib/aia/task_decomposer.rb`, `lib/aia/task_executor.rb`): Extracted from `DelegateHandler`. `TaskDecomposer#decompose` calls the lead robot with a JSON decomposition prompt and returns `[{title:, assignee:}]`. `TaskExecutor#execute` claims, runs, and completes a single TrakFlow step. `DelegateHandler` is now a thin coordinator. (P2-23 / 6.3)
|
|
179
|
+
- **`StartupCoordinator`** (`lib/aia/startup_coordinator.rb`): New class extracting all session startup concerns from `Session`: MCP server connection, tool collection, filter registry initialization, TrakFlow bootstrap, and bus attachment. `StartupCoordinator.new(robot:, rule_router:, ui_presenter:).run(config)` runs all startup tasks and exposes `filters` and `mcp_manager` attributes. (P2-16 / 6.4)
|
|
180
|
+
- **`PipelineOrchestrator`** (`lib/aia/pipeline_orchestrator.rb`): New class extracting per-prompt pipeline processing from `Session`: prompt building (role, stdin, context files), concurrent MCP detection, robot dispatch, result display, metrics, and TrakFlow step tracking. `PipelineOrchestrator.new(...).process(config)` replaces `Session#process_pipeline` and all its private helpers. (P2-16 / 6.4)
|
|
181
|
+
- **`Session` thinned** (`lib/aia/session.rb`): `Session#start` now delegates to `StartupCoordinator#run` and `PipelineOrchestrator#process`. The 12 extracted private methods (`connect_mcp_servers`, `process_pipeline`, `execute_prompt`, `maybe_use_concurrent_mcp`, `build_prompt_text`, `add_context_files`, `display_metrics`, etc.) have been removed. Session is a thin shell sequencing startup → pipeline → chat. (P2-16 / 6.4)
|
|
182
|
+
- **`MCPConfigNormalizer`** (`lib/aia/mcp_config_normalizer.rb`): New class extracting MCP server filtering and normalization from `RobotFactory`. `MCPConfigNormalizer.filter_servers(config)` applies use/skip/KBS lists and returns normalized configs. `MCPConfigNormalizer.normalize(server)` converts flat format to robot_lab's nested transport format. `RobotFactory#mcp_server_configs` and `#normalize_mcp_config` now delegate to it. (P2-17 / 6.5)
|
|
183
|
+
- **`NetworkMemoryManager`** (`lib/aia/network_memory_manager.rb`): New class extracting network shared-memory setup from `RobotFactory`. `NetworkMemoryManager.initialize_memory(network, config)` seeds session metadata. `NetworkMemoryManager.setup_subscriptions(network, config)` wires debug-logging and completion-count subscriptions. `RobotFactory#initialize_network_memory` and `#setup_memory_subscriptions` now delegate to it. (P2-17 / 6.5)
|
|
184
|
+
- **`RobotBuilder`** (`lib/aia/robot_builder.rb`): New class extracting single-robot construction from `RobotFactory`. `RobotBuilder.build(config, namer:)` assembles the system prompt, resolves MCP configs via `MCPConfigNormalizer`, and calls `RobotLab.build`. `RobotFactory#build_single_robot` now delegates to it. (P2-17 / 6.5)
|
|
185
|
+
|
|
186
|
+
## [2.0.5.alpha] - 2026-03-27
|
|
187
|
+
|
|
188
|
+
### Improvements (Section 5 — State Machine & Lifecycle)
|
|
189
|
+
|
|
190
|
+
- **`TurnState#request(mode)` mutual exclusion** (`lib/aia/turn_state.rb`): Added `EXCLUSIVE_MODES` constant and `request(mode, type: nil)` method. Calling `request` clears all other exclusive `force_*` flags before setting the new one, enforcing that only one special mode is active at a time. Added `active_mode` helper returning the currently active mode symbol. Direct `attr_accessor` assignment still works for backward compatibility and test assertions. (P1-13)
|
|
191
|
+
- **`SpawnHandler` lifecycle** (`lib/aia/spawn_handler.rb`): Added `MAX_CACHE_SIZE = 5` constant. When a new specialist is spawned and the cache is full, the oldest entry is evicted (insertion-order LRU via Ruby Hash). Added `cleanup!` method that clears all cached specialists — called on session end to release resources. (P2-22)
|
|
192
|
+
- **`DebateHandler` convergence** (`lib/aia/debate_handler.rb`): Replaced the fragile `"CONVERGED"` string check with semantic similarity scoring using `SimilarityScorer`. Added `MIN_ROUNDS = 2` and `SIMILARITY_THRESHOLD = 0.85`. Convergence is only evaluated after `MIN_ROUNDS` rounds; it triggers when the combined response text from consecutive rounds scores ≥ threshold. One robot mentioning "CONVERGED" incidentally no longer ends the debate prematurely. (P2-21)
|
|
193
|
+
- **`MentionRouter` mention stripping** (`lib/aia/mention_router.rb`): After matching `@mention` tokens to robots, all mention tokens are stripped from the prompt (`gsub(/@\w+\s*/i, '').strip`) before routing to the target robot. The robot now receives only the query, not the routing prefix. (P3-26)
|
|
194
|
+
- **`ModelSwitchHandler#model_exists?` caching** (`lib/aia/model_switch_handler.rb`): Added `@model_exists_cache` instance hash. Each model name is looked up via `RubyLLM.models.find(name)` at most once per handler instance; subsequent calls for the same name return the cached boolean without hitting the provider. (P3-27)
|
|
195
|
+
|
|
196
|
+
## [2.0.4.alpha] - 2026-03-27
|
|
197
|
+
|
|
198
|
+
### Improvements (Section 4 — Tool Infrastructure)
|
|
199
|
+
|
|
200
|
+
- **`ToolLoader` converted to class** (`lib/aia/tool_loader.rb`): `module_function` with a module-level `@tool_cache` was replaced by a class with per-instance `@tool_cache`. Class-level convenience methods delegate to a resettable default instance via `ToolLoader.instance`. `ToolLoader.reset_instance!` (and `AIA.reset!`) discard the singleton for clean test isolation. Two `ToolLoader.new` instances now have independent caches. (P1-12)
|
|
201
|
+
- **`ToolFilterRegistry`** (`lib/aia/tool_filter_registry.rb`): New class with `build_from_config(config, tools, rule_router:)`. Extracts the five identical `if/prep/assign` blocks from `Session#start` into a single, independently testable method. Session now calls one line. (P1-7)
|
|
202
|
+
- **`EmbeddingModelLoader` mixin** (`lib/aia/tool_filter/embedding_model_loader.rb`): New module with `load_embedding_model(label, model_name)`. Included by both `ToolFilter::Zvec` and `ToolFilter::SqliteVec`, removing two identical 3-line embedding-load sequences. (P3-25)
|
|
203
|
+
- **`ToolFilter::SqliteVec` rowid mapping** (`lib/aia/tool_filter/sqlite_vec.rb`): Replaced fragile `@tool_entries[rowid - 1]` positional lookup with `@tool_index` hash (`rowid → entry`). Both `create_database` and `load_persisted` populate the index; `do_filter_with_scores` uses `@tool_index[rowid]`. Lookup is now stable across deletions and reinsertions. (P3-31)
|
|
204
|
+
- **`ToolFilter::TFIDF` vectorizer caching** (`lib/aia/tool_filter/tfidf.rb`): `Classifier::TFIDF.new`, `fit`, and full-corpus `transform` were called on every user turn. Now the vectorizer is fitted and all tool vectors are computed once in `do_prep` and cached as `@tfidf` / `@tool_vectors`. Per-turn cost is reduced to a single `@tfidf.transform(prompt)` call. (P3-24)
|
|
205
|
+
|
|
206
|
+
## [2.0.3.alpha] - 2026-03-27
|
|
207
|
+
|
|
208
|
+
### Improvements (Section 3 — Handler Cleanup)
|
|
209
|
+
|
|
210
|
+
- **`ContentExtractor#extract_content`**: Replaced three identical `extract_reply` private methods in `SpawnHandler`, `DebateHandler`, and `DelegateHandler` with a single call to the shared `ContentExtractor#extract_content`. (P1-9)
|
|
211
|
+
- **`HandlerProtocol` module** (`lib/aia/handler_protocol.rb`): New module defining the `handle(context)` interface. All five turn-level handlers now `include HandlerProtocol` and raise `NotImplementedError` from the base if `handle` is not overridden.
|
|
212
|
+
- **`HandlerContext` struct** (`lib/aia/handler_context.rb`): New value object carrying `robot`, `prompt`, `decisions`, `config`, and `specialist_type` — replaces five incompatible handler signatures with a single unified protocol. All five handlers (`SpawnHandler`, `DebateHandler`, `DelegateHandler`, `MentionRouter`, `ModelSwitchHandler`) migrated to `handle(context)`. All call sites in `SpecialModeHandler` and `ChatLoop` updated. (P1-8)
|
|
213
|
+
- **`Fzf`**: Removed dead code — `tempfile_path` method, `unlink_tempfile` method, and the `ensure` block that called `unlink_tempfile`. `fzf` now passes list items via `stdin_data:` only; no tempfile is created. (P3-29)
|
|
214
|
+
- **Section 3.4** was completed as part of Section 2.5 (`UIPresenter#calculate_cost` already delegates to `CostCalculator`).
|
|
215
|
+
|
|
216
|
+
## [2.0.2.alpha] - 2026-03-27
|
|
217
|
+
|
|
218
|
+
### Improvements (Section 2 — Correctness Completions)
|
|
219
|
+
|
|
220
|
+
- **`DecisionApplier`**: When `build_temp_robot` returns nil, now emits a `warn` and explicitly sets `context.model_overridden = false` before returning. Previously the turn fell through silently with no indication the model switch failed. (C4)
|
|
221
|
+
- **`FactAsserter`**: Changed `config.models.each` → `Array(config.models).each` to prevent `NoMethodError` when `config.models` is nil during early KBS evaluation. (P1-10)
|
|
222
|
+
- **`RuleRouter`**: Changed silent `next unless kb` to emit a structured warning (`[RuleRouter] Warning: knowledge base '#{name}' not found in pipeline — skipping`) when a KB from `KB_ORDER` is absent. Missing KBs no longer cause silent rule failures. (C5)
|
|
223
|
+
- **`TrakFlowBridge`**: `attr_reader :db` moved from `private` to public. The database accessor is now part of the public API.
|
|
224
|
+
- **`TaskCoordinator`**: Replaced `bridge.send(:db)` with `bridge.db`, removing the private-access workaround.
|
|
225
|
+
- **New `AIA::CostCalculator` module** (`lib/aia/cost_calculator.rb`): Extracts the duplicated cost calculation logic that previously lived in `SessionTracker` and `UIPresenter`. Single entry point: `AIA::CostCalculator.calculate(model_id:, input_tokens:, output_tokens:)` → `{ available:, total_cost:, input_cost:, output_cost: }`. (P1-15)
|
|
226
|
+
- **`SessionTracker`**: `compute_cost_for_model` and `compute_cost` now delegate to `CostCalculator`.
|
|
227
|
+
- **`UIPresenter`**: `calculate_cost` now delegates to `CostCalculator`.
|
|
228
|
+
|
|
229
|
+
## [2.0.1.alpha] - 2026-03-27
|
|
230
|
+
|
|
231
|
+
### Improvements (Section 1 — Safety Net)
|
|
232
|
+
|
|
233
|
+
- **`MCPConnectionManager`**: All reads of `@connected_clients`, `@connected_tools`, and `@connected_servers` are now wrapped in `@mutex.synchronize`. Eliminates data races between `connect_one` threads and callers of `inject_into`, `update_config`, `any_tools?`, `connected_server_names`, and `failed_server_names`. (C1)
|
|
234
|
+
- **`AIA.reset!`**: New class method that nils all seven mutable singletons (`@config`, `@client`, `@session_tracker`, `@turn_state`, `@task_coordinator`, `@decisions`, `@rule_router`) for clean test isolation. (C2)
|
|
235
|
+
- **`Decisions#add(:model_decision)`**: Now raises `ArgumentError` when `:model` is nil, preventing silent propagation of invalid model decisions downstream. (C3)
|
|
236
|
+
- **`HistoryManager`**: All three `exit(1)` calls replaced with `raise AIA::Error`. Callers can now rescue or propagate the error; `AIA.run` catches it and exits with a message. (C7)
|
|
237
|
+
- **`ToolFilter::TFIDF`**: Replaced undefined `logger.warn` in the rescue path with `Kernel#warn`, eliminating a `NoMethodError` that would mask the original classifier error. (P1-16)
|
|
238
|
+
|
|
239
|
+
## [2.0.0.alpha] - 2026-03-26
|
|
240
|
+
|
|
241
|
+
### Breaking Changes
|
|
242
|
+
- **New execution engine**: AIA is now powered by `robot_lab` and `kbs`. The `RubyLLMAdapter` and the entire `lib/aia/adapter/` layer have been removed.
|
|
243
|
+
- **`AIA.client` is now a `RobotLab::Robot` or `RobotLab::Network`**, built by `AIA::RobotFactory`. Code that references `AIA::RubyLLMAdapter` directly must be updated.
|
|
244
|
+
- **Removed gems**: `ostruct` and `securerandom` are no longer dependencies.
|
|
245
|
+
|
|
246
|
+
### New Features
|
|
247
|
+
- **`RobotFactory`**: Single entry point for building the AI backend. Supports single robot, parallel multi-model, consensus network, and pipeline network modes.
|
|
248
|
+
- **`RuleRouter` with multi-KB architecture**: RETE-based rule engine (via `kbs` gem) with five specialized knowledge bases — input classification, model selection, MCP/tool routing, quality gates, and post-response learning.
|
|
249
|
+
- **`NetworkBuilder`**: Extracted network construction for pipeline, parallel, and consensus topologies.
|
|
250
|
+
- **Dynamic model switching**: Mid-session model changes via `ModelSwitchHandler`, `ModelAliasRegistry` (fuzzy name matching), and `HistoryTransfer` (conversation continuity across switches).
|
|
251
|
+
- **`@mention` routing**: `MentionRouter` routes prompts to named robots via `@model-name` syntax in chat.
|
|
252
|
+
- **MCP concurrency**: `McpConnectionManager` maintains persistent stdio connections; `McpDiscovery` and `McpGrouper` classify and route servers by capability.
|
|
253
|
+
- **TrakFlow integration**: `TrakFlowBridge` creates plans from prompt pipelines and tracks task state. New `/trak` directives. TrakFlow MCP server config included.
|
|
254
|
+
- **Advanced RobotLab patterns**:
|
|
255
|
+
- `VerificationNetwork` — two robots answer independently, a reconciler produces a verified result
|
|
256
|
+
- `DebateHandler` — multi-round debate between robots with convergence detection (max 5 rounds)
|
|
257
|
+
- `PromptDecomposer` — breaks complex prompts into parallel subtasks
|
|
258
|
+
- `ExpertRouter` — KBS-driven routing to domain-specialist robots with tailored model and MCP selection
|
|
259
|
+
- `SpawnHandler` / `DelegateHandler` — dynamic robot spawning and subtask delegation
|
|
260
|
+
- **Built-in tools**: `DelegateToForemanTool` and `TaskBoardTool` as `RubyLLM::Tool` subclasses.
|
|
261
|
+
- **`DynamicRuleBuilder`**: Generates KBS route rules at runtime from discovered local tools and MCP servers, matching domains to activate the appropriate tools per turn.
|
|
262
|
+
- **Semantic tool filtering**: Multiple backends in `lib/aia/tool_filter/` — KBS, LSI, TF-IDF, sqlite-vec, and zvec.
|
|
263
|
+
- **`SessionTracker` and `TurnState`**: Per-session and per-turn state containers for metrics and cost tracking.
|
|
264
|
+
- **`SystemPromptAssembler`**: Extracted system prompt resolution including role loading.
|
|
265
|
+
- **`RobotNamer`**: Deterministic unique robot name generation.
|
|
266
|
+
|
|
267
|
+
### Improvements
|
|
268
|
+
- `RobotFactory` decomposed into focused collaborators (`NetworkBuilder`, `ToolLoader`, `ToolFilter`, `SystemPromptAssembler`, `RobotNamer`)
|
|
269
|
+
- `RuleRouter` refactored from single-KB to multi-KB registry with typed `Decisions` struct
|
|
270
|
+
- `FactAsserter` and `DecisionApplier` extracted for testability; `FactAsserter` now supports asserting additional fact types
|
|
271
|
+
- `StreamingRunner` extracted from `ChatLoop`
|
|
272
|
+
- New `rules_dsl.rb` provides a user-facing DSL for writing custom routing rules
|
|
273
|
+
- `ChatLoop` refactored AI response handling for cleaner robot tool execution and logging
|
|
274
|
+
- `ChatLoop` improved empty user input handling — empty input exits cleanly (break) rather than looping
|
|
275
|
+
- `Decisions` gains `group_by_mcp_server` — groups tool activations by their originating MCP server
|
|
276
|
+
|
|
277
|
+
### Dependencies
|
|
278
|
+
- Added: `robot_lab ~> 0.0, >= 0.0.9`, `kbs ~> 0.2, >= 0.2.1`, `trak_flow`, `classifier`, `zvec`, `sqlite-vec`, `informers`
|
|
279
|
+
- Removed: `ruby_llm` adapter layer (still used transitively via `robot_lab`)
|
|
280
|
+
- `Gemfile.lock` added to `.gitignore`
|
|
67
281
|
|
|
68
282
|
## [1.0.0] - 2026-02-22
|
|
69
283
|
|
|
@@ -778,7 +992,7 @@ aia --chat -m gpt-4o-mini,gpt-3.5-turbo
|
|
|
778
992
|
- fixed a problem with a priming prompt in a chat loop
|
|
779
993
|
|
|
780
994
|
## [0.9.0] 2025-05-13
|
|
781
|
-
- Adding experimental MCP Client
|
|
995
|
+
- Adding experimental MCP Client support
|
|
782
996
|
- removed the CLI options --erb and --shell but kept them in the config file with a default of true for both
|
|
783
997
|
|
|
784
998
|
## [0.8.6] 2025-04-23
|
|
@@ -850,7 +1064,7 @@ aia --chat -m gpt-4o-mini,gpt-3.5-turbo
|
|
|
850
1064
|
- Added --image_size and --image_quality (--is --iq)
|
|
851
1065
|
|
|
852
1066
|
## [0.5.15] 2024-03-30
|
|
853
|
-
- Added the ability to accept piped in text to be
|
|
1067
|
+
- Added the ability to accept piped in text to be appended to the end of the prompt text: curl $URL | aia ad_hoc
|
|
854
1068
|
- Fixed bugs with entering directives as follow-up prompts during a chat session
|
|
855
1069
|
|
|
856
1070
|
## [0.5.14] 2024-03-09
|
|
@@ -922,7 +1136,7 @@ aia --chat -m gpt-4o-mini,gpt-3.5-turbo
|
|
|
922
1136
|
|
|
923
1137
|
## [0.3.20] 2023-12-28
|
|
924
1138
|
- added work around to issue with multiple context files going to the `mods` backend
|
|
925
|
-
- added shellwords gem to
|
|
1139
|
+
- added shellwords gem to sanitize prompt text on the command line
|
|
926
1140
|
|
|
927
1141
|
## [0.3.19] 2023-12-26
|
|
928
1142
|
- major code refactoring.
|
|
@@ -930,7 +1144,7 @@ aia --chat -m gpt-4o-mini,gpt-3.5-turbo
|
|
|
930
1144
|
- usage implemented as a man page. --help will display the man page/
|
|
931
1145
|
- added "--dump <yml|yaml|toml>" to send current configuration to STDOUT
|
|
932
1146
|
- added "--completion <bash|fish|zsh>" to send a a completion function for the indicated shell to STDOUT
|
|
933
|
-
- added system environment variable (envar) over-rides of default config values uppercase environment variables prefixed with "AIA_" + config item name for example AIA_PROMPTS_DIR and AIA_MODEL. All config items can be over-ridden by their
|
|
1147
|
+
- added system environment variable (envar) over-rides of default config values uppercase environment variables prefixed with "AIA_" + config item name for example AIA_PROMPTS_DIR and AIA_MODEL. All config items can be over-ridden by their corresponding envars.
|
|
934
1148
|
- config value hierarchy is:
|
|
935
1149
|
1. values from config file over-rides ...
|
|
936
1150
|
2. command line values over-rides ...
|
|
@@ -939,7 +1153,7 @@ aia --chat -m gpt-4o-mini,gpt-3.5-turbo
|
|
|
939
1153
|
|
|
940
1154
|
## [0.3.0] = 2023-11-23
|
|
941
1155
|
|
|
942
|
-
- Matching version to [prompt_manager](https://github.com/prompt_manager) This version allows for the user of history in the
|
|
1156
|
+
- Matching version to [prompt_manager](https://github.com/prompt_manager) This version allows for the user of history in the entry of values to prompt keywords. KW_HISTORY_MAX is set at 5. Changed CLI interaction to use historical selection and editing of prior keyword values.
|
|
943
1157
|
|
|
944
1158
|
## [0.1.0] - 2023-11-23
|
|
945
1159
|
|