Files
Agent-Native/runtime/tools/code_tool.go
T
weichenandCursor e4020d297c
ci / vet-and-test (pull_request) Successful in 49s
ci / docker-checkout-hostgateway (pull_request) Successful in 1s
Add a script host, deferred tools, and background MCP connect
Why: models need a capped way to call several tools from one script, and a slow MCP server must not block the first prompt.
Evidence: GOWORK=off go test ./runtime/codeorch/ ./runtime/tools/ ./runtime/mcp/ ./runtime/policy/ ./adapters/native/
Impact: run_tool_script stays unregistered until the caller turns it on. Deferred tools stay out of the model list. An unready MCP server connects in the background.
Refs: feature/code-orchestration
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-03 18:02:53 +00:00

60 lines
1.9 KiB
Go

package tools
import (
"context"
"encoding/json"
"fmt"
"strings"
"time"
"agent-native/runtime/codeorch"
)
// RegisterCodeTool 注册 run_tool_script。调用方在开关打开时才注册。
func RegisterCodeTool(reg *Registry) {
if reg == nil {
return
}
reg.Register(&codeScriptTool{reg: reg})
}
type codeScriptTool struct{ reg *Registry }
func (t *codeScriptTool) Name() string { return "run_tool_script" }
func (t *codeScriptTool) Description() string {
return "用一段 Python 依次调用已有工具。禁止再调用解释器、本工具、派发和工作流。失败时会列出已经执行的调用"
}
func (t *codeScriptTool) Parameters() json.RawMessage {
return json.RawMessage(`{"type":"object","properties":{"script":{"type":"string"},"timeout_sec":{"type":"integer"}},"required":["script"]}`)
}
func (t *codeScriptTool) Execute(ctx context.Context, args json.RawMessage) (Result, error) {
var req struct {
Script string `json:"script"`
Timeout int `json:"timeout_sec"`
}
if err := json.Unmarshal(args, &req); err != nil {
return Result{Content: err.Error(), IsError: true}, nil
}
if strings.TrimSpace(req.Script) == "" {
return Result{Content: "script 不能为空", IsError: true}, nil
}
lim := codeorch.Limits{FullDir: t.reg.Root()}
if req.Timeout > 0 {
lim.Timeout = time.Duration(req.Timeout) * time.Second
}
out := codeorch.Run(ctx, t.reg.Root(), req.Script, lim, nil, func(ctx context.Context, call codeorch.Call) (string, error) {
if call.Op != "tool.call" {
return "", fmt.Errorf("不能调用 %s", call.Op)
}
if codeorch.Forbidden(call.Name) {
return "", fmt.Errorf("不能调用 %s", call.Name)
}
res := t.reg.Execute(ctx, call.Name, call.Args)
if res.IsError {
return "", fmt.Errorf("%s", res.Content)
}
return res.Content, nil
})
return Result{Content: out.ModelText(), IsError: out.Err != nil}, nil
}