Skip to content

Commit 34ec768

Browse files
committed
Implement glob pattern support for file path matching in A2uiCatalog and enable corresponding conformance tests
1 parent c3d87c3 commit 34ec768

2 files changed

Lines changed: 64 additions & 12 deletions

File tree

agent_sdks/cpp/src/schema/catalog.cc

Lines changed: 64 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include <sstream>
2020
#include <stdexcept>
2121
#include <algorithm>
22+
#include <regex>
2223
#include <queue>
2324
#include <set>
2425

@@ -103,18 +104,75 @@ std::string A2uiCatalog::render_as_llm_instructions() const {
103104
return ss.str();
104105
}
105106

107+
static std::string glob_to_regex(const std::string& glob) {
108+
std::string regex = "^";
109+
for (size_t i = 0; i < glob.length(); ++i) {
110+
char c = glob[i];
111+
if (c == '*') {
112+
if (i + 1 < glob.length() && glob[i+1] == '*') {
113+
regex += ".*";
114+
i++; // skip next *
115+
if (i + 1 < glob.length() && glob[i+1] == '/') {
116+
i++; // skip next /
117+
}
118+
} else {
119+
regex += "[^/]*";
120+
}
121+
} else if (c == '?') {
122+
regex += "[^/]";
123+
} else if (c == '.') {
124+
regex += "\\.";
125+
} else if (c == '[') {
126+
regex += c;
127+
if (i + 1 < glob.length() && glob[i+1] == '!') {
128+
regex += "^";
129+
i++; // skip !
130+
}
131+
} else if (c == ']') {
132+
regex += c;
133+
134+
} else {
135+
regex += c;
136+
}
137+
}
138+
regex += "$";
139+
return regex;
140+
}
141+
106142
std::string A2uiCatalog::load_examples(const std::string& path, bool validate) const {
107143
if (path.empty()) return "";
108144

109145
std::vector<std::string> matched_files;
110-
if (fs::is_directory(path)) {
111-
for (const auto& entry : fs::directory_iterator(path)) {
112-
if (entry.is_regular_file() && entry.path().extension() == ".json") {
113-
matched_files.push_back(entry.path().string());
146+
147+
size_t first_wildcard = path.find_first_of("*?[");
148+
if (first_wildcard != std::string::npos) {
149+
size_t last_slash = path.rfind('/', first_wildcard);
150+
std::string base_dir = (last_slash == std::string::npos) ? "." : path.substr(0, last_slash);
151+
std::string pattern = (last_slash == std::string::npos) ? path : path.substr(last_slash + 1);
152+
153+
std::string regex_str = glob_to_regex(pattern);
154+
std::regex pattern_regex(regex_str);
155+
156+
if (fs::exists(base_dir) && fs::is_directory(base_dir)) {
157+
for (const auto& entry : fs::recursive_directory_iterator(base_dir)) {
158+
if (entry.is_regular_file()) {
159+
std::string rel_path = fs::relative(entry.path(), base_dir).string();
160+
if (std::regex_match(rel_path, pattern_regex) && entry.path().extension() == ".json") {
161+
matched_files.push_back(entry.path().string());
162+
}
163+
}
164+
}
165+
}
166+
} else {
167+
if (fs::is_directory(path)) {
168+
for (const auto& entry : fs::directory_iterator(path)) {
169+
if (entry.is_regular_file() && entry.path().extension() == ".json") {
170+
matched_files.push_back(entry.path().string());
171+
}
114172
}
173+
} else if (fs::is_regular_file(path)) {
174+
matched_files.push_back(path);
115175
}
116-
} else if (fs::is_regular_file(path)) {
117-
matched_files.push_back(path);
118176
}
119177

120178
if (matched_files.empty()) return "";

agent_sdks/cpp/tests/test_conformance.cc

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -157,12 +157,6 @@ TEST(CatalogConformanceTest, RunAll) {
157157
path = args["path"].get<std::string>();
158158
}
159159

160-
// Skip glob tests in C++ as it doesn't support them
161-
if (path.find('*') != std::string::npos || path.find('[') != std::string::npos) {
162-
std::cout << "[SKIPPED] Glob test in C++: " << name << std::endl;
163-
continue;
164-
}
165-
166160
std::string full_path = "";
167161
if (!path.empty()) {
168162
full_path = (conformance_dir / path).string();

0 commit comments

Comments
 (0)