74 lines
2.2 KiB
Go
74 lines
2.2 KiB
Go
package builtin
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
|
|
"nub/internal/tool"
|
|
)
|
|
|
|
// QuestionTool stellt eine generische Rückfrage an den Nutzer — anders als
|
|
// Permissions (system-/config-entschieden, boolesch) entscheidet hier das
|
|
// Modell selbst, dass es etwas klären will, und bekommt eine Text-Antwort
|
|
// als normales Tool-Ergebnis zurück. Kein Permission-Gate: das Tool ist
|
|
// von sich aus interaktiv, eine Rückfrage auf die Rückfrage ergäbe keinen
|
|
// Sinn.
|
|
type QuestionTool struct{}
|
|
|
|
func (QuestionTool) Name() string { return "question" }
|
|
func (QuestionTool) Description() string {
|
|
return "Stellt dem Nutzer eine Rückfrage, wenn eine Aufgabe mehrdeutig ist oder eine Entscheidung nötig ist, bevor es weitergeht."
|
|
}
|
|
|
|
func (QuestionTool) Schema() json.RawMessage {
|
|
return json.RawMessage(`{
|
|
"type": "object",
|
|
"properties": {
|
|
"question": {"type": "string"},
|
|
"options": {
|
|
"type": "array",
|
|
"items": {"type": "string"},
|
|
"description": "Optionale Vorschläge, die dem Nutzer zusätzlich zur Frage angezeigt werden"
|
|
}
|
|
},
|
|
"required": ["question"]
|
|
}`)
|
|
}
|
|
|
|
type questionInput struct {
|
|
Question string `json:"question"`
|
|
Options []string `json:"options"`
|
|
}
|
|
|
|
func (QuestionTool) Run(ctx context.Context, input json.RawMessage, env tool.Env) (tool.Result, error) {
|
|
var in questionInput
|
|
if err := json.Unmarshal(input, &in); err != nil {
|
|
return tool.Result{ForModel: "invalid input: " + err.Error(), IsError: true}, nil
|
|
}
|
|
if in.Question == "" {
|
|
return tool.Result{ForModel: "question must not be empty", IsError: true}, nil
|
|
}
|
|
if env.Ask == nil {
|
|
return tool.Result{
|
|
ForModel: "interactive questions are not supported in this mode (e.g. print mode) — proceed with your best judgment, or state your assumption in your next reply instead of asking",
|
|
IsError: true,
|
|
}, nil
|
|
}
|
|
|
|
answer, err := env.Ask(ctx, in.Question, in.Options)
|
|
if err != nil {
|
|
return tool.Result{ForModel: fmt.Sprintf("question failed: %v", err), IsError: true}, nil
|
|
}
|
|
|
|
return tool.Result{
|
|
ForModel: answer,
|
|
ForUI: QuestionResult{Question: in.Question, Options: in.Options, Answer: answer},
|
|
}, nil
|
|
}
|
|
|
|
type QuestionResult struct {
|
|
Question string
|
|
Options []string
|
|
Answer string
|
|
}
|