Add tool binary file detection
This commit is contained in:
@@ -5,6 +5,7 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
@@ -175,33 +176,50 @@ func (r *Registry) ToAPI() []APITool {
|
||||
return tools
|
||||
}
|
||||
|
||||
// binaryOutputPrefix is the message shown when tool output is detected as binary.
|
||||
const binaryOutputPrefix = "error: binary output detected: "
|
||||
|
||||
// ToolResult holds the structured output from a tool execution.
|
||||
type ToolResult struct {
|
||||
Stdout string
|
||||
Stderr string
|
||||
Stdout []byte
|
||||
Stderr []byte
|
||||
ProcessState *os.ProcessState
|
||||
}
|
||||
|
||||
// FormatResult formats the tool result using the structured label-based
|
||||
// format with stdout, stderr, and exit code sections.
|
||||
// FormatResult formats the tool result using the structured label-based
|
||||
// format with stdout, stderr, and exit code sections.
|
||||
//
|
||||
// http.DetectContentType implements the WHATWG MIME-sniffing spec and
|
||||
// returns text/plain for any content consisting entirely of printable
|
||||
// characters and whitespace. Text-based formats like JSON, JavaScript,
|
||||
// and XML will be detected as text/plain; charset=utf-8. We assume
|
||||
// checking for the "text/" prefix is sufficient.
|
||||
func (r *ToolResult) FormatResult() string {
|
||||
var buf strings.Builder
|
||||
|
||||
fmt.Fprintln(&buf, "▸ stdout:")
|
||||
if r.Stdout != "" {
|
||||
fmt.Fprint(&buf, r.Stdout)
|
||||
if !strings.HasSuffix(r.Stdout, "\n") {
|
||||
fmt.Fprint(&buf, "\n")
|
||||
if len(r.Stdout) > 0 {
|
||||
ctype := http.DetectContentType(r.Stdout)
|
||||
if !strings.HasPrefix(ctype, "text/") {
|
||||
fmt.Fprintf(&buf, binaryOutputPrefix+"%s\n", ctype)
|
||||
} else {
|
||||
buf.Write(r.Stdout)
|
||||
if r.Stdout[len(r.Stdout)-1] != '\n' {
|
||||
fmt.Fprint(&buf, "\n")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Fprintln(&buf, "▸ stderr:")
|
||||
if r.Stderr != "" {
|
||||
fmt.Fprint(&buf, r.Stderr)
|
||||
if !strings.HasSuffix(r.Stderr, "\n") {
|
||||
fmt.Fprint(&buf, "\n")
|
||||
if len(r.Stderr) > 0 {
|
||||
ctype := http.DetectContentType(r.Stderr)
|
||||
if !strings.HasPrefix(ctype, "text/") {
|
||||
fmt.Fprintf(&buf, binaryOutputPrefix+"%s\n", ctype)
|
||||
} else {
|
||||
buf.Write(r.Stderr)
|
||||
if r.Stderr[len(r.Stderr)-1] != '\n' {
|
||||
fmt.Fprint(&buf, "\n")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -301,8 +319,8 @@ func (r *Registry) Execute(
|
||||
// ProcessState is set; return it along with captured output.
|
||||
default:
|
||||
return &ToolResult{
|
||||
Stdout: stdout.String(),
|
||||
Stderr: stderr.String(),
|
||||
Stdout: stdout.Bytes(),
|
||||
Stderr: stderr.Bytes(),
|
||||
ProcessState: cmd.ProcessState,
|
||||
}, nil
|
||||
}
|
||||
@@ -310,8 +328,8 @@ func (r *Registry) Execute(
|
||||
|
||||
// No error. Process exited with status 0.
|
||||
return &ToolResult{
|
||||
Stdout: stdout.String(),
|
||||
Stderr: stderr.String(),
|
||||
Stdout: stdout.Bytes(),
|
||||
Stderr: stderr.Bytes(),
|
||||
ProcessState: cmd.ProcessState,
|
||||
}, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user