Files
byre/internal/agents/diagram.go
T

65 lines
1.8 KiB
Go

package agents
import (
"bytes"
"context"
"encoding/base64"
"encoding/json"
"fmt"
"os"
"os/exec"
"path/filepath"
"strings"
"time"
"g.fc.run/ai/byre/internal/mcp"
)
func (m *Manager) renderDiagramTool() mcp.Tool {
return mcp.Tool{
Name: "render_diagram",
Description: "See a diagram as byre's app draws it in the transcript: pass the body of a ```diagram block and get back a PNG of the result, drawn by the app's own renderer in light mode. " +
"A source the app can't draw comes back as the reason instead.",
InputSchema: json.RawMessage(`{
"type": "object",
"properties": {
"source": {"type": "string", "description": "The block's body, without the fence lines."}
},
"required": ["source"]
}`),
Rich: func(ctx context.Context, raw json.RawMessage) mcp.Result {
args := struct {
Source string `json:"source"`
}{}
err := json.Unmarshal(raw, &args)
if err != nil {
return mcp.TextResult(fmt.Sprintf("malformed render_diagram call: %v", err), true)
}
png, err := renderDiagram(ctx, args.Source)
if err != nil {
return mcp.TextResult(err.Error(), true)
}
return mcp.Result{Content: []mcp.Content{{Type: "image", Data: base64.StdEncoding.EncodeToString(png), MimeType: "image/png"}}}
},
}
}
func renderDiagram(ctx context.Context, source string) ([]byte, error) {
exe, err := os.Executable()
if err != nil {
return nil, err
}
app := filepath.Join(filepath.Dir(exe), "..", "MacOS", "Byre")
ctx, cancel := context.WithTimeout(ctx, 30*time.Second)
defer cancel()
cmd := exec.CommandContext(ctx, app, "render-diagram")
cmd.Stdin = strings.NewReader(source)
stderr := bytes.Buffer{}
cmd.Stderr = &stderr
out, err := cmd.Output()
if err != nil {
return nil, fmt.Errorf("render diagram: %w: %s", err, strings.TrimSpace(stderr.String()))
}
return out, nil
}