cloudwego / cloudwego/eino-ext

adk/backend/local: Local backend is not compatible with plantask.Backend

Open
#908 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Go
Stars
811
Forks
368
Avg merge
16h 22m
Merged PRs (30d)
13

Description

**Describe the bug**

`github.com/cloudwego/eino-ext/adk/backend/local.Local` implements `github.com/cloudwego/eino/adk/filesystem.Backend`, and can be used by the filesystem middleware and the skill filesystem backend.

However, it cannot be used directly with `github.com/cloudwego/eino/adk/middlewares/plantask`, even though `plantask` reuses the same filesystem request/response types for `LsInfo`, `Read`, and `Write`.

There are two incompatibilities:

1. `plantask.Backend` requires `Delete`, but `local.Local` does not implement it.
2. `local.Local.LsInfo` returns only entry names, while `plantask` treats `FileInfo.Path` as a path that can be passed back to `Read`.

**To Reproduce**

Steps to reproduce the behavior:

1. Create a small module that imports both packages and points them at local/current versions:

```go
package main

import (
"context"

extlocal "github.com/cloudwego/eino-ext/adk/backend/local"
"github.com/cloudwego/eino/adk/filesystem"
"github.com/cloudwego/eino/adk/middlewares/plantask"
)

func main() {
ctx := context.Background()
b, err := extlocal.NewBackend(ctx, &extlocal.Config{})
if err != nil {
panic(err)
}

var _ filesystem.Backend = b // OK
var _ plantask.Backend = b // FAIL
}
```

2. Run `go test ./...` or `go build`.

3. The compile-time check fails:

```text
./main.go:19:27: cannot use b (variable of type *local.Local) as plantask.Backend value in variable declaration: *local.Local does not implement plantask.Backend (missing method Delete)
```

4. Even if `Delete` is provided externally, `LsInfo` path semantics still do not match `plantask`'s current usage. `local.Local.LsInfo` returns basenames:

```go
files = append(files, filesystem.FileInfo{
Path: entry.Name(),
})
```

For example, listing `/tmp/tasks` may return:

```go
FileInfo{Path: ".highwatermark"}
FileInfo{Path: "1.json"}
```

But `plantask` uses `file.Path` directly as a readable path:

```go
content, readErr := t.Backend.Read(ctx, &ReadRequest{
FilePath: file.Path,
})
```

With `local.Local`, `Read(".highwatermark")` reads from the process working directory, not from the requested `BaseDir` such as `/tmp/tasks`.

**Expected behavior**

A local backend intended for ADK middleware usage should be usable with `plantask`, or the documentation should clearly state that `filesystem.Backend` implementations are not directly compatible with `plantask.Backend`.

For example, this should either compile and work, or have a documented adapter requirement:

```go
localBackend, _ := local.NewBackend(ctx, &local.Config{})

mw, err := plantask.New(ctx, &plantask.Config{
Backend: localBackend,
BaseDir: "/tmp/tasks",
})
```

**Screenshots**

N/A

**Version:**

Verified against:

- `cloudwego/eino-ext` local commit: `7f6839c`
- `github.com/cloudwego/eino-ext/adk/backend/local/go.mod` requires `github.com/cloudwego/eino v0.9.1`
- `cloudwego/eino` local commit used for checking current `plantask`: `ad1d0af`

**Environment:**

Relevant `go env` output:

```text
GOOS='linux'
GOARCH='amd64'
GOVERSION='go1.25.0'
GOTOOLCHAIN='go1.24.11+auto'
CGO_ENABLED='1'
GOMOD='/home/yanxu.666/projects/github/eino-ext/adk/backend/local/go.mod'
GOMODCACHE='/home/yanxu.666/go/pkg/mod'
GOWORK=''
```

**Additional context**

`filesystem.FileInfo.Path` is documented as allowing a filename, relative path, or absolute path. Therefore `local.Local.LsInfo` returning `entry.Name()` is valid for the shared filesystem backend contract.

The mismatch seems to come from `plantask` assuming a stronger contract than `filesystem.FileInfo.Path` documents: it expects `LsInfo` results to be directly readable with `Read`.

Possible fixes:

- Provide a `plantask` adapter that wraps a `filesystem.Backend`, implements `Delete`, and normalizes non-absolute `LsInfo` paths by joining them with the requested directory.
- Or normalize paths inside `plantask` before calling `Read`, for example:

```go
filePath := file.Path
if !filepath.IsAbs(filePath) {
filePath = filepath.Join(baseDir, filePath)
}
```

This would make `plantask` compatible with all valid `filesystem.FileInfo.Path` forms.

Contributor guide

Open the contributing guide

Research direction

Start by inspecting the adk/backend/local package and the plantask.Backend and filesystem.Backend interfaces, then reproduce the compile-time assertion and the LsInfo/Read path mismatch described here. Determine whether compatibility should come from a plantask adapter or path normalization, and verify that the chosen approach supports Delete and makes listed files readable from BaseDir.

Written by the indexing model from the issue text.

Assessment

Tech stack
go
Domain
api, backend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.