summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-03-14 10:55:38 +0200
committerPaul Buetow <paul@buetow.org>2026-03-14 10:55:38 +0200
commit8b0531bec5e9229ca41ab7bf143e319f66ed0a22 (patch)
treec705122a5d645cf77e4162a93f3bbfc56fa5c84c
parent2b4c2d4bbb47b59fb8bf7fec027efd36b1352857 (diff)
Resolve multi-word agent names in file DSLdevelop
-rw-r--r--lib/dslkeywords/file.rb38
-rw-r--r--test/lib/dslkeywords/agent_test.rb40
2 files changed, 70 insertions, 8 deletions
diff --git a/lib/dslkeywords/file.rb b/lib/dslkeywords/file.rb
index 08f8f48..1e40691 100644
--- a/lib/dslkeywords/file.rb
+++ b/lib/dslkeywords/file.rb
@@ -156,9 +156,7 @@ module RCM
attr_reader :agent_name, :prompt_name
def agent(spec = nil, prompt_name = nil)
- agent_name = normalize_agent_reference(spec)
- prompt_name = normalize_agent_reference(prompt_name)
- agent_name, prompt_name = agent_name.split(/\s+/, 2) if prompt_name.nil? && agent_name&.include?(' ')
+ agent_name, prompt_name = resolved_agent_spec(spec, prompt_name)
if agent_name.nil? || prompt_name.nil?
raise InvalidAgentSpec, 'Expected exactly one agent name and one prompt name'
@@ -218,6 +216,40 @@ module RCM
normalized.gsub(/\s+/, ' ')
end
+ def resolved_agent_spec(spec, prompt_name)
+ agent_name = normalize_agent_reference(spec)
+ prompt_name = normalize_agent_reference(prompt_name)
+ candidates = resolved_agent_candidates(agent_name, prompt_name)
+
+ return candidates.first if candidates.one?
+ raise InvalidAgentSpec, 'Ambiguous agent specification' if candidates.length > 1
+ return [agent_name, prompt_name] unless prompt_name.nil?
+ return [agent_name, nil] unless agent_name&.include?(' ')
+
+ agent_name.split(/\s+/, 2)
+ end
+
+ def resolved_agent_candidates(agent_name, prompt_name)
+ phrase = [agent_name, prompt_name].compact.join(' ')
+ parts = phrase.split(/\s+/)
+ return [] if parts.length < 2
+
+ (1...parts.length).filter_map do |index|
+ candidate_agent_name = parts[0...index].join(' ')
+ candidate_prompt_name = parts[index..].join(' ')
+ next unless definition_registered?(AgentDefinition, candidate_agent_name)
+ next unless definition_registered?(PromptDefinition, candidate_prompt_name)
+
+ [candidate_agent_name, candidate_prompt_name]
+ end
+ end
+
+ def definition_registered?(klass, name)
+ dsl.class.object(klass.id_for(name))
+ rescue klass::InvalidName
+ false
+ end
+
def evaluate_agent_processing!
raise MissingAgentInput, "File #{@file_path} does not exist for agent processing" unless ::File.file?(@file_path)
diff --git a/test/lib/dslkeywords/agent_test.rb b/test/lib/dslkeywords/agent_test.rb
index d3fc49f..b09a2ec 100644
--- a/test/lib/dslkeywords/agent_test.rb
+++ b/test/lib/dslkeywords/agent_test.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-# rubocop:disable Metrics/ClassLength, Metrics/MethodLength
+# rubocop:disable Metrics/ClassLength, Metrics/MethodLength, Metrics/AbcSize
require 'minitest/autorun'
require 'fileutils'
require 'rbconfig'
@@ -117,22 +117,52 @@ class RCMAgentTest < Minitest::Test
File.write(file_path, 'abc123')
configure_from_scratch do
- agent 'reverse via file' do
+ agent reverse via file do
command
end
- prompt 'no op' do
+ prompt no op do
''
end
file file_path do
- agent 'reverse via file', 'no op'
+ agent reverse via file no op
end
end
assert_equal '321cba', File.read(file_path)
end
+ def test_agent_spec_raises_when_multiword_split_is_ambiguous
+ file_path = path('ambiguous.txt')
+ command = mock_agent_command(:pass_through)
+ File.write(file_path, 'hello')
+
+ assert_raises(RCM::File::InvalidAgentSpec) do
+ configure_from_scratch do
+ agent alpha do
+ command
+ end
+
+ agent alpha beta do
+ command
+ end
+
+ prompt gamma do
+ ''
+ end
+
+ prompt beta gamma do
+ ''
+ end
+
+ file file_path do
+ agent alpha beta gamma
+ end
+ end
+ end
+ end
+
def test_agent_can_use_file_path_placeholder
file_path = path('placeholder.txt')
command = mock_agent_command(:basename, 'FILE_PATH')
@@ -346,4 +376,4 @@ class RCMAgentTest < Minitest::Test
end
end
-# rubocop:enable Metrics/ClassLength, Metrics/MethodLength
+# rubocop:enable Metrics/ClassLength, Metrics/MethodLength, Metrics/AbcSize