agentf 0.4.6 → 0.5.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.
@@ -0,0 +1,211 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+ require "yaml"
5
+
6
+ module Agentf
7
+ module Evals
8
+ class Scenario
9
+ DEFAULT_TIMEOUT_SECONDS = 30
10
+
11
+ attr_reader :path, :metadata
12
+
13
+ def self.discover(root)
14
+ return [] unless Dir.exist?(root)
15
+
16
+ Dir.children(root).sort.filter_map do |entry|
17
+ scenario_dir = File.join(root, entry)
18
+ next unless File.directory?(scenario_dir)
19
+
20
+ load(scenario_dir)
21
+ rescue StandardError
22
+ nil
23
+ end
24
+ end
25
+
26
+ def self.load(path)
27
+ metadata_path = File.join(path, "scenario.yml")
28
+ metadata = File.exist?(metadata_path) ? (YAML.load_file(metadata_path) || {}) : {}
29
+ new(path: path, metadata: metadata)
30
+ end
31
+
32
+ def initialize(path:, metadata: {})
33
+ @path = path
34
+ @metadata = metadata.transform_keys(&:to_s)
35
+ end
36
+
37
+ def name
38
+ metadata.fetch("name", File.basename(path))
39
+ end
40
+
41
+ def description
42
+ metadata.fetch("description", "")
43
+ end
44
+
45
+ def execution_mode
46
+ metadata.fetch("execution_mode", "agent").to_s
47
+ end
48
+
49
+ def agent
50
+ metadata["agent"]
51
+ end
52
+
53
+ def mcp_tool
54
+ metadata["mcp_tool"]
55
+ end
56
+
57
+ def provider_name
58
+ metadata["provider"]
59
+ end
60
+
61
+ def provider_runtime_tool
62
+ metadata["provider_runtime_tool"]
63
+ end
64
+
65
+ def provider_scope
66
+ metadata.fetch("provider_scope", "local").to_s
67
+ end
68
+
69
+ def provider_install_deps?
70
+ return false unless metadata.key?("provider_install_deps")
71
+
72
+ metadata["provider_install_deps"] == true
73
+ end
74
+
75
+ def install_agents
76
+ Array(metadata["install_agents"]).map(&:to_s)
77
+ end
78
+
79
+ def install_commands
80
+ Array(metadata["install_commands"]).map(&:to_s)
81
+ end
82
+
83
+ def expected_memory_titles
84
+ Array(metadata["expected_memory_titles"]).map(&:to_s)
85
+ end
86
+
87
+ def prompt
88
+ File.read(prompt_path)
89
+ end
90
+
91
+ def prompt_payload
92
+ content = prompt.to_s
93
+ return content unless json_prompt?
94
+
95
+ JSON.parse(content)
96
+ rescue JSON::ParserError
97
+ content
98
+ end
99
+
100
+ def json_prompt?
101
+ metadata["prompt_format"].to_s == "json"
102
+ end
103
+
104
+ def prompt_path
105
+ File.join(path, "prompt.txt")
106
+ end
107
+
108
+ def setup_script_path
109
+ file = File.join(path, "setup.sh")
110
+ File.exist?(file) ? file : nil
111
+ end
112
+
113
+ def verify_script_path
114
+ file = File.join(path, "verify.sh")
115
+ File.exist?(file) ? file : nil
116
+ end
117
+
118
+ def workspace_path
119
+ file = File.join(path, "workspace")
120
+ Dir.exist?(file) ? file : nil
121
+ end
122
+
123
+ def timeout_seconds
124
+ Integer(metadata.fetch("timeout_seconds", DEFAULT_TIMEOUT_SECONDS))
125
+ rescue ArgumentError, TypeError
126
+ DEFAULT_TIMEOUT_SECONDS
127
+ end
128
+
129
+ def auto_confirm_memories?
130
+ return true unless metadata.key?("auto_confirm_memories")
131
+
132
+ metadata["auto_confirm_memories"] == true
133
+ end
134
+
135
+ def env
136
+ raw = metadata.fetch("env", {})
137
+ return {} unless raw.is_a?(Hash)
138
+
139
+ raw.transform_keys(&:to_s).transform_values(&:to_s)
140
+ end
141
+
142
+ def tags
143
+ Array(metadata["tags"]).map(&:to_s)
144
+ end
145
+
146
+ def retry_on_confirmation?
147
+ metadata["retry_on_confirmation"] == true
148
+ end
149
+
150
+ def confirmed_write_token
151
+ metadata.fetch("confirmed_write_token", "confirmed")
152
+ end
153
+
154
+ def providers
155
+ Array(metadata["providers"]).map(&:to_s)
156
+ end
157
+
158
+ def models
159
+ Array(metadata["models"]).map(&:to_s)
160
+ end
161
+
162
+ def validate!
163
+ raise ArgumentError, "Scenario missing prompt.txt: #{prompt_path}" unless File.exist?(prompt_path)
164
+ case execution_mode
165
+ when "agent"
166
+ raise ArgumentError, "Scenario missing agent in scenario.yml: #{path}" if agent.to_s.strip.empty?
167
+ when "mcp"
168
+ raise ArgumentError, "Scenario missing mcp_tool in scenario.yml: #{path}" if mcp_tool.to_s.strip.empty?
169
+ when "provider", "provider_runtime"
170
+ raise ArgumentError, "Scenario missing provider in scenario.yml: #{path}" if provider_name.to_s.strip.empty?
171
+ if execution_mode == "provider_runtime" && provider_runtime_tool.to_s.strip.empty?
172
+ raise ArgumentError, "Scenario missing provider_runtime_tool in scenario.yml: #{path}"
173
+ end
174
+ else
175
+ raise ArgumentError, "Unknown execution_mode '#{execution_mode}' for #{path}"
176
+ end
177
+ raise ArgumentError, "Scenario missing verify.sh: #{path}" unless verify_script_path
178
+ end
179
+
180
+ def to_h
181
+ {
182
+ "name" => name,
183
+ "description" => description,
184
+ "execution_mode" => execution_mode,
185
+ "agent" => agent,
186
+ "mcp_tool" => mcp_tool,
187
+ "provider" => provider_name,
188
+ "provider_runtime_tool" => provider_runtime_tool,
189
+ "provider_scope" => provider_scope,
190
+ "provider_install_deps" => provider_install_deps?,
191
+ "install_agents" => install_agents,
192
+ "install_commands" => install_commands,
193
+ "expected_memory_titles" => expected_memory_titles,
194
+ "path" => path,
195
+ "prompt_path" => prompt_path,
196
+ "setup_script_path" => setup_script_path,
197
+ "verify_script_path" => verify_script_path,
198
+ "workspace_path" => workspace_path,
199
+ "timeout_seconds" => timeout_seconds,
200
+ "auto_confirm_memories" => auto_confirm_memories?,
201
+ "retry_on_confirmation" => retry_on_confirmation?,
202
+ "confirmed_write_token" => confirmed_write_token,
203
+ "env" => env,
204
+ "tags" => tags,
205
+ "providers" => providers,
206
+ "models" => models
207
+ }
208
+ end
209
+ end
210
+ end
211
+ end