Skip to content

Commit 134c7f1

Browse files
committed
feat(adk): align filesystem backend Path field behavior with Python glob and ls command
Enhanced the filesystem backend to align Path field behavior with Python glob patterns and standard ls command output. Also improved documentation for enhanced tool call wrapper methods. Key Changes: 1. Updated FileInfo.Path field documentation: - Changed from "absolute path only" to support filename, relative path, or absolute path - Clarified that Path value depends on the command context (Ls vs Glob) 2. Modified LsInfo implementation: - Returns only filename/directory name instead of full path - Uses filepath.Base() for file entries - Uses parts[0] for immediate children in directory listings - Behavior now matches standard ls command output 3. Enhanced GlobInfo with Python glob compatibility: - Replaced custom recursive matching with github.com/bmatcuk/doublestar/v4 library - Implemented ** (double star) support for recursive directory traversal - Added absolute pattern detection (patterns starting with /) - Absolute patterns return absolute paths; relative patterns return relative paths - Supports ** in any position: beginning, middle, or end of pattern 4. Comprehensive test coverage: - Added TestInMemoryBackend_LsInfo_PathIsFilename: validates Ls returns filenames only - Added TestInMemoryBackend_GlobInfo_RelativePath: tests relative/absolute pattern behavior - Added TestInMemoryBackend_GlobInfo_RecursivePattern: validates ** recursive matching - Updated existing tests to match new Path field behavior 5. Documentation improvements: - Added comprehensive documentation for WrapEnhancedInvokableToolCall method - Added comprehensive documentation for WrapEnhancedStreamableToolCall method - Documentation follows the same pattern as existing WrapInvokableToolCall and WrapStreamableToolCall methods Technical Implementation: - Uses doublestar.Match() for robust glob pattern matching with ** support - Pattern matching handles complex patterns like "**/*.go", "src/**/*.go" - Absolute patterns (starting with /) bypass basePath filtering and return full paths - Relative patterns respect basePath and return paths relative to it Impact: - Ls command now returns clean filenames like standard Unix ls - Glob patterns behave identically to Python glob.glob() with recursive=True - Supports complex patterns like "**/*.go", "src/**/*.go", and "/absolute/path/**/*.go" - Enhanced tool wrapper methods are now properly documented for middleware developers
1 parent 235a286 commit 134c7f1

File tree

16 files changed

+500
-57
lines changed

16 files changed

+500
-57
lines changed

adk/filesystem/backend.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import (
2525

2626
// FileInfo represents basic file metadata information.
2727
type FileInfo struct {
28-
// Path is the absolute path of the file or directory.
28+
// Path is the path of the file or directory, which can be a filename, relative path, or absolute path.
2929
Path string
3030

3131
// IsDir indicates whether the entry is a directory.

adk/filesystem/backend_inmemory.go

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ import (
2525
"strings"
2626
"sync"
2727
"time"
28+
29+
"github.com/bmatcuk/doublestar/v4"
2830
)
2931

3032
type fileEntry struct {
@@ -71,7 +73,7 @@ func (b *InMemoryBackend) LsInfo(ctx context.Context, req *LsInfoRequest) ([]Fil
7173
// The path itself is a file
7274
if !seen[normalizedFilePath] {
7375
result = append(result, FileInfo{
74-
Path: normalizedFilePath,
76+
Path: filepath.Base(normalizedFilePath),
7577
IsDir: false,
7678
Size: int64(len(entry.content)),
7779
ModifiedAt: entry.modifiedAt.Format(time.RFC3339Nano),
@@ -94,14 +96,14 @@ func (b *InMemoryBackend) LsInfo(ctx context.Context, req *LsInfoRequest) ([]Fil
9496
if !seen[childPath] {
9597
if isDir {
9698
dirInfo[childPath] = &FileInfo{
97-
Path: childPath,
99+
Path: parts[0],
98100
IsDir: true,
99101
Size: 0,
100102
ModifiedAt: entry.modifiedAt.Format(time.RFC3339Nano),
101103
}
102104
} else {
103105
result = append(result, FileInfo{
104-
Path: childPath,
106+
Path: parts[0],
105107
IsDir: false,
106108
Size: int64(len(entry.content)),
107109
ModifiedAt: entry.modifiedAt.Format(time.RFC3339Nano),
@@ -588,31 +590,40 @@ func (b *InMemoryBackend) GlobInfo(ctx context.Context, req *GlobInfoRequest) ([
588590
defer b.mu.RUnlock()
589591

590592
basePath := normalizePath(req.Path)
593+
isAbsolutePattern := strings.HasPrefix(req.Pattern, "/")
591594

592595
var result []FileInfo
593596

594597
for filePath, entry := range b.files {
595598
normalizedFilePath := normalizePath(filePath)
596599

597-
if basePath != "/" && !strings.HasPrefix(normalizedFilePath, basePath+"/") && normalizedFilePath != basePath {
598-
continue
599-
}
600+
var matchPath string
601+
var resultPath string
600602

601-
var relativePath string
602-
if basePath == "/" {
603-
relativePath = strings.TrimPrefix(normalizedFilePath, "/")
603+
if isAbsolutePattern {
604+
matchPath = normalizedFilePath
605+
resultPath = normalizedFilePath
604606
} else {
605-
relativePath = strings.TrimPrefix(normalizedFilePath, basePath+"/")
607+
if basePath != "/" && !strings.HasPrefix(normalizedFilePath, basePath+"/") && normalizedFilePath != basePath {
608+
continue
609+
}
610+
611+
if basePath == "/" {
612+
matchPath = strings.TrimPrefix(normalizedFilePath, "/")
613+
} else {
614+
matchPath = strings.TrimPrefix(normalizedFilePath, basePath+"/")
615+
}
616+
resultPath = matchPath
606617
}
607618

608-
matched, err := filepath.Match(req.Pattern, relativePath)
619+
matched, err := doublestar.Match(req.Pattern, matchPath)
609620
if err != nil {
610621
return nil, fmt.Errorf("invalid glob pattern: %w", err)
611622
}
612623

613624
if matched {
614625
result = append(result, FileInfo{
615-
Path: normalizedFilePath,
626+
Path: resultPath,
616627
IsDir: false,
617628
Size: int64(len(entry.content)),
618629
ModifiedAt: entry.modifiedAt.Format(time.RFC3339Nano),

0 commit comments

Comments
 (0)