fix: support code_execute for go backend (#16903)

### Summary

As title

<img width="3764" height="2033" alt="image"
src="https://github.com/user-attachments/assets/3f5084c2-0a04-4a44-bb31-a39a59c2a91f"
/>
This commit is contained in:
Haruko386
2026-07-15 10:55:39 +08:00
committed by GitHub
parent 3339040987
commit 654279a745
3 changed files with 73 additions and 10 deletions

View File

@@ -626,6 +626,52 @@ func TestCodeExec_LegacyDSLWrapperResolvesArgumentRefsFromState(t *testing.T) {
}
}
func TestCodeExec_LegacyDSLWrapperResolvesSysArgumentRefsFromCanvasState(t *testing.T) {
prev := agenttool.GetSandboxClient()
recorder := &codeExecSandboxRecorder{
resp: &agenttool.SandboxResponse{
ExitCode: 0,
StructuredResult: map[string]any{
"present": true,
"value": "532",
},
},
}
agenttool.SetSandboxClient(recorder)
t.Cleanup(func() { agenttool.SetSandboxClient(prev) })
c, err := New(componentNameCodeExec, map[string]any{
"lang": "python",
"script": "def main(num):\n" +
" return num\n",
"arguments": map[string]any{
"num": "sys.query",
},
"outputs": map[string]any{
"result": map[string]any{
"type": "String",
},
},
})
if err != nil {
t.Fatalf("New(CodeExec): %v", err)
}
state := runtime.NewCanvasState("run-codeexec", "task-codeexec")
state.Sys["query"] = "532"
ctx := runtime.WithState(context.Background(), state)
out, err := c.Invoke(ctx, nil)
if err != nil {
t.Fatalf("CodeExec.Invoke: %v", err)
}
if got := recorder.req.Arguments["num"]; got != "532" {
t.Fatalf("sandbox arguments[num] = %#v, want \"532\"", got)
}
if got := out["result"]; got != "532" {
t.Fatalf("CodeExec result = %v, want 532", got)
}
}
func TestCodeExec_LegacyDSLWrapperContractMismatchSetsError(t *testing.T) {
prev := agenttool.GetSandboxClient()
recorder := &codeExecSandboxRecorder{

View File

@@ -14,7 +14,7 @@
// limitations under the License.
//
// Universe A delegation wrappers. Canvas-facing components that
// Package component Universe A delegation wrappers. Canvas-facing components that
// delegate to their corresponding Universe B eino tool
// implementations. The delegation pattern keeps the canvas
// scheduler's Component contract thin and the eino tool's
@@ -1496,6 +1496,17 @@ func (c *codeExecComponent) Inputs() map[string]string {
}
}
func (c *codeExecComponent) GetInputForm() map[string]any {
res := make(map[string]any, len(c.params))
for k, _ := range c.params {
res[k] = map[string]any{
"type": "line",
"name": k,
}
}
return res
}
func (c *codeExecComponent) Outputs() map[string]string {
return map[string]string{
"result": "The main(...) return value rendered as the legacy CodeExec result field.",
@@ -1517,7 +1528,8 @@ func (c *codeExecComponent) Invoke(ctx context.Context, inputs map[string]any) (
merged[k] = v
}
if rawArgs, ok := merged["arguments"].(map[string]any); ok {
merged["arguments"] = resolveCodeExecArguments(rawArgs, merged)
state, _, _ := runtime.GetStateFromContext[*runtime.CanvasState](ctx)
merged["arguments"] = resolveCodeExecArguments(rawArgs, merged, state)
}
common.Debug("CodeExec wrapper invoke",
zap.Int("params_keys", len(c.params)),
@@ -1656,29 +1668,29 @@ func cloneAnyMap(in map[string]any) map[string]any {
return out
}
func resolveCodeExecArguments(args map[string]any, merged map[string]any) map[string]any {
func resolveCodeExecArguments(args map[string]any, merged map[string]any, state *runtime.CanvasState) map[string]any {
if args == nil {
return nil
}
out := make(map[string]any, len(args))
for k, v := range args {
out[k] = resolveCodeExecArgumentValue(v, merged)
out[k] = resolveCodeExecArgumentValue(v, merged, state)
}
return out
}
func resolveCodeExecArgumentValue(v any, merged map[string]any) any {
func resolveCodeExecArgumentValue(v any, merged map[string]any, state *runtime.CanvasState) any {
switch x := v.(type) {
case map[string]any:
return resolveCodeExecArguments(x, merged)
return resolveCodeExecArguments(x, merged, state)
case []any:
out := make([]any, 0, len(x))
for _, item := range x {
out = append(out, resolveCodeExecArgumentValue(item, merged))
out = append(out, resolveCodeExecArgumentValue(item, merged, state))
}
return out
case string:
if resolved, ok := lookupCodeExecArgumentRef(x, merged); ok {
if resolved, ok := lookupCodeExecArgumentRef(x, merged, state); ok {
return resolved
}
return x
@@ -1687,11 +1699,16 @@ func resolveCodeExecArgumentValue(v any, merged map[string]any) any {
}
}
func lookupCodeExecArgumentRef(ref string, merged map[string]any) (any, bool) {
func lookupCodeExecArgumentRef(ref string, merged map[string]any, state *runtime.CanvasState) (any, bool) {
ref = strings.TrimSpace(ref)
if ref == "" {
return nil, false
}
if state != nil {
if v, err := state.GetVar(ref); err == nil && v != nil {
return v, true
}
}
at := strings.Index(ref, "@")
if at <= 0 || at >= len(ref)-1 {
return nil, false

View File

@@ -75,7 +75,7 @@ import (
// selfManagedDefaultEndpoint is the canonical executor_manager
// endpoint baked into the Python side. Operators override via
// SANDBOX_EXECUTOR_MANAGER_URL.
const selfManagedDefaultEndpoint = "http://sandbox-executor-manager:9385"
const selfManagedDefaultEndpoint = "http://localhost:9385"
// SelfManagedProvider is the Go port of
// `agent/sandbox/providers/self_managed.py::SelfManagedProvider`.