aia 2.0.1 → 2.1.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +89 -57
- data/README.md +64 -19
- data/lib/aia/config/cli_parser.rb +3 -2
- data/lib/aia/config/model_spec.rb +14 -5
- data/lib/aia/config.rb +14 -5
- data/lib/aia/delegate_handler.rb +3 -0
- data/lib/aia/errors.rb +4 -0
- data/lib/aia/llm_error_collector.rb +67 -0
- data/lib/aia/pipeline_orchestrator.rb +56 -6
- data/lib/aia/prompt_handler.rb +24 -0
- data/lib/aia/provider_registry.rb +58 -7
- data/lib/aia/robot_factory.rb +54 -1
- data/lib/aia/special_mode_handler.rb +0 -2
- data/lib/aia/tools/delegate_to_foreman_tool.rb +2 -0
- data/lib/aia/version.rb +1 -1
- data/lib/aia.rb +13 -5
- metadata +33 -14
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 1d7d1dff13dc9c4e4558c4624bf6368cb32f42a4a4896238e1750e5beaa24d7b
|
|
4
|
+
data.tar.gz: e430f69d905314342a538d063b5123dd5fd454dabcd6bae08a2ad3d696d74d56
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b136ae2840a452e8aa5dae4585588036ea10420abbd071c5fd3b45e0fea86a2f6c35005680757e8c2ebde9a63d8a6abf3538a164446c03cc1300aafd41a97728
|
|
7
|
+
data.tar.gz: 06c4e7081bdfe6c618bb4dc868d37daf232c491d04319bf8426232b85442a94eb279b04cba69e3e456d7580d51bdaede5d761367f9331f481387c15432506df4
|
data/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,38 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## [2.0
|
|
3
|
+
## [2.1.0] - 2026-11-07
|
|
4
|
+
|
|
5
|
+
Coding-agent CLIs (Claude Code, Codex, GitHub Copilot) can be used as models, and a prompt file can ask for a special mode such as `debate` in its front matter. Batch runs now exit 1 when an LLM call fails. The unit test suite runs without API keys, a UTF-8 locale or a particular Ruby patch level, and every test file runs on its own.
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- **Coding agents as models.** `--model claude_code/opus`, `codex/default` or `copilot/auto` sends prompts to the Claude Code, Codex or GitHub Copilot CLI in batch mode (stdin in, JSON out) through the `ruby_llm-providers-claude_code`, `-codex` and `-copilot` gems, which resume the agent's own session between turns. A bare provider name (`--model claude_code`) now means that provider's default model. Providers that answer `accepts_tools?` with `false` get no aia tools or MCP servers attached, with a one-line notice. An installed provider gem is found and loaded even when aia itself runs under Bundler (a `bin/aia` checkout, or an app that lists aia in its Gemfile) and the gem is not in that Gemfile, provided the bundle already satisfies the gem's dependencies.
|
|
10
|
+
|
|
11
|
+
- **`mode:` front matter key.** A prompt file can ask for one of the special modes that the chat directives `/debate`, `/verify`, `/decompose`, `/delegate`, `/spawn`, `/orchestrate` and `/concurrent` request, by naming it in its front matter: `mode: debate`. Prompts run from the command line, in a pipeline or as executable prompts then get that mode, which until now ran only in chat; a `/debate` line inside a prompt file was sent to the model as text. As in chat, a debate needs several robots (`--model a,b,c`).
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
|
|
15
|
+
- **`--provider` outranks `AIA_MODEL` and the config file.** `--provider claude_code` replaced the provider only of models given without a `<provider>/` prefix, so with `AIA_MODEL=lms/qwen3.8` exported the flag did nothing and the prompt still went to LM Studio. A command-line `--provider` now applies to every model that came from the environment or a config file, prefix or not, keeping their model names; it sets the provider, never the model, so `--model claude_code` (a bare provider name) remains the way to ask for a provider's default model. Models named on the command line with `--model` keep an explicit prefix, since both values come from the same place. When a provider gem cannot be loaded because aia is running under Bundler, the warning now names the Gemfile to add the `ruby_llm-providers-<slug>` gem to.
|
|
16
|
+
|
|
17
|
+
- **Batch runs exit 1 on LLM errors.** robot_lab shields a robot's exception into an `Error: ...` reply so one failing robot cannot crash a network, which left `aia prompt` printing a bad API key, rate limit or provider outage as the answer and exiting 0. A hook now records the real exception for each pipeline step: outside chat the step fails, the error goes to stderr and aia exits 1; in a chat session the error is shown and the session continues. Unshielded RubyLLM errors (image generation, provider setup) exit 1 with a one-line message instead of a backtrace.
|
|
18
|
+
|
|
19
|
+
- **`--paint` works again, and `--image_quality` / `--image_style` reach the API.** Since 2.0.0 the image step handed `RubyLLM.paint` a `params:` keyword that ruby_llm 2.1 does not have, so every `--paint` run stopped with `ArgumentError: unknown keyword: :params` before any request was made. The options now go through `provider_options:`, which ruby_llm merges into the request, so `--image_quality hd --image_style vivid` take effect (#135).
|
|
20
|
+
|
|
21
|
+
- **`DelegateHandler` and `DelegateToForemanTool` load what they use.** `delegate_handler.rb` now requires `TaskDecomposer` and `TaskExecutor`, and `delegate_to_foreman_tool.rb` requires `TaskBoardTool`. Each worked only because its one caller also required those files, so loading either on its own and calling it raised `uninitialized constant`.
|
|
22
|
+
|
|
23
|
+
**Test suite**
|
|
24
|
+
|
|
25
|
+
- **Failing test runs exit non-zero.** `test_helper.rb`'s `exit` override, which stops aia's exit calls from ending a test run early, also swallowed Minitest's exit status, so `rake test` and single test files exited 0 when tests failed. The override now stands down after the suite runs.
|
|
26
|
+
|
|
27
|
+
- **Test suite loads on Ruby 4.1.** `ostruct` is a bundled gem since Ruby 4.0 and only reached the test bundle as a transitive dependency of `oj` 3.17.7; `oj` 3.17.8 dropped it, so `bundle update` left the suite unable to load `OpenStruct`. It is now a development dependency. The speech player test no longer stubs `ENV`, which Ruby 4.1 rejects as a shareable object.
|
|
28
|
+
|
|
29
|
+
- **Unit suite passes without API keys or a UTF-8 locale.** The network-building tests create real RubyLLM chats, which ruby_llm 2.1 refuses without a provider API key, so 37 tests errored unless `OPENAI_API_KEY` was set. They now skip that credential check; they never call an API. The gemspec version test errored under a non-UTF-8 locale; it now loads the gemspec and compares its version with `AIA::VERSION`. `test_helper.rb` requires `ostruct`, so test files that use `OpenStruct` also run on their own.
|
|
30
|
+
|
|
31
|
+
- **Every unit test file runs on its own.** Six files raised `uninitialized constant` when run alone, because aia loads a class each one uses lazily: `TaskDecomposer`, `TaskExecutor`, `TaskBoardTool` (one file each) and `ToolFilter::TFIDF` (three files). Each file now requires that class.
|
|
32
|
+
|
|
33
|
+
- **`ConfigTest` ignores the shell's `AIA_PLUGINS_DIR`.** The test that checks `paths.plugins_dir` defaults to `nil` read whatever the developer's shell had exported and failed, and the two tests that set the variable deleted it afterwards. All three now set the variable for their own run and restore it.
|
|
34
|
+
|
|
35
|
+
## [2.0.1] - 2026-11-02
|
|
4
36
|
|
|
5
37
|
### Fixed
|
|
6
38
|
|
|
@@ -11,7 +43,7 @@
|
|
|
11
43
|
- `logger.mcp.file` defaults to `~/.config/aia/logs/mcp.log` (was `STDOUT`), so MCP connection warnings no longer print over the spinner. Failed servers are still listed in the startup banner. A config file that sets `file: STDOUT` keeps the old behavior.
|
|
12
44
|
- Log directories are created when they don't exist.
|
|
13
45
|
|
|
14
|
-
## [2.0.0] 2026-11-02
|
|
46
|
+
## [2.0.0] - 2026-11-02
|
|
15
47
|
|
|
16
48
|
AIA 2.0 rebuilds the CLI on [robot_lab](https://github.com/MadBomber/robot_lab): every session is a crew of robots, MCP servers come from ruby_llm 2.1's built-in client, and any provider RubyLLM registers can be used. This entry summarizes everything since 1.1.1, the last 1.x release, including the `2.0.0.pre.alpha` and `2.0.0.pre.beta2` pre-releases.
|
|
17
49
|
|
|
@@ -436,7 +468,7 @@ If you used a 2.0 pre-release: the KBS rule engine, `/rules`, user-defined rule
|
|
|
436
468
|
- Added `handle_tool_crash` method that logs errors with 5-line traceback
|
|
437
469
|
- Tool crashes no longer crash AIA - conversation continues gracefully
|
|
438
470
|
|
|
439
|
-
## [0.9.24] 2025-12-17
|
|
471
|
+
## [0.9.24] - 2025-12-17
|
|
440
472
|
### Fixes
|
|
441
473
|
- Ran into a problem with the `shared_tools` gem and the --require parameter of AIA which required changes to both gems.
|
|
442
474
|
|
|
@@ -461,7 +493,7 @@ If you used a 2.0 pre-release: the KBS rule engine, `/rules`, user-defined rule
|
|
|
461
493
|
- Added `handle_tool_crash` method for graceful error handling
|
|
462
494
|
- Removed debug statements
|
|
463
495
|
|
|
464
|
-
## [0.9.23] 2025-12-06
|
|
496
|
+
## [0.9.23] - 2025-12-06
|
|
465
497
|
|
|
466
498
|
### New Features
|
|
467
499
|
- **MCP Server Configuration**: Added native support for defining MCP (Model Context Protocol) servers in the config file
|
|
@@ -494,7 +526,7 @@ If you used a 2.0 pre-release: the KBS rule engine, `/rules`, user-defined rule
|
|
|
494
526
|
MY_VAR: "value"
|
|
495
527
|
```
|
|
496
528
|
|
|
497
|
-
## [0.9.22] 2025-11-12
|
|
529
|
+
## [0.9.22] - 2025-11-12
|
|
498
530
|
|
|
499
531
|
### Bug Fixes
|
|
500
532
|
- **TEST SUITE**: Fixed all Mocha test isolation issues causing stub contamination between tests
|
|
@@ -510,14 +542,14 @@ If you used a 2.0 pre-release: the KBS rule engine, `/rules`, user-defined rule
|
|
|
510
542
|
- Standardized stub usage pattern across test suite for consistency
|
|
511
543
|
- Eliminated stub leakage that caused "unexpected invocation" and "AIA was instantiated in one test but receiving invocations in another" errors
|
|
512
544
|
|
|
513
|
-
## [0.9.21] 2025-10-08
|
|
545
|
+
## [0.9.21] - 2025-10-08
|
|
514
546
|
### Bug Fixes
|
|
515
547
|
- **Checkpoint Directive Output**: Fixed `//checkpoint` directive to return empty string instead of status message (lib/aia/directives/configuration.rb:155)
|
|
516
548
|
- Prevents checkpoint creation messages from entering AI context
|
|
517
549
|
- Outputs confirmation to STDOUT instead for user feedback
|
|
518
550
|
- Prevents potential AI manipulation of checkpoint system
|
|
519
551
|
|
|
520
|
-
## [0.9.20] 2025-10-06
|
|
552
|
+
## [0.9.20] - 2025-10-06
|
|
521
553
|
### Added
|
|
522
554
|
- **Enhanced Multi-Model Role System (ADR-005)**: Implemented per-model role assignment with inline syntax
|
|
523
555
|
- New inline syntax: `--model MODEL[=ROLE][,MODEL[=ROLE]]...`
|
|
@@ -581,7 +613,7 @@ If you used a 2.0 pre-release: the KBS rule engine, `/rules`, user-defined rule
|
|
|
581
613
|
- Enhanced `apply_file_config_to_struct` to detect and process model arrays with role hashes
|
|
582
614
|
- Enhanced `envar_options` to parse inline syntax for `:model` key (lib/aia/config/base.rb:212-217)
|
|
583
615
|
|
|
584
|
-
## [0.9.19] 2025-10-06
|
|
616
|
+
## [0.9.19] - 2025-10-06
|
|
585
617
|
|
|
586
618
|
### Bug Fixes
|
|
587
619
|
- **CRITICAL BUG FIX**: Fixed multi-model cross-talk issue (#118) where models could see each other's conversation history
|
|
@@ -644,7 +676,7 @@ bin/aia --chat --model lms/openai/gpt-oss-20b,ollama/gpt-oss:20b --tokens
|
|
|
644
676
|
# (Previously: LMS would say "5 times", Ollama "6 times" due to cross-talk)
|
|
645
677
|
```
|
|
646
678
|
|
|
647
|
-
## [0.9.18] 2025-10-05
|
|
679
|
+
## [0.9.18] - 2025-10-05
|
|
648
680
|
|
|
649
681
|
### Bug Fixes
|
|
650
682
|
- **BUG FIX**: Fixed RubyLLM provider error parsing to handle both OpenAI and LM Studio error formats
|
|
@@ -663,7 +695,7 @@ bin/aia --chat --model lms/openai/gpt-oss-20b,ollama/gpt-oss:20b --tokens
|
|
|
663
695
|
- Cleaned up debug puts statements from RubyLLMAdapter and provider_fix
|
|
664
696
|
- Added robust JSON parsing with fallback error handling
|
|
665
697
|
|
|
666
|
-
## [0.9.17] 2025-10-04
|
|
698
|
+
## [0.9.17] - 2025-10-04
|
|
667
699
|
|
|
668
700
|
### New Features
|
|
669
701
|
- **NEW FEATURE**: Enhanced local model support with comprehensive validation and error handling
|
|
@@ -713,7 +745,7 @@ aia --model ollama/llama3.2 --chat
|
|
|
713
745
|
> //models
|
|
714
746
|
```
|
|
715
747
|
|
|
716
|
-
## [0.9.16] 2025-09-26
|
|
748
|
+
## [0.9.16] - 2025-09-26
|
|
717
749
|
|
|
718
750
|
### New Features
|
|
719
751
|
- **NEW FEATURE**: Added support for Ollama AI provider
|
|
@@ -724,7 +756,7 @@ aia --model ollama/llama3.2 --chat
|
|
|
724
756
|
- **ENHANCEMENT**: Expanded AI provider ecosystem with three new local/self-hosted model options
|
|
725
757
|
- **ENHANCEMENT**: Improved flexibility for users preferring local LLM deployments
|
|
726
758
|
|
|
727
|
-
## [0.9.15] 2025-09-21
|
|
759
|
+
## [0.9.15] - 2025-09-21
|
|
728
760
|
|
|
729
761
|
### New Features
|
|
730
762
|
- **NEW FEATURE**: Added `//paste` directive to insert clipboard contents into prompts
|
|
@@ -734,7 +766,7 @@ aia --model ollama/llama3.2 --chat
|
|
|
734
766
|
- Enhanced DirectiveProcessor with clipboard integration using the clipboard gem
|
|
735
767
|
- Added comprehensive test coverage for paste directive functionality
|
|
736
768
|
|
|
737
|
-
## [0.9.14] 2025-09-19
|
|
769
|
+
## [0.9.14] - 2025-09-19
|
|
738
770
|
|
|
739
771
|
### New Features
|
|
740
772
|
- **NEW FEATURE**: Added `//checkpoint` directive to create named snapshots of conversation context
|
|
@@ -760,7 +792,7 @@ aia --model ollama/llama3.2 --chat
|
|
|
760
792
|
- Refactored help directive to collect directives from all registered modules
|
|
761
793
|
- Added comprehensive test coverage for checkpoint and restore functionality
|
|
762
794
|
|
|
763
|
-
## [0.9.13] 2025-09-02
|
|
795
|
+
## [0.9.13] - 2025-09-02
|
|
764
796
|
### New Features
|
|
765
797
|
- **NEW FEATURE**: Added `--tokens` flag to show token counts for each model
|
|
766
798
|
- **NEW FEATURE**: Added `--cost` flag to enable cost estimation for each model
|
|
@@ -778,7 +810,7 @@ aia --model ollama/llama3.2 --chat
|
|
|
778
810
|
- Enhanced test suite with improved assertions and coverage
|
|
779
811
|
- Updated various gem dependencies to latest stable versions
|
|
780
812
|
|
|
781
|
-
## [0.9.12] 2025-08-28
|
|
813
|
+
## [0.9.12] - 2025-08-28
|
|
782
814
|
|
|
783
815
|
### New Features
|
|
784
816
|
- **MAJOR NEW FEATURE**: Multi-model support - specify multiple AI models simultaneously with comma-separated syntax
|
|
@@ -845,15 +877,15 @@ aia --chat -m gpt-4o-mini,gpt-3.5-turbo
|
|
|
845
877
|
- TODO: focus on log file consistency using Logger
|
|
846
878
|
|
|
847
879
|
|
|
848
|
-
## [0.9.11] 2025-07-31
|
|
880
|
+
## [0.9.11] - 2025-07-31
|
|
849
881
|
- added a cost per 1 million input tokens to available_models query output
|
|
850
882
|
- updated ruby_llm to version 1.4.0
|
|
851
883
|
- updated all other gem dependencies to their latest versions
|
|
852
884
|
|
|
853
|
-
## [0.9.10] 2025-07-18
|
|
885
|
+
## [0.9.10] - 2025-07-18
|
|
854
886
|
- updated ruby_llm-mcp to version 0.6.1 which solves problems with MCP tools not being installed
|
|
855
887
|
|
|
856
|
-
## [0.9.9] 2025-07-10
|
|
888
|
+
## [0.9.9] - 2025-07-10
|
|
857
889
|
- refactored the Session and Config classes into more testable method_missing
|
|
858
890
|
- updated the test suire for both the Session and Config classes
|
|
859
891
|
- added support for MCP servers coming into AIA via the shared_tools gem
|
|
@@ -864,13 +896,13 @@ aia --chat -m gpt-4o-mini,gpt-3.5-turbo
|
|
|
864
896
|
- //available_models now has context window size and capabilities for each model returned
|
|
865
897
|
|
|
866
898
|
|
|
867
|
-
## [0.9.8] 2025-06-25
|
|
899
|
+
## [0.9.8] - 2025-06-25
|
|
868
900
|
- fixing an issue with pipelined prompts
|
|
869
901
|
- now showing the complete modality of the model on the processing line.
|
|
870
902
|
- changed -p option from prompts_dir to pipeline
|
|
871
903
|
- found problem with simple cov and deep cov w/r/t their reported test coverage; they have problems with heredoc and complex conditionals.
|
|
872
904
|
|
|
873
|
-
## [0.9.7] 2025-06-20
|
|
905
|
+
## [0.9.7] - 2025-06-20
|
|
874
906
|
|
|
875
907
|
- **NEW FEATURE**: Added `--available_models` CLI option to list all available AI models
|
|
876
908
|
- **NEW FEATURE**: Added `//tools` to show a list of available tools and their description
|
|
@@ -881,7 +913,7 @@ aia --chat -m gpt-4o-mini,gpt-3.5-turbo
|
|
|
881
913
|
- **DOCUMENTATION**: Updated README for better clarity and structure
|
|
882
914
|
- **DEPENDENCY**: Updated Gemfile.lock with latest dependency versions
|
|
883
915
|
|
|
884
|
-
## [0.9.6] 2025-06-13
|
|
916
|
+
## [0.9.6] - 2025-06-13
|
|
885
917
|
- fixed issue 84 with the //llms directive
|
|
886
918
|
- changed the monkey patch to the RubyLLM::Model::Modalities class at the suggestions of the RubyLLM author in prep for a PR against that gem.
|
|
887
919
|
- added the shared_tools gem - need to add examples on how to use it with the --tools option
|
|
@@ -889,11 +921,11 @@ aia --chat -m gpt-4o-mini,gpt-3.5-turbo
|
|
|
889
921
|
- added images/aia.png to README.md
|
|
890
922
|
- let claude code rewrite the README.md file. Some details were dropped but overall in reads better. Need to add the details to a wiki or other documentation site.
|
|
891
923
|
|
|
892
|
-
## [0.9.5] 2025-06-04
|
|
924
|
+
## [0.9.5] - 2025-06-04
|
|
893
925
|
- changed the RubyLLM::Modalities class to use method_missing for mode query
|
|
894
926
|
- hunting for why the //llms query directive is not finding image_to_image LLMs.
|
|
895
927
|
|
|
896
|
-
## [0.9.4] 2025-06-03
|
|
928
|
+
## [0.9.4] - 2025-06-03
|
|
897
929
|
- using RubyLLM v1.3.0
|
|
898
930
|
- setting up a docs infrastructure to behave like the ruby_llm gem's guides side
|
|
899
931
|
- fixed bug in the text-to-image workflow
|
|
@@ -901,7 +933,7 @@ aia --chat -m gpt-4o-mini,gpt-3.5-turbo
|
|
|
901
933
|
- need to pay attention to the test suite
|
|
902
934
|
- also need to ensure the non text2text modes are working
|
|
903
935
|
|
|
904
|
-
## [0.9.3rc1] 2025-05-24
|
|
936
|
+
## [0.9.3rc1] - 2025-05-24
|
|
905
937
|
- using ruby_llm v1.3.0rc1
|
|
906
938
|
- added a models database refresh based on integer days interval with the --refresh option
|
|
907
939
|
- config file now has a "last_refresh" String in format YYYY-MM-DD
|
|
@@ -910,41 +942,41 @@ aia --chat -m gpt-4o-mini,gpt-3.5-turbo
|
|
|
910
942
|
- fixed a bug in the prompt_manager gem which is now at v0.5.5
|
|
911
943
|
|
|
912
944
|
|
|
913
|
-
## [0.9.2] 2025-05-18
|
|
945
|
+
## [0.9.2] - 2025-05-18
|
|
914
946
|
- removing the MCP experiment
|
|
915
947
|
- adding support for RubyLLM::Tool usage in place of the MCP stuff
|
|
916
948
|
- updated prompt_manager to v0.5.4 which fixed shell integration problem
|
|
917
949
|
|
|
918
|
-
## [0.9.1] 2025-05-16
|
|
950
|
+
## [0.9.1] - 2025-05-16
|
|
919
951
|
- rethink MCP approach in favor of just RubyLLM::Tool
|
|
920
952
|
- fixed problem with //clear
|
|
921
953
|
- fixed a problem with a priming prompt in a chat loop
|
|
922
954
|
|
|
923
|
-
## [0.9.0] 2025-05-13
|
|
955
|
+
## [0.9.0] - 2025-05-13
|
|
924
956
|
- Adding experimental MCP Client support
|
|
925
957
|
- removed the CLI options --erb and --shell but kept them in the config file with a default of true for both
|
|
926
958
|
|
|
927
|
-
## [0.8.6] 2025-04-23
|
|
959
|
+
## [0.8.6] - 2025-04-23
|
|
928
960
|
- Added a client adapter for the ruby_llm gem
|
|
929
961
|
- Added the adapter config item and the --adapter option to select at runtime which client to use ai_client or ruby_llm
|
|
930
962
|
|
|
931
|
-
## [0.8.5] 2025-04-19
|
|
963
|
+
## [0.8.5] - 2025-04-19
|
|
932
964
|
- documentation updates
|
|
933
965
|
- integrated the https://pure.md web service for inserting web pages into the context window
|
|
934
966
|
- //include http?://example.com/stuff
|
|
935
967
|
- //webpage http?://example.com/stuff
|
|
936
968
|
|
|
937
|
-
## [0.8.2] 2025-04-18
|
|
969
|
+
## [0.8.2] - 2025-04-18
|
|
938
970
|
- fixed problems with pre-loaded context and chat repl
|
|
939
971
|
- piped content into `aia --chat` is now a part of the context/instructions
|
|
940
972
|
- content via "aia --chat < some_file" is added to the context/instructions
|
|
941
973
|
- `aia --chat context_file.txt context_file2.txt` now works
|
|
942
974
|
- `aia --chat prompt_id context)file.txt` also works
|
|
943
975
|
|
|
944
|
-
## [0.8.1] 2025-04-17
|
|
976
|
+
## [0.8.1] - 2025-04-17
|
|
945
977
|
- bumped version to 0.8.1 after correcting merge conflicts
|
|
946
978
|
|
|
947
|
-
## [0.8.0]
|
|
979
|
+
## [0.8.0] - 2025-04-15
|
|
948
980
|
- Updated PromptManager to v0.5.1 which has some of the functionality that was originally developed in the AIA.
|
|
949
981
|
- Enhanced README.md to include a comprehensive table of configuration options with defaults and associated environment variables.
|
|
950
982
|
- Added a note in README.md about the expandability of configuration options from a config file for dynamic prompt generation.
|
|
@@ -952,7 +984,7 @@ aia --chat -m gpt-4o-mini,gpt-3.5-turbo
|
|
|
952
984
|
- Ensured version consistency across `.version`, `aia.gemspec`, and `lib/aia/version.rb`.
|
|
953
985
|
- Verified and updated documentation to ensure readiness for release on RubyGems.org.
|
|
954
986
|
|
|
955
|
-
## [0.7.1]
|
|
987
|
+
## [0.7.1] - 2025-03-22
|
|
956
988
|
- Added `UIPresenter` class for handling user interface presentation.
|
|
957
989
|
- Added `DirectiveProcessor` class for processing chat-based directives.
|
|
958
990
|
- Added `HistoryManager` class for managing conversation and variable history.
|
|
@@ -966,7 +998,7 @@ aia --chat -m gpt-4o-mini,gpt-3.5-turbo
|
|
|
966
998
|
- Improved error handling and user feedback for directive processing.
|
|
967
999
|
- Enhanced logging and output options for chat sessions.
|
|
968
1000
|
|
|
969
|
-
## [0.7.0]
|
|
1001
|
+
## [0.7.0] - 2025-03-17
|
|
970
1002
|
- Major code refactoring for better organization and maintainability:
|
|
971
1003
|
- Extracted `DirectiveProcessor` class to handle chat-based directives
|
|
972
1004
|
- Extracted `HistoryManager` class for conversation and variable history management
|
|
@@ -977,13 +1009,13 @@ aia --chat -m gpt-4o-mini,gpt-3.5-turbo
|
|
|
977
1009
|
- Improved output handling to suppress STDOUT when chat mode is off and output file is specified
|
|
978
1010
|
- Updated spinner format in the process_prompt method for better user experience
|
|
979
1011
|
|
|
980
|
-
## [0.6.?] WIP
|
|
1012
|
+
## [0.6.?] - WIP
|
|
981
1013
|
- Implemented Tony Stark's Clean Slate Protocol on the develop branch
|
|
982
1014
|
|
|
983
|
-
## [0.5.17] 2024-05-17
|
|
1015
|
+
## [0.5.17] - 2024-05-17
|
|
984
1016
|
- removed replaced `semver` with `versionaire`
|
|
985
1017
|
|
|
986
|
-
## [0.5.16] 2024-04-02
|
|
1018
|
+
## [0.5.16] - 2024-04-02
|
|
987
1019
|
- fixed prompt pipelines
|
|
988
1020
|
- added //next and //pipeline directives as shortcuts to //config [next,pipeline]
|
|
989
1021
|
- Added new backend "client" as an internal OpenAI client
|
|
@@ -992,82 +1024,82 @@ aia --chat -m gpt-4o-mini,gpt-3.5-turbo
|
|
|
992
1024
|
- Added --voice default: alloy (if "siri" and Mac? then uses cli tool "say")
|
|
993
1025
|
- Added --image_size and --image_quality (--is --iq)
|
|
994
1026
|
|
|
995
|
-
## [0.5.15] 2024-03-30
|
|
1027
|
+
## [0.5.15] - 2024-03-30
|
|
996
1028
|
- Added the ability to accept piped in text to be appended to the end of the prompt text: curl $URL | aia ad_hoc
|
|
997
1029
|
- Fixed bugs with entering directives as follow-up prompts during a chat session
|
|
998
1030
|
|
|
999
|
-
## [0.5.14] 2024-03-09
|
|
1031
|
+
## [0.5.14] - 2024-03-09
|
|
1000
1032
|
- Directly access OpenAI to do text to speech when using the `--speak` option
|
|
1001
1033
|
- Added --voice to specify which voice to use
|
|
1002
1034
|
- Added --speech_model to specify which TTS model to use
|
|
1003
1035
|
|
|
1004
|
-
## [0.5.13] 2024-03-03
|
|
1036
|
+
## [0.5.13] - 2024-03-03
|
|
1005
1037
|
- Added CLI-utility `llm` as a backend processor
|
|
1006
1038
|
|
|
1007
|
-
## [0.5.12] 2024-02-24
|
|
1039
|
+
## [0.5.12] - 2024-02-24
|
|
1008
1040
|
- Happy Birthday Ruby!
|
|
1009
1041
|
- Added --next CLI option
|
|
1010
1042
|
- Added --pipeline CLI option
|
|
1011
1043
|
|
|
1012
|
-
## [0.5.11] 2024-02-18
|
|
1044
|
+
## [0.5.11] - 2024-02-18
|
|
1013
1045
|
- allow directives to return information that is inserted into the prompt text
|
|
1014
1046
|
- added //shell command directive
|
|
1015
1047
|
- added //ruby ruby_code directive
|
|
1016
1048
|
- added //include path_to_file directive
|
|
1017
1049
|
|
|
1018
|
-
## [0.5.10] 2024-02-03
|
|
1050
|
+
## [0.5.10] - 2024-02-03
|
|
1019
1051
|
- Added --roles_dir to isolate roles from other prompts if desired
|
|
1020
1052
|
- Changed --prompts to --prompts_dir to be consistent
|
|
1021
1053
|
- Refactored common fzf usage into its own tool class
|
|
1022
1054
|
|
|
1023
|
-
## [0.5.9] 2024-02-01
|
|
1055
|
+
## [0.5.9] - 2024-02-01
|
|
1024
1056
|
- Added a "I'm working" spinner thing when "--verbose" is used as an indication that the backend is in the process of composing its response to the prompt.
|
|
1025
1057
|
|
|
1026
|
-
## [0.5.8] 2024-01-17
|
|
1058
|
+
## [0.5.8] - 2024-01-17
|
|
1027
1059
|
- Changed the behavior of the --dump option. It must now be followed by path/to/file.ext where ext is a supported config file format: yml, yaml, toml
|
|
1028
1060
|
|
|
1029
|
-
## [0.5.7] 2024-01-15
|
|
1061
|
+
## [0.5.7] - 2024-01-15
|
|
1030
1062
|
- Added ERB processing to the config_file
|
|
1031
1063
|
|
|
1032
|
-
## [0.5.6] 2024-01-15
|
|
1064
|
+
## [0.5.6] - 2024-01-15
|
|
1033
1065
|
- Adding processing for directives, shell integration and erb to the follow up prompt in a chat session
|
|
1034
1066
|
- some code refactoring.
|
|
1035
1067
|
|
|
1036
|
-
## [0.5.3] 2024-01-14
|
|
1068
|
+
## [0.5.3] - 2024-01-14
|
|
1037
1069
|
- adding ability to render markdown to the terminal using the "glow" CLI utility
|
|
1038
1070
|
|
|
1039
|
-
## [0.5.2] 2024-01-13
|
|
1071
|
+
## [0.5.2] - 2024-01-13
|
|
1040
1072
|
- wrap response when its going to the terminal
|
|
1041
1073
|
|
|
1042
|
-
## [0.5.1] 2024-01-12
|
|
1074
|
+
## [0.5.1] - 2024-01-12
|
|
1043
1075
|
- removed a wicked puts "loaded" statement
|
|
1044
1076
|
- fixed missed code when the options were changed to --out_file and --log_file
|
|
1045
1077
|
- fixed completion functions by updating $PROMPT_DIR to $AIA_PROMPTS_DIR to match the documentation.
|
|
1046
1078
|
|
|
1047
|
-
## [0.5.0] 2024-01-05
|
|
1079
|
+
## [0.5.0] - 2024-01-05
|
|
1048
1080
|
- breaking changes:
|
|
1049
1081
|
- changed `--config` to `--config_file`
|
|
1050
1082
|
- changed `--env` to `--shell`
|
|
1051
1083
|
- changed `--output` to `--out_file`
|
|
1052
1084
|
- changed default `out_file` to `STDOUT`
|
|
1053
1085
|
|
|
1054
|
-
## [0.4.3] 2023-12-31
|
|
1086
|
+
## [0.4.3] - 2023-12-31
|
|
1055
1087
|
- added --env to process embedded system environment variables and shell commands within a prompt.
|
|
1056
1088
|
- added --erb to process Embedded RuBy within a prompt because have embedded shell commands will only get you in a trouble. Having ERB will really get you into trouble. Remember the simple prompt is usually the best prompt.
|
|
1057
1089
|
|
|
1058
|
-
## [0.4.2] 2023-12-31
|
|
1090
|
+
## [0.4.2] - 2023-12-31
|
|
1059
1091
|
- added the --role CLI option to pre-pend a "role" prompt to the front of a primary prompt.
|
|
1060
1092
|
|
|
1061
|
-
## [0.4.1] 2023-12-31
|
|
1093
|
+
## [0.4.1] - 2023-12-31
|
|
1062
1094
|
- added a chat mode
|
|
1063
1095
|
- prompt directives now supported
|
|
1064
1096
|
- version bumped to match the `prompt_manager` gem
|
|
1065
1097
|
|
|
1066
|
-
## [0.3.20] 2023-12-28
|
|
1098
|
+
## [0.3.20] - 2023-12-28
|
|
1067
1099
|
- added work around to issue with multiple context files going to the `mods` backend
|
|
1068
1100
|
- added shellwords gem to sanitize prompt text on the command line
|
|
1069
1101
|
|
|
1070
|
-
## [0.3.19] 2023-12-26
|
|
1102
|
+
## [0.3.19] - 2023-12-26
|
|
1071
1103
|
- major code refactoring.
|
|
1072
1104
|
- supports config files \*.yml, \*.yaml and \*.toml
|
|
1073
1105
|
- usage implemented as a man page. --help will display the man page/
|
|
@@ -1080,7 +1112,7 @@ aia --chat -m gpt-4o-mini,gpt-3.5-turbo
|
|
|
1080
1112
|
3. envar values over-rides ...
|
|
1081
1113
|
4. default values
|
|
1082
1114
|
|
|
1083
|
-
## [0.3.0]
|
|
1115
|
+
## [0.3.0] - 2023-11-23
|
|
1084
1116
|
|
|
1085
1117
|
- 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.
|
|
1086
1118
|
|
data/README.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
<img src="docs/assets/images/aia.png" alt="Robots waiter ready to take your order."><br />
|
|
8
8
|
**The Prompt is the Code**<br />
|
|
9
|
-
<p>
|
|
9
|
+
<p>New in 2.1: <a href="#coding-agents-as-models-claude-code-codex-copilot">coding agents as models</a>. Point <code>--model</code> at <code>claude_code/</code>, <code>codex/</code> or <code>copilot/</code> and the Claude Code, Codex or GitHub Copilot CLI answers your prompt, alone or as a member of a crew.</p>
|
|
10
10
|
</div>
|
|
11
11
|
|
|
12
12
|
---
|
|
@@ -33,6 +33,7 @@ For more information on AIA visit these locations:
|
|
|
33
33
|
| Prompt management | File-based system with history, variables, and fuzzy search | Limited or none |
|
|
34
34
|
| Workflow pipelines | Native `--next` / `--pipeline` chaining | Manual chaining required |
|
|
35
35
|
| Local model support | Ollama and LM Studio out of the box | Varies |
|
|
36
|
+
| Coding agents as models | Claude Code, Codex and Copilot CLIs used like any other model, alone or in a crew | Not available |
|
|
36
37
|
| Tool integration | RubyLLM tools + MCP server ecosystem | Limited |
|
|
37
38
|
| Shell & ERB integration | Native — prompts are live Ruby/shell programs | External only |
|
|
38
39
|
| Agent orchestration | Debate, spawn, verify, decompose, delegate directives | Not available |
|
|
@@ -74,15 +75,15 @@ For more information on AIA visit these locations:
|
|
|
74
75
|
|
|
75
76
|
```plain
|
|
76
77
|
|
|
77
|
-
, , AIA v2.
|
|
78
|
+
, , AIA v2.1.0 is Online
|
|
78
79
|
(\____/)
|
|
79
|
-
(_oo_) Models:
|
|
80
|
-
(O) DB: refreshed 2026-
|
|
81
|
-
__|||__ \) Libs: ruby_llm v2.1.1, robot_lab v0.
|
|
82
|
-
[/ Tobor \] /
|
|
83
|
-
/ \_______/ \/
|
|
84
|
-
/ /___\
|
|
85
|
-
(\ /_____\
|
|
80
|
+
(_oo_) Models: claude-sonnet-4-6
|
|
81
|
+
(O) DB: refreshed 2026-11-01 at 22:28
|
|
82
|
+
__|||__ \) Libs: ruby_llm v2.1.1, robot_lab v0.6.0, simple_flow v0.4.0, trak_flow v0.2.0, typed_bus v0.0.1
|
|
83
|
+
[/ Tobor \] / Tools: none loaded
|
|
84
|
+
/ \_______/ \/ MCP: (none configured)
|
|
85
|
+
/ /___\ Crew: @tobor
|
|
86
|
+
(\ /_____\
|
|
86
87
|
::: :::
|
|
87
88
|
::: :::
|
|
88
89
|
|
|
@@ -175,6 +176,7 @@ Implement a schema registry with event-driven synchronization...
|
|
|
175
176
|
- [Ollama Integration](#ollama-integration)
|
|
176
177
|
- [LM Studio Integration](#lm-studio-integration)
|
|
177
178
|
- [Listing Local Models](#listing-local-models)
|
|
179
|
+
- [Coding Agents as Models (Claude Code, Codex, Copilot)](#coding-agents-as-models-claude-code-codex-copilot)
|
|
178
180
|
- [Shell Integration](#shell-integration)
|
|
179
181
|
- [Embedded Ruby (ERB)](#embedded-ruby-erb)
|
|
180
182
|
- [Prompt Sequences](#prompt-sequences)
|
|
@@ -296,7 +298,8 @@ aia --fuzzy
|
|
|
296
298
|
| Option | Description | Example |
|
|
297
299
|
|--------|-------------|---------|
|
|
298
300
|
| `--chat` | Start interactive chat session | `aia --chat` |
|
|
299
|
-
| `--model MODEL` | Specify AI model(s) to use. Supports `MODEL[=ROLE]` syntax | `aia --model gpt-4o-mini,gpt-3.5-turbo` or `aia --model gpt-4o=architect,claude=security` |
|
|
301
|
+
| `--model MODEL` | Specify AI model(s) to use. Supports `MODEL[=ROLE]` syntax. A bare provider name (`claude_code`) means that provider's default model | `aia --model gpt-4o-mini,gpt-3.5-turbo` or `aia --model gpt-4o=architect,claude=security` |
|
|
302
|
+
| `--provider SLUG` | Provider for models named without a `provider/` prefix. Also re-points models from `AIA_MODEL` or the config file at this provider, keeping their names. Scopes `--list-models` | `aia --provider ollama -m llama3.2` |
|
|
300
303
|
| `--consensus` | Enable consensus mode for multi-model | `aia --consensus` |
|
|
301
304
|
| `--no-consensus` | Force individual responses | `aia --no-consensus` |
|
|
302
305
|
| `--role ROLE` | Use a role/system prompt (default for all models) | `aia --role expert` |
|
|
@@ -348,6 +351,8 @@ AIA determines configuration settings using this order (highest to lowest priori
|
|
|
348
351
|
|
|
349
352
|
**Note:** When `-c` / `--config-file` is used, it replaces the user config and environment variables. Configuration resets to bundled defaults, then the specified file is applied, then CLI arguments take precedence.
|
|
350
353
|
|
|
354
|
+
**`--provider` sets the provider, not the model.** Models named with `--model` and no `provider/` prefix get it. Models that came from `AIA_MODEL` or a config file get it too, replacing their own prefix but keeping their names, because the command line outranks both. So `--provider claude_code` with `AIA_MODEL=lms/qwen3.8` exported asks Claude Code for a model named `qwen3.8`. To use a provider's default model, name the provider as the model: `--model claude_code` means `claude_code/default`.
|
|
355
|
+
|
|
351
356
|
### Configuration Methods
|
|
352
357
|
|
|
353
358
|
**Environment Variables:**
|
|
@@ -964,6 +969,46 @@ The `/available_models` directive (alias: `/models`) lists all models known to t
|
|
|
964
969
|
- 📡 **Offline**: Works without internet connection
|
|
965
970
|
- 🔧 **Control**: Full control over model and parameters
|
|
966
971
|
|
|
972
|
+
### Coding Agents as Models (Claude Code, Codex, Copilot)
|
|
973
|
+
|
|
974
|
+
An agent CLI can stand in for a model. With the matching
|
|
975
|
+
`ruby_llm-providers-*` gem installed, the provider prefix sends the prompt to
|
|
976
|
+
the agent's batch mode on stdin and reads its answer back from stdout. The
|
|
977
|
+
agent keeps its own tools, settings and MCP servers and works in the current
|
|
978
|
+
directory, so any aia prompt, pipeline or multi-model run can be driven by an
|
|
979
|
+
agent that reads and edits files.
|
|
980
|
+
|
|
981
|
+
| Prefix | Gem | CLI |
|
|
982
|
+
|---|---|---|
|
|
983
|
+
| `claude_code/` | `ruby_llm-providers-claude_code` | `claude -p` |
|
|
984
|
+
| `codex/` | `ruby_llm-providers-codex` | `codex exec` |
|
|
985
|
+
| `copilot/` | `ruby_llm-providers-copilot` | `copilot` (non-interactive) |
|
|
986
|
+
|
|
987
|
+
```bash
|
|
988
|
+
gem install ruby_llm-providers-claude_code
|
|
989
|
+
|
|
990
|
+
# The part after the slash is the agent's --model; a bare prefix means its default
|
|
991
|
+
aia --model claude_code/opus refactor_prompt
|
|
992
|
+
aia --model claude_code my_prompt
|
|
993
|
+
|
|
994
|
+
# --provider alone keeps the model name from AIA_MODEL or the config file and
|
|
995
|
+
# hands it to the agent; for the agent's default model use --model as above
|
|
996
|
+
aia --provider claude_code --model sonnet my_prompt
|
|
997
|
+
|
|
998
|
+
# Chat keeps the agent's session alive between turns (--resume)
|
|
999
|
+
aia --chat --model claude_code/sonnet
|
|
1000
|
+
|
|
1001
|
+
# Cross-vendor review: one agent implements, another reviews
|
|
1002
|
+
aia --model claude_code/sonnet=implementer,codex/default=reviewer --consensus review_prompt
|
|
1003
|
+
|
|
1004
|
+
aia --list-models --provider claude_code
|
|
1005
|
+
```
|
|
1006
|
+
|
|
1007
|
+
Because the agent brings its own tools, aia's `--tools` and MCP servers are
|
|
1008
|
+
not attached to these robots (a one-line notice says so). Permissions, the
|
|
1009
|
+
working directory, timeouts and extra CLI flags are set through the gem's
|
|
1010
|
+
`RubyLLM.config.<provider>_*` options; see each gem's README.
|
|
1011
|
+
|
|
967
1012
|
### Shell Integration
|
|
968
1013
|
|
|
969
1014
|
AIA automatically processes shell patterns in prompts:
|
|
@@ -1393,18 +1438,18 @@ mcp_servers:
|
|
|
1393
1438
|
|
|
1394
1439
|
#### Verifying MCP Server Configuration
|
|
1395
1440
|
|
|
1396
|
-
When MCP servers are configured, AIA
|
|
1441
|
+
When MCP servers are configured, AIA lists them in the startup robot with each server's tool count in parentheses. Servers that failed to connect are named after `FAILED:`:
|
|
1397
1442
|
|
|
1398
1443
|
```
|
|
1399
|
-
, , AIA v2.
|
|
1444
|
+
, , AIA v2.1.0 is Online
|
|
1400
1445
|
(\____/)
|
|
1401
|
-
(_oo_) Models:
|
|
1402
|
-
(O) DB: refreshed 2026-
|
|
1403
|
-
__|||__ \) Libs: ruby_llm v2.1.1, robot_lab v0.
|
|
1404
|
-
[/ Tobor \] /
|
|
1405
|
-
/ \_______/ \/
|
|
1406
|
-
/ /___\
|
|
1407
|
-
(\ /_____\
|
|
1446
|
+
(_oo_) Models: claude-sonnet-4-6
|
|
1447
|
+
(O) DB: refreshed 2026-11-01 at 22:28
|
|
1448
|
+
__|||__ \) Libs: ruby_llm v2.1.1, robot_lab v0.6.0, simple_flow v0.4.0, trak_flow v0.2.0, typed_bus v0.0.1
|
|
1449
|
+
[/ Tobor \] / Tools: 109 tools loaded
|
|
1450
|
+
/ \_______/ \/ MCP: github(42), brew(14), redis(53) | FAILED: htm
|
|
1451
|
+
/ /___\ Crew: @tobor
|
|
1452
|
+
(\ /_____\
|
|
1408
1453
|
::: :::
|
|
1409
1454
|
::: :::
|
|
1410
1455
|
|
|
@@ -99,8 +99,9 @@ module AIA
|
|
|
99
99
|
end
|
|
100
100
|
|
|
101
101
|
opts.on('--provider SLUG',
|
|
102
|
-
'
|
|
103
|
-
'
|
|
102
|
+
'Provider for models given without a provider/ prefix; also re-points ' \
|
|
103
|
+
'models from AIA_MODEL or the config file at it, keeping their names. ' \
|
|
104
|
+
'Scopes --list-models (any RubyLLM-registered provider)') do |slug|
|
|
104
105
|
options[:provider] = slug
|
|
105
106
|
end
|
|
106
107
|
|
|
@@ -13,6 +13,10 @@
|
|
|
13
13
|
|
|
14
14
|
module AIA
|
|
15
15
|
class ModelSpec
|
|
16
|
+
# The model id used when a bare provider name is given (e.g. `claude_code`):
|
|
17
|
+
# the provider's own default model.
|
|
18
|
+
DEFAULT_MODEL = 'default'
|
|
19
|
+
|
|
16
20
|
attr_accessor :name, :role, :instance, :internal_id, :provider
|
|
17
21
|
|
|
18
22
|
def initialize(hash = {})
|
|
@@ -76,18 +80,23 @@ module AIA
|
|
|
76
80
|
|
|
77
81
|
private
|
|
78
82
|
|
|
79
|
-
# Extract a provider
|
|
80
|
-
#
|
|
83
|
+
# Extract a provider from the model name. "<provider>/<model-id>" splits
|
|
84
|
+
# on the slash; a bare "<provider>" with no slash names that provider's
|
|
85
|
+
# DEFAULT_MODEL, which is how agent-CLI providers such as claude_code,
|
|
86
|
+
# codex and copilot are usually given. The prefix is a provider exactly
|
|
87
|
+
# when RubyLLM knows it (registered already, or loadable as a
|
|
81
88
|
# conventional ruby_llm-providers-<prefix> gem) — no provider names are
|
|
82
89
|
# hardcoded here. Names whose first segment is not a provider (registry
|
|
83
|
-
# ids like "meta-llama/llama-4-maverick") pass
|
|
90
|
+
# ids like "meta-llama/llama-4-maverick", plain ids like "gpt-4o") pass
|
|
91
|
+
# through untouched.
|
|
84
92
|
def extract_provider_from_name!
|
|
85
|
-
return
|
|
93
|
+
return if @name.nil?
|
|
86
94
|
|
|
87
95
|
prefix, rest = @name.split('/', 2)
|
|
88
96
|
return unless ProviderRegistry.available?(prefix)
|
|
97
|
+
|
|
89
98
|
@provider = prefix
|
|
90
|
-
@name = rest
|
|
99
|
+
@name = rest || DEFAULT_MODEL
|
|
91
100
|
end
|
|
92
101
|
end
|
|
93
102
|
end
|
data/lib/aia/config.rb
CHANGED
|
@@ -227,7 +227,7 @@ module AIA
|
|
|
227
227
|
apply_models_env_var unless overrides[:models]
|
|
228
228
|
apply_plugins_dir_env_var unless overrides[:plugins_dir]
|
|
229
229
|
apply_overrides(overrides) if overrides && !overrides.empty?
|
|
230
|
-
|
|
230
|
+
apply_cli_provider(overrides.key?(:models) ? :fill : :replace)
|
|
231
231
|
expand_paths
|
|
232
232
|
process_mcp_files(overrides[:mcp_files]) if overrides[:mcp_files]
|
|
233
233
|
end
|
|
@@ -382,13 +382,22 @@ module AIA
|
|
|
382
382
|
end
|
|
383
383
|
end
|
|
384
384
|
|
|
385
|
-
# `--provider SLUG`
|
|
386
|
-
#
|
|
387
|
-
|
|
385
|
+
# `--provider SLUG` on the command line. Given together with --model
|
|
386
|
+
# (+mode+ :fill), it is the provider for the models named there without
|
|
387
|
+
# a "<provider>/" prefix; an explicit prefix keeps its own provider,
|
|
388
|
+
# since both values come from the command line. Given without --model
|
|
389
|
+
# (+mode+ :replace), the models from AIA_MODEL or the config file keep
|
|
390
|
+
# their names but take this provider, prefix or not, because a
|
|
391
|
+
# command-line flag outranks both.
|
|
392
|
+
#
|
|
393
|
+
# @param mode [Symbol] :fill or :replace
|
|
394
|
+
def apply_cli_provider(mode)
|
|
388
395
|
return if provider.nil? || provider.to_s.empty?
|
|
389
396
|
|
|
390
397
|
Array(models).each do |spec|
|
|
391
|
-
|
|
398
|
+
next unless spec.respond_to?(:provider)
|
|
399
|
+
|
|
400
|
+
spec.provider = provider if mode == :replace || spec.provider.nil?
|
|
392
401
|
end
|
|
393
402
|
end
|
|
394
403
|
|
data/lib/aia/delegate_handler.rb
CHANGED
data/lib/aia/errors.rb
CHANGED
|
@@ -36,4 +36,8 @@ module AIA
|
|
|
36
36
|
|
|
37
37
|
# Raised when all sub-tasks fail in SpecialModeHandler decompose mode
|
|
38
38
|
class DecomposeError < Error; end
|
|
39
|
+
|
|
40
|
+
# Raised when a robot's LLM call fails during a batch (non-chat) pipeline
|
|
41
|
+
# step; robot_lab shields the exception into reply text, this surfaces it
|
|
42
|
+
class LLMError < Error; end
|
|
39
43
|
end
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# lib/aia/llm_error_collector.rb
|
|
4
|
+
#
|
|
5
|
+
# A robot_lab hook that remembers the exceptions robots raise while a
|
|
6
|
+
# pipeline step runs. robot_lab's Network shields a robot's exception into
|
|
7
|
+
# an "Error: ..." reply so one failing robot cannot crash the network, which
|
|
8
|
+
# also hides the failure from aia: a batch run would print the error as the
|
|
9
|
+
# answer and exit 0. The on_error hook fires before the shield, so the
|
|
10
|
+
# PipelineOrchestrator can ask afterwards whether the step really failed.
|
|
11
|
+
|
|
12
|
+
module AIA
|
|
13
|
+
class LLMErrorCollector < RobotLab::Hook
|
|
14
|
+
Entry = Data.define(:robot_name, :error) do
|
|
15
|
+
def to_s
|
|
16
|
+
prefix = robot_name.empty? ? '' : "#{robot_name}: "
|
|
17
|
+
"#{prefix}#{error.class}: #{error.message}"
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
@errors = []
|
|
22
|
+
@mutex = Mutex.new
|
|
23
|
+
|
|
24
|
+
class << self
|
|
25
|
+
# Register the collector on +registry+ once. robot_lab's global
|
|
26
|
+
# registry (the default) is consulted by every Robot#run, including
|
|
27
|
+
# the robots a Network runs in parallel threads.
|
|
28
|
+
#
|
|
29
|
+
# @param registry [RobotLab::HookRegistry]
|
|
30
|
+
def install!(registry = RobotLab.hooks)
|
|
31
|
+
return if registry.registrations.any? { |reg| reg.handler_class == self }
|
|
32
|
+
|
|
33
|
+
registry.on(self)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# robot_lab hook: a robot run raised +ctx.error+.
|
|
37
|
+
#
|
|
38
|
+
# @param ctx [RobotLab::RunHookContext]
|
|
39
|
+
def on_error(ctx)
|
|
40
|
+
robot_name = ctx.respond_to?(:robot) ? ctx.robot&.name.to_s : ''
|
|
41
|
+
@mutex.synchronize { @errors << Entry.new(robot_name: robot_name, error: ctx.error) }
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Forget the errors of the previous step.
|
|
45
|
+
def reset!
|
|
46
|
+
@mutex.synchronize { @errors.clear }
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# @return [Array<Entry>] the errors recorded since the last reset!
|
|
50
|
+
def errors
|
|
51
|
+
@mutex.synchronize { @errors.dup }
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def errors?
|
|
55
|
+
!errors.empty?
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# One line naming the prompt and every distinct error it hit.
|
|
59
|
+
#
|
|
60
|
+
# @param prompt_id [String]
|
|
61
|
+
# @return [String]
|
|
62
|
+
def message(prompt_id)
|
|
63
|
+
"LLM error in prompt '#{prompt_id}': #{errors.map(&:to_s).uniq.join('; ')}"
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
@@ -38,6 +38,8 @@ module AIA
|
|
|
38
38
|
bridge = config.flags.track_pipeline ? TrakFlowBridge.new : nil
|
|
39
39
|
bridge&.create_plan_from_pipeline(config.pipeline)
|
|
40
40
|
|
|
41
|
+
LLMErrorCollector.install!
|
|
42
|
+
|
|
41
43
|
until config.pipeline.empty?
|
|
42
44
|
prompt_id = config.pipeline.shift
|
|
43
45
|
next if prompt_id.nil? || prompt_id.empty?
|
|
@@ -69,7 +71,15 @@ module AIA
|
|
|
69
71
|
# Front matter may have changed the model or its settings
|
|
70
72
|
@robot = @robot_sync.call(@robot) if @robot_sync
|
|
71
73
|
|
|
74
|
+
LLMErrorCollector.reset!
|
|
75
|
+
if special_mode_handled?(prompt_text)
|
|
76
|
+
bridge&.update_step_status(prompt_id, :completed) unless llm_errors_handled?(prompt_id, bridge)
|
|
77
|
+
return
|
|
78
|
+
end
|
|
79
|
+
|
|
72
80
|
result, content = compute_result(prompt_text, config)
|
|
81
|
+
return if llm_errors_handled?(prompt_id, bridge)
|
|
82
|
+
|
|
73
83
|
bridge&.update_step_status(prompt_id, :completed)
|
|
74
84
|
|
|
75
85
|
@tracker.record_turn(model: config.models.first.name, input: prompt_text, result: result)
|
|
@@ -79,6 +89,46 @@ module AIA
|
|
|
79
89
|
raise
|
|
80
90
|
end
|
|
81
91
|
|
|
92
|
+
# robot_lab shields a robot's exception into an "Error: ..." reply, so a
|
|
93
|
+
# failed LLM call comes back looking like an answer. The collector hook
|
|
94
|
+
# saw the real exception. Outside chat the step fails and aia exits 1
|
|
95
|
+
# (see AIA.run); in a chat session the error is shown and the session
|
|
96
|
+
# carries on. True when the step failed.
|
|
97
|
+
def llm_errors_handled?(prompt_id, bridge)
|
|
98
|
+
return false unless LLMErrorCollector.errors?
|
|
99
|
+
|
|
100
|
+
message = LLMErrorCollector.message(prompt_id)
|
|
101
|
+
raise AIA::LLMError, message unless AIA.chat?
|
|
102
|
+
|
|
103
|
+
@ui.display_info(message)
|
|
104
|
+
@ui.display_separator
|
|
105
|
+
bridge&.update_step_status(prompt_id, :failed, reason: message)
|
|
106
|
+
true
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# A directive in the prompt (/debate, /verify, /decompose, /delegate,
|
|
110
|
+
# /spawn, /orchestrate) asked for a special mode: hand the turn to the
|
|
111
|
+
# SpecialModeHandler, as ChatLoop does. True when it ran the turn, which
|
|
112
|
+
# includes displaying, saving and recording it. Concurrent MCP is left
|
|
113
|
+
# to execute_prompt, which honors it alongside config.concurrency.auto.
|
|
114
|
+
# A --paint step has no robot turn to hand over.
|
|
115
|
+
def special_mode_handled?(prompt_text)
|
|
116
|
+
return false if AIA.paint? || !special_mode_requested?
|
|
117
|
+
|
|
118
|
+
special_mode_handler.robot = @robot
|
|
119
|
+
special_mode_handler.handle(prompt_text)
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
# True when the turn state holds a mode for SpecialModeHandler to run.
|
|
123
|
+
def special_mode_requested?
|
|
124
|
+
mode = AIA.turn_state.active_mode
|
|
125
|
+
!mode.nil? && mode != :concurrent_mcp
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def special_mode_handler
|
|
129
|
+
@special_mode_handler ||= SpecialModeHandler.new(robot: @robot, ui_presenter: @ui, tracker: @tracker)
|
|
130
|
+
end
|
|
131
|
+
|
|
82
132
|
# Show a step's response, then save and speak it. A --paint step saved
|
|
83
133
|
# an image next to the output file, so there is no text to keep or speak.
|
|
84
134
|
def present_result(content, result, config)
|
|
@@ -108,16 +158,16 @@ module AIA
|
|
|
108
158
|
img_cfg = config.image
|
|
109
159
|
quality = img_cfg.quality
|
|
110
160
|
style = img_cfg.style
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
161
|
+
provider_options = {}
|
|
162
|
+
provider_options[:quality] = quality if quality && !quality.to_s.strip.empty?
|
|
163
|
+
provider_options[:style] = style if style && !style.to_s.strip.empty?
|
|
114
164
|
|
|
115
165
|
image = @ui.with_spinner("Generating image") do
|
|
116
166
|
RubyLLM.paint(
|
|
117
167
|
prompt_text,
|
|
118
|
-
model:
|
|
119
|
-
size:
|
|
120
|
-
|
|
168
|
+
model: img_cfg.model || 'gpt-image-1',
|
|
169
|
+
size: img_cfg.size || '1024x1024',
|
|
170
|
+
provider_options:
|
|
121
171
|
)
|
|
122
172
|
end
|
|
123
173
|
|
data/lib/aia/prompt_handler.rb
CHANGED
|
@@ -22,6 +22,9 @@ module AIA
|
|
|
22
22
|
'erb' => [%w[config erb], %w[config flags erb]]
|
|
23
23
|
}.freeze
|
|
24
24
|
|
|
25
|
+
# Front matter `mode:` names that differ from their TurnState mode.
|
|
26
|
+
MODE_SHORTHANDS = { 'concurrent' => :concurrent_mcp }.freeze
|
|
27
|
+
|
|
25
28
|
def initialize
|
|
26
29
|
@prompts_dir = AIA.config.prompts.dir
|
|
27
30
|
|
|
@@ -36,6 +39,22 @@ module AIA
|
|
|
36
39
|
register_pm_directives
|
|
37
40
|
end
|
|
38
41
|
|
|
42
|
+
# The TurnState mode a front matter `mode:` +value+ names: a chat
|
|
43
|
+
# directive's name without the slash (debate, verify, decompose,
|
|
44
|
+
# delegate, spawn, orchestrate, concurrent).
|
|
45
|
+
#
|
|
46
|
+
# @param value [String, Symbol]
|
|
47
|
+
# @return [Symbol] one of TurnState::EXCLUSIVE_MODES
|
|
48
|
+
# @raise [ConfigurationError] for a name that is not a mode
|
|
49
|
+
def self.mode_for(value)
|
|
50
|
+
name = value.to_s.strip.downcase
|
|
51
|
+
mode = MODE_SHORTHANDS.fetch(name, name.to_sym)
|
|
52
|
+
return mode if TurnState::EXCLUSIVE_MODES.include?(mode)
|
|
53
|
+
|
|
54
|
+
names = (TurnState::EXCLUSIVE_MODES - MODE_SHORTHANDS.values).map(&:to_s) + MODE_SHORTHANDS.keys
|
|
55
|
+
raise ConfigurationError, "Unknown mode: #{value.inspect} (one of #{names.sort.join(', ')})"
|
|
56
|
+
end
|
|
57
|
+
|
|
39
58
|
# A shell/erb flag is on unless it is explicitly false.
|
|
40
59
|
#
|
|
41
60
|
# @param flags [#shell, #erb, nil]
|
|
@@ -212,6 +231,11 @@ module AIA
|
|
|
212
231
|
|
|
213
232
|
erb_val = shorthand(meta_hash, :erb)
|
|
214
233
|
cfg.flags.erb = erb_val unless erb_val.nil?
|
|
234
|
+
|
|
235
|
+
# mode → the special mode for this prompt's turn, as the chat
|
|
236
|
+
# directive of that name (/debate, /verify, ...) would request it
|
|
237
|
+
mode_val = shorthand(meta_hash, :mode)
|
|
238
|
+
AIA.turn_state.request(self.class.mode_for(mode_val)) if mode_val
|
|
215
239
|
end
|
|
216
240
|
|
|
217
241
|
# Fetch a front-matter shorthand value by string or symbol key.
|
|
@@ -37,7 +37,9 @@ module AIA
|
|
|
37
37
|
# Attempt to require the conventional gem path for a provider slug.
|
|
38
38
|
# Returns true when the provider ends up registered. Failed lookups are
|
|
39
39
|
# cached so repeated non-provider prefixes (model ids also use "/")
|
|
40
|
-
# don't pay the require cost every time.
|
|
40
|
+
# don't pay the require cost every time. When the plain require fails
|
|
41
|
+
# because aia runs under Bundler and the gem is installed but not in the
|
|
42
|
+
# Gemfile, the gem is sideloaded from the RubyGems search path.
|
|
41
43
|
def load(slug)
|
|
42
44
|
slug = slug.to_s
|
|
43
45
|
return false unless slug.match?(/\A[a-z0-9_]+\z/)
|
|
@@ -50,22 +52,71 @@ module AIA
|
|
|
50
52
|
require "ruby_llm/providers/#{slug}"
|
|
51
53
|
registered?(slug)
|
|
52
54
|
rescue LoadError
|
|
53
|
-
|
|
55
|
+
sideload(slug)
|
|
54
56
|
end
|
|
55
57
|
end
|
|
56
58
|
|
|
59
|
+
# Load an installed `ruby_llm-providers-<slug>` gem that the active
|
|
60
|
+
# bundle hides. Under Bundler only the Gemfile's gems can be required,
|
|
61
|
+
# so a provider gem added with `gem install` is invisible to a plain
|
|
62
|
+
# require even though it sits on disk. This finds its gemspec on the
|
|
63
|
+
# RubyGems search path and, when every runtime dependency it declares is
|
|
64
|
+
# already satisfied by the bundle, adds its lib directory to the load
|
|
65
|
+
# path and requires it. The bundle itself is not changed. Returns true
|
|
66
|
+
# when the provider ends up registered.
|
|
67
|
+
def sideload(slug)
|
|
68
|
+
spec = installed_spec(slug)
|
|
69
|
+
return false unless spec
|
|
70
|
+
|
|
71
|
+
unmet = spec.runtime_dependencies.reject { |dep| dependency_met?(dep) }
|
|
72
|
+
unless unmet.empty?
|
|
73
|
+
AIA.debug_warn("#{spec.full_name} is installed but needs #{unmet.join(', ')}, which this bundle does not provide")
|
|
74
|
+
return false
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
spec.full_require_paths.each { |dir| $LOAD_PATH.unshift(dir) unless $LOAD_PATH.include?(dir) }
|
|
78
|
+
require "ruby_llm/providers/#{slug}"
|
|
79
|
+
registered?(slug)
|
|
80
|
+
rescue LoadError
|
|
81
|
+
false
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# The newest installed gemspec for `ruby_llm-providers-<slug>`, read from
|
|
85
|
+
# the specifications directories on the RubyGems search path, or nil.
|
|
86
|
+
# Reads the files directly, so it sees gems the bundle does not.
|
|
87
|
+
def installed_spec(slug)
|
|
88
|
+
name = "ruby_llm-providers-#{slug}"
|
|
89
|
+
Gem.path
|
|
90
|
+
.flat_map { |dir| Dir[File.join(dir, 'specifications', "#{name}-*.gemspec")] }
|
|
91
|
+
.filter_map { |file| Gem::Specification.load(file) }
|
|
92
|
+
.select { |spec| spec.name == name }
|
|
93
|
+
.max_by(&:version)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# Whether a gem dependency is satisfied by a gem already active in this
|
|
97
|
+
# process (under Bundler, that is the bundle).
|
|
98
|
+
def dependency_met?(dep)
|
|
99
|
+
active = Gem.loaded_specs[dep.name]
|
|
100
|
+
!active.nil? && dep.requirement.satisfied_by?(active.version)
|
|
101
|
+
end
|
|
102
|
+
|
|
57
103
|
# A provider instance ready for API calls (model listing etc.).
|
|
58
104
|
# Raises RubyLLM's own errors for unknown or unconfigured providers.
|
|
59
105
|
def instantiate(slug)
|
|
60
106
|
RubyLLM::Provider.resolve!(slug.to_sym).new(RubyLLM.config)
|
|
61
107
|
end
|
|
62
108
|
|
|
63
|
-
# Slugs of conventionally named provider gems
|
|
64
|
-
#
|
|
109
|
+
# Slugs of conventionally named provider gems (ruby_llm-providers-<slug>)
|
|
110
|
+
# that are installed, whether in the bundle or only on the RubyGems
|
|
111
|
+
# search path, and whether or not they are loaded yet.
|
|
65
112
|
def installed_gem_slugs
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
113
|
+
prefix = 'ruby_llm-providers-'
|
|
114
|
+
bundled = Gem::Specification.map(&:name)
|
|
115
|
+
on_disk = Gem.path.flat_map { |dir| Dir[File.join(dir, 'specifications', "#{prefix}*.gemspec")] }
|
|
116
|
+
.map { |file| File.basename(file, '.gemspec').sub(/-[^-]+\z/, '') }
|
|
117
|
+
(bundled + on_disk).select { |name| name.start_with?(prefix) }
|
|
118
|
+
.map { |name| name.delete_prefix(prefix) }
|
|
119
|
+
.uniq
|
|
69
120
|
end
|
|
70
121
|
|
|
71
122
|
# Register every installed conventional provider gem, so a full listing
|
data/lib/aia/robot_factory.rb
CHANGED
|
@@ -243,9 +243,49 @@ module AIA
|
|
|
243
243
|
# @return [RobotLab::Robot]
|
|
244
244
|
def build_robot(spec, **opts)
|
|
245
245
|
opts[:provider] = resolve_provider(spec) if spec.provider
|
|
246
|
+
opts = without_tools(spec, opts) unless provider_accepts_tools?(spec.provider)
|
|
246
247
|
RobotLab.build(model: spec.name, **opts)
|
|
247
248
|
end
|
|
248
249
|
|
|
250
|
+
# Whether a provider can take RubyLLM tools. Agent-CLI providers
|
|
251
|
+
# (claude_code, codex, copilot) run their own tools and say so with a
|
|
252
|
+
# class-level `accepts_tools?` returning false; every other provider
|
|
253
|
+
# accepts tools. Nothing is hardcoded here — the provider class decides.
|
|
254
|
+
#
|
|
255
|
+
# @param provider [String, nil] a RubyLLM provider slug
|
|
256
|
+
# @return [Boolean]
|
|
257
|
+
def provider_accepts_tools?(provider)
|
|
258
|
+
klass = provider && ProviderRegistry.providers[provider.to_s]
|
|
259
|
+
return true unless klass.respond_to?(:accepts_tools?)
|
|
260
|
+
|
|
261
|
+
klass.accepts_tools?
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
# Strip the tools and MCP servers from a robot's build options for a
|
|
265
|
+
# provider that brings its own, telling the user once per provider what
|
|
266
|
+
# was left out so a `--tools` or `--mcp-use` that silently did nothing
|
|
267
|
+
# is not a mystery.
|
|
268
|
+
#
|
|
269
|
+
# @param spec [AIA::ModelSpec]
|
|
270
|
+
# @param opts [Hash] RobotLab.build options
|
|
271
|
+
# @return [Hash] opts with empty local_tools: and mcp:
|
|
272
|
+
def without_tools(spec, opts)
|
|
273
|
+
dropped = []
|
|
274
|
+
dropped << 'tools' if opts[:local_tools]&.any?
|
|
275
|
+
dropped << 'MCP servers' if opts[:mcp]&.any?
|
|
276
|
+
notice_tools_dropped(spec.provider, dropped) unless dropped.empty?
|
|
277
|
+
opts.merge(local_tools: [], mcp: [])
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
# One notice per provider per process.
|
|
281
|
+
def notice_tools_dropped(provider, dropped)
|
|
282
|
+
@tools_dropped_notices ||= {}
|
|
283
|
+
return if @tools_dropped_notices[provider]
|
|
284
|
+
|
|
285
|
+
@tools_dropped_notices[provider] = true
|
|
286
|
+
AIA.debug_warn("#{provider} runs its own tools; aia #{dropped.join(' and ')} are not attached to it")
|
|
287
|
+
end
|
|
288
|
+
|
|
249
289
|
# Resolve a spec's provider to a RubyLLM provider slug. Slugs pass
|
|
250
290
|
# through unchanged — RubyLLM's registry is the single source of truth —
|
|
251
291
|
# but the method stays as the seam where optional provider gems get
|
|
@@ -265,10 +305,23 @@ module AIA
|
|
|
265
305
|
|
|
266
306
|
AIA.debug_warn(
|
|
267
307
|
"provider '#{provider}' is not registered with RubyLLM and no " \
|
|
268
|
-
"ruby_llm/providers/#{provider} library could be loaded"
|
|
308
|
+
"ruby_llm/providers/#{provider} library could be loaded#{bundler_hint(provider)}"
|
|
269
309
|
)
|
|
270
310
|
end
|
|
271
311
|
|
|
312
|
+
# Under Bundler only the gems in the Gemfile can be required, so a
|
|
313
|
+
# provider gem installed with `gem install` stays invisible. Name the
|
|
314
|
+
# Gemfile to add it to; outside Bundler there is nothing to add.
|
|
315
|
+
#
|
|
316
|
+
# @param provider [String] a provider slug
|
|
317
|
+
# @param gemfile [String, nil] the active Gemfile; nil when not under Bundler
|
|
318
|
+
# @return [String] text to append to the warning, "" outside Bundler
|
|
319
|
+
def bundler_hint(provider, gemfile = ENV.fetch('BUNDLE_GEMFILE', nil))
|
|
320
|
+
return '' if gemfile.nil? || gemfile.empty?
|
|
321
|
+
|
|
322
|
+
"; aia is running under Bundler, so add gem 'ruby_llm-providers-#{provider}' to #{gemfile}"
|
|
323
|
+
end
|
|
324
|
+
|
|
272
325
|
private
|
|
273
326
|
|
|
274
327
|
# Configure RobotLab providers from AIA config
|
|
@@ -253,8 +253,6 @@ module AIA
|
|
|
253
253
|
def delegate_handler
|
|
254
254
|
@delegate_handler ||= begin
|
|
255
255
|
require_relative 'delegate_handler'
|
|
256
|
-
require_relative 'task_decomposer'
|
|
257
|
-
require_relative 'task_executor'
|
|
258
256
|
DelegateHandler.new(
|
|
259
257
|
robot: @robot, ui_presenter: @ui_presenter,
|
|
260
258
|
tracker: @tracker, task_coordinator: AIA.task_coordinator
|
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
# with full TaskBoardTool access. Foreman is built on first use
|
|
8
8
|
# and cached for the session.
|
|
9
9
|
|
|
10
|
+
require_relative 'task_board_tool'
|
|
11
|
+
|
|
10
12
|
module AIA
|
|
11
13
|
class DelegateToForemanTool < RubyLLM::Tool
|
|
12
14
|
description "Delegate a task management request to Foreman, the task board manager. " \
|
data/lib/aia/version.rb
CHANGED
data/lib/aia.rb
CHANGED
|
@@ -73,6 +73,7 @@ require_relative 'aia/mention_router'
|
|
|
73
73
|
require_relative 'aia/special_mode_handler'
|
|
74
74
|
require_relative 'aia/mcp_connection_manager'
|
|
75
75
|
require_relative 'aia/startup_coordinator'
|
|
76
|
+
require_relative 'aia/llm_error_collector'
|
|
76
77
|
require_relative 'aia/pipeline_orchestrator'
|
|
77
78
|
require_relative 'aia/chat_loop'
|
|
78
79
|
require_relative 'aia/session'
|
|
@@ -185,16 +186,23 @@ module AIA
|
|
|
185
186
|
RobotFactory.setup(@config)
|
|
186
187
|
load_fzf_integration
|
|
187
188
|
start_session
|
|
188
|
-
rescue AIA::ConfigurationError => e
|
|
189
|
-
$stderr.puts e.message
|
|
190
|
-
exit 1
|
|
191
189
|
rescue AIA::Error => e
|
|
192
|
-
|
|
193
|
-
|
|
190
|
+
fail_run(e.message)
|
|
191
|
+
rescue RubyLLM::Error, RubyLLM::ConfigurationError => e
|
|
192
|
+
# An LLM failure that nothing shielded (image generation, provider setup)
|
|
193
|
+
fail_run("LLM error: #{e.class}: #{e.message}")
|
|
194
194
|
end
|
|
195
195
|
|
|
196
196
|
private
|
|
197
197
|
|
|
198
|
+
# Print a one-line fatal error to stderr and exit 1.
|
|
199
|
+
#
|
|
200
|
+
# @param message [String]
|
|
201
|
+
def fail_run(message)
|
|
202
|
+
$stderr.puts message
|
|
203
|
+
exit 1
|
|
204
|
+
end
|
|
205
|
+
|
|
198
206
|
# Record startup in all three log files. Only aia.log gets the full
|
|
199
207
|
# configuration dump; llm.log and mcp.log just note that AIA started,
|
|
200
208
|
# since their configuration is already covered by the aia.log entry.
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: aia
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.0
|
|
4
|
+
version: 2.1.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Dewayne VanHoozer
|
|
@@ -331,6 +331,20 @@ dependencies:
|
|
|
331
331
|
- - ">="
|
|
332
332
|
- !ruby/object:Gem::Version
|
|
333
333
|
version: '0'
|
|
334
|
+
- !ruby/object:Gem::Dependency
|
|
335
|
+
name: ostruct
|
|
336
|
+
requirement: !ruby/object:Gem::Requirement
|
|
337
|
+
requirements:
|
|
338
|
+
- - ">="
|
|
339
|
+
- !ruby/object:Gem::Version
|
|
340
|
+
version: '0'
|
|
341
|
+
type: :development
|
|
342
|
+
prerelease: false
|
|
343
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
344
|
+
requirements:
|
|
345
|
+
- - ">="
|
|
346
|
+
- !ruby/object:Gem::Version
|
|
347
|
+
version: '0'
|
|
334
348
|
- !ruby/object:Gem::Dependency
|
|
335
349
|
name: rake
|
|
336
350
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -401,16 +415,17 @@ dependencies:
|
|
|
401
415
|
- - ">="
|
|
402
416
|
- !ruby/object:Gem::Version
|
|
403
417
|
version: '0'
|
|
404
|
-
description:
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
individual outputs side-by-side. With dynamic prompt management, embedded directives,
|
|
410
|
-
shell and Ruby integration, interactive chats, and comprehensive history tracking,
|
|
411
|
-
AIA transforms how you interact with AI.
|
|
418
|
+
description: |
|
|
419
|
+
AIA runs large language models from the terminal. Prompts are Markdown files with YAML front matter: parameters
|
|
420
|
+
that AIA asks for, directives such as /include and /shell, ERB and shell expansion, and keys that pick the model,
|
|
421
|
+
temperature or a special mode. Run a prompt once, chain prompts into a pipeline, make a prompt file executable,
|
|
422
|
+
or open an interactive chat with history, checkpoints and skills.
|
|
412
423
|
|
|
413
|
-
|
|
424
|
+
Every session is a crew of robots built on robot_lab. Name several models to compare them side by side, ask for a
|
|
425
|
+
consensus or a debate, have two independent answers reconciled with /verify, or decompose and delegate work to
|
|
426
|
+
specialists. Robots use RubyLLM tools and MCP servers through ruby_llm 2.1's built-in client, with per-tool
|
|
427
|
+
approval and automatic tool filtering. Any provider RubyLLM registers can be used, local or remote, plus optional
|
|
428
|
+
ruby_llm-providers-* gems that run Claude Code, Codex or GitHub Copilot as models. Requires Ruby 4.0.9 or newer.
|
|
414
429
|
email:
|
|
415
430
|
- dvanhoozer@gmail.com
|
|
416
431
|
executables:
|
|
@@ -456,6 +471,7 @@ files:
|
|
|
456
471
|
- lib/aia/history_transfer.rb
|
|
457
472
|
- lib/aia/input_collector.rb
|
|
458
473
|
- lib/aia/layered_orchestrator.rb
|
|
474
|
+
- lib/aia/llm_error_collector.rb
|
|
459
475
|
- lib/aia/logger.rb
|
|
460
476
|
- lib/aia/mcp_config_normalizer.rb
|
|
461
477
|
- lib/aia/mcp_connection_manager.rb
|
|
@@ -533,12 +549,14 @@ metadata:
|
|
|
533
549
|
post_install_message: |2+
|
|
534
550
|
|
|
535
551
|
╔══════════════════════════════════════════════════════════════╗
|
|
536
|
-
║
|
|
552
|
+
║ AIA — AI Assistant v2.1.0 ║
|
|
537
553
|
║ ║
|
|
538
|
-
║
|
|
554
|
+
║ Prompts as Markdown, crews of robots, MCP servers, and ║
|
|
555
|
+
║ any RubyLLM provider, including coding-agent CLIs. ║
|
|
539
556
|
╚══════════════════════════════════════════════════════════════╝
|
|
540
557
|
|
|
541
558
|
Get started: aia --help
|
|
559
|
+
What is new: https://github.com/MadBomber/aia/blob/main/CHANGELOG.md
|
|
542
560
|
Full docs: https://madbomber.github.io/aia
|
|
543
561
|
|
|
544
562
|
rdoc_options: []
|
|
@@ -557,7 +575,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
557
575
|
requirements: []
|
|
558
576
|
rubygems_version: 4.0.23
|
|
559
577
|
specification_version: 4
|
|
560
|
-
summary:
|
|
561
|
-
|
|
578
|
+
summary: 'Command-line AI assistant: Markdown prompts with directives, ERB and shell,
|
|
579
|
+
chat with crews of robots, MCP servers, and any RubyLLM provider including coding-agent
|
|
580
|
+
CLIs.'
|
|
562
581
|
test_files: []
|
|
563
582
|
...
|