Skip to content

Commit b6be434

Browse files
committed
fix: improve aiosandbox-backend reliability and docs
- Fix incorrect directory paths in README examples - Fix relative link to deep-aiosandbox example - Add URL validation for BaseURL (scheme/host required, http/https only) - Use path package instead of filepath for cross-platform consistency - Refactor grep to use ripgrep JSON output for reliable parsing - Move sandbox-sdk-go to direct dependency
1 parent ad4a2c8 commit b6be434

4 files changed

Lines changed: 47 additions & 26 deletions

File tree

adk/middleware/aiosandbox-backend/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ agent, err := deep.New(ctx, &deep.Config{
9393
## Run the Example
9494

9595
```bash
96-
cd adk/middleware/aiosandbox-filesystem
96+
cd adk/middleware/aiosandbox-backend
9797
go run .
9898
```
9999

@@ -126,7 +126,7 @@ This example uses the **Middleware approach** with `filesystem.Backend`:
126126
- Includes built-in large result offloading
127127
- Clean interface-based design
128128

129-
The [deep-aiosandbox](../multiagent/deep-aiosandbox) example uses the **Tool approach** with `commandline.Operator`:
129+
The [deep-aiosandbox](../../multiagent/deep-aiosandbox) example uses the **Tool approach** with `commandline.Operator`:
130130
- Manually registers tools: `bash`, `read_file`, `edit_file`, `tree`
131131
- More flexible for custom tool combinations
132132
- Requires more setup code

adk/middleware/aiosandbox-backend/README_zh.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ agent, err := deep.New(ctx, &deep.Config{
9393
## 运行示例
9494

9595
```bash
96-
cd adk/middleware/aiosandbox-filesystem
96+
cd adk/middleware/aiosandbox-backend
9797
go run .
9898
```
9999

@@ -128,7 +128,7 @@ type ShellBackend interface {
128128
- 内置大结果分流处理
129129
- 简洁的基于接口的设计
130130

131-
[deep-aiosandbox](../multiagent/deep-aiosandbox) 示例使用 **工具方式** 配合 `commandline.Operator`
131+
[deep-aiosandbox](../../multiagent/deep-aiosandbox) 示例使用 **工具方式** 配合 `commandline.Operator`
132132
- 手动注册工具:`bash``read_file``edit_file``tree`
133133
- 对自定义工具组合更灵活
134134
- 需要更多配置代码

adk/middleware/aiosandbox-backend/backend.go

Lines changed: 42 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,11 @@ package main
1818

1919
import (
2020
"context"
21+
"encoding/json"
2122
"fmt"
2223
"net/http"
2324
"net/url"
24-
"path/filepath"
25+
"path"
2526
"strings"
2627

2728
sandboxsdk "github.com/agent-infra/sandbox-sdk-go"
@@ -71,6 +72,14 @@ func NewAIOSandboxBackend(ctx context.Context, config *AIOSandboxBackendConfig)
7172
return nil, fmt.Errorf("invalid BaseURL: %w", err)
7273
}
7374

75+
if parsedURL.Scheme == "" || parsedURL.Host == "" {
76+
return nil, fmt.Errorf("invalid BaseURL: scheme and host are required")
77+
}
78+
79+
if parsedURL.Scheme != "http" && parsedURL.Scheme != "https" {
80+
return nil, fmt.Errorf("invalid BaseURL: only http and https schemes are supported")
81+
}
82+
7483
baseURL := fmt.Sprintf("%s://%s%s", parsedURL.Scheme, parsedURL.Host, parsedURL.Path)
7584

7685
opts := []option.RequestOption{
@@ -160,8 +169,22 @@ func escapeShellArg(s string) string {
160169
return strings.ReplaceAll(s, "'", "'\\''")
161170
}
162171

172+
// rgJSONMatch represents the ripgrep JSON output for a match.
173+
type rgJSONMatch struct {
174+
Type string `json:"type"`
175+
Data struct {
176+
Path struct {
177+
Text string `json:"text"`
178+
} `json:"path"`
179+
Lines struct {
180+
Text string `json:"text"`
181+
} `json:"lines"`
182+
LineNumber int `json:"line_number"`
183+
} `json:"data"`
184+
}
185+
163186
// GrepRaw searches for content matching the specified pattern in files.
164-
// Uses ripgrep (rg) for better performance.
187+
// Uses ripgrep (rg) with JSON output for reliable parsing.
165188
func (b *AIOSandboxBackend) GrepRaw(ctx context.Context, req *filesystem.GrepRequest) ([]filesystem.GrepMatch, error) {
166189
if req.Pattern == "" {
167190
return nil, nil
@@ -172,22 +195,19 @@ func (b *AIOSandboxBackend) GrepRaw(ctx context.Context, req *filesystem.GrepReq
172195
searchPath = b.config.WorkDir
173196
}
174197

175-
// Build rg command
176-
// -n: show line numbers
198+
// Build rg command with JSON output for reliable parsing
177199
// -F: treat pattern as literal string
178-
// --no-heading: show file path on each line
179-
// --null: use \0 as separator to handle : in filenames
180-
// Output format: filename\0linenum\0content
200+
// --json: output in JSON format
181201
pattern := escapeShellArg(req.Pattern)
182202
searchPath = escapeShellArg(searchPath)
183203

184204
var cmd string
185205
if req.Glob != "" {
186206
glob := escapeShellArg(req.Glob)
187-
cmd = fmt.Sprintf("rg -n -F --no-heading --null -g '%s' '%s' '%s' 2>/dev/null || true",
207+
cmd = fmt.Sprintf("rg -F --json -g '%s' '%s' '%s' 2>/dev/null || true",
188208
glob, pattern, searchPath)
189209
} else {
190-
cmd = fmt.Sprintf("rg -n -F --no-heading --null '%s' '%s' 2>/dev/null || true",
210+
cmd = fmt.Sprintf("rg -F --json '%s' '%s' 2>/dev/null || true",
191211
pattern, searchPath)
192212
}
193213

@@ -204,23 +224,24 @@ func (b *AIOSandboxBackend) GrepRaw(ctx context.Context, req *filesystem.GrepReq
204224
return nil, nil
205225
}
206226

207-
// Parse rg --null output: filename\0linenum\0content
227+
// Parse rg --json output: each line is a JSON object
208228
var matches []filesystem.GrepMatch
209229
lines := strings.Split(*data.Output, "\n")
210230
for _, line := range lines {
211231
if line == "" {
212232
continue
213233
}
214-
parts := strings.SplitN(line, "\x00", 3)
215-
if len(parts) < 3 {
234+
var m rgJSONMatch
235+
if err := json.Unmarshal([]byte(line), &m); err != nil {
236+
continue
237+
}
238+
if m.Type != "match" {
216239
continue
217240
}
218-
lineNum := 0
219-
fmt.Sscanf(parts[1], "%d", &lineNum)
220241
matches = append(matches, filesystem.GrepMatch{
221-
Path: parts[0],
222-
Line: lineNum,
223-
Content: parts[2],
242+
Path: m.Data.Path.Text,
243+
Line: m.Data.LineNumber,
244+
Content: strings.TrimSuffix(m.Data.Lines.Text, "\n"),
224245
})
225246
}
226247

@@ -319,11 +340,11 @@ func (b *AIOSandboxBackend) Edit(ctx context.Context, req *filesystem.EditReques
319340
return nil
320341
}
321342

322-
func (b *AIOSandboxBackend) resolvePath(path string) string {
323-
if filepath.IsAbs(path) {
324-
return path
343+
func (b *AIOSandboxBackend) resolvePath(p string) string {
344+
if path.IsAbs(p) {
345+
return p
325346
}
326-
return filepath.Join(b.config.WorkDir, path)
347+
return path.Join(b.config.WorkDir, p)
327348
}
328349

329350
// Execute runs a shell command in the sandbox.

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ go 1.24.7
55
toolchain go1.24.9
66

77
require (
8+
github.com/agent-infra/sandbox-sdk-go v0.0.3
89
github.com/alicebob/miniredis/v2 v2.35.0
910
github.com/bytedance/sonic v1.14.2
1011
github.com/chromedp/chromedp v0.9.5
@@ -39,7 +40,6 @@ require (
3940

4041
require (
4142
github.com/PuerkitoBio/goquery v1.10.3 // indirect
42-
github.com/agent-infra/sandbox-sdk-go v0.0.3 // indirect
4343
github.com/andybalholm/cascadia v1.3.3 // indirect
4444
github.com/aymerick/douceur v0.2.0 // indirect
4545
github.com/bahlo/generic-list-go v0.2.0 // indirect

0 commit comments

Comments
 (0)