feat: enhance go_eval tool with injected context bindings

- Modified GoEvalTool to accept a map of reflect.Value bindings.
- Exported these bindings to the synthetic `jane/env` and `jane/env/env` packages in Yaegi.
- Added comprehensive unit tests for the GoEvalTool to verify isolated execution and execution with bindings.
- Aligns with Phase 1 of JANE_EVOLUTION_PLAN.md for autonomous task execution.

Co-authored-by: hobbyistlabs-coder <267281733+hobbyistlabs-coder@users.noreply.github.com>
This commit is contained in:
google-labs-jules[bot] 2026-03-27 00:57:36 +00:00
parent c31965f35e
commit 9fc542294c
2 changed files with 122 additions and 0 deletions

View file

@ -3,6 +3,7 @@ package tools
import ( import (
"context" "context"
"fmt" "fmt"
"reflect"
"sync" "sync"
"time" "time"
@ -37,6 +38,7 @@ func (b *threadSafeBuffer) Len() int {
type GoEvalTool struct { type GoEvalTool struct {
workspace string workspace string
timeout time.Duration timeout time.Duration
Bindings map[string]reflect.Value
} }
func NewGoEvalTool(workspace string) *GoEvalTool { func NewGoEvalTool(workspace string) *GoEvalTool {
@ -46,6 +48,10 @@ func NewGoEvalTool(workspace string) *GoEvalTool {
} }
} }
func (t *GoEvalTool) SetBindings(bindings map[string]reflect.Value) {
t.Bindings = bindings
}
func (t *GoEvalTool) Name() string { func (t *GoEvalTool) Name() string {
return "go_eval" return "go_eval"
} }
@ -92,6 +98,20 @@ func (t *GoEvalTool) Execute(ctx context.Context, args map[string]any) *ToolResu
} }
} }
if t.Bindings != nil && len(t.Bindings) > 0 {
exports := interp.Exports{
"jane/env/env": t.Bindings,
"jane/env": t.Bindings,
}
if err := i.Use(exports); err != nil {
return &ToolResult{
ForLLM: fmt.Sprintf("Failed to initialize injected bindings: %v", err),
ForUser: "Execution environment setup failed.",
IsError: true,
}
}
}
// Channel to capture execution result // Channel to capture execution result
done := make(chan error, 1) done := make(chan error, 1)
go func() { go func() {

102
pkg/tools/go_eval_test.go Normal file
View file

@ -0,0 +1,102 @@
package tools
import (
"context"
"reflect"
"strings"
"testing"
"time"
)
func TestGoEvalTool(t *testing.T) {
tool := NewGoEvalTool("/tmp/test_workspace")
ctx := context.Background()
t.Run("execute simple go code", func(t *testing.T) {
args := map[string]any{
"code": `
import "fmt"
func main() {
fmt.Println("hello from yaegi")
}
`,
}
result := tool.Execute(ctx, args)
if result.IsError {
t.Fatalf("Expected no error, got: %s", result.ForLLM)
}
if !strings.Contains(result.ForLLM, "hello from yaegi") {
t.Errorf("Expected output to contain 'hello from yaegi', got %q", result.ForLLM)
}
})
t.Run("execution timeout", func(t *testing.T) {
tool.timeout = 100 * time.Millisecond
defer func() { tool.timeout = 60 * time.Second }()
args := map[string]any{
"code": `
import "time"
func init() {
time.Sleep(1 * time.Second)
}
`,
}
result := tool.Execute(ctx, args)
if !result.IsError {
t.Fatal("Expected timeout error, got success")
}
if !strings.Contains(result.ForLLM, "timed out") {
t.Errorf("Expected timeout message, got %q", result.ForLLM)
}
})
}
var TestWorkspace = "mock_workspace"
var DoMockTask = func() string {
return "mock task completed"
}
func TestGoEvalToolWithBindings(t *testing.T) {
tool := NewGoEvalTool("/tmp/test_workspace")
bindings := map[string]reflect.Value{
"Workspace": reflect.ValueOf(&TestWorkspace).Elem(),
"DoTask": reflect.ValueOf(&DoMockTask).Elem(),
}
tool.SetBindings(bindings)
ctx := context.Background()
t.Run("execute with bindings", func(t *testing.T) {
args := map[string]any{
"code": `
import "jane/env"
import "fmt"
func init() {
fmt.Println("workspace:", env.Workspace)
fmt.Println("task:", env.DoTask())
}
`,
}
result := tool.Execute(ctx, args)
if result.IsError {
t.Fatalf("Expected no error, got: %s", result.ForLLM)
}
if !strings.Contains(result.ForLLM, "workspace: mock_workspace") {
t.Errorf("Expected output to contain 'workspace: mock_workspace', got %q", result.ForLLM)
}
if !strings.Contains(result.ForLLM, "task: mock task completed") {
t.Errorf("Expected output to contain 'task: mock task completed', got %q", result.ForLLM)
}
})
}