mirror of
https://github.com/wavetermdev/waveterm
synced 2026-05-18 22:38:25 +00:00
Documentation Updates (removing AI Widget Information / deprecation) Hover effect on tool calls shows which widget is effected Remove AI Widget from sidebar unless there is customized presets Backend now provides blockid (if available) to frontend for tool calls
170 lines
4.8 KiB
Go
170 lines
4.8 KiB
Go
// Copyright 2025, Command Line Inc.
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
package aiusechat
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/wavetermdev/waveterm/pkg/aiusechat/uctypes"
|
|
"github.com/wavetermdev/waveterm/pkg/wcore"
|
|
"github.com/wavetermdev/waveterm/pkg/wshrpc"
|
|
"github.com/wavetermdev/waveterm/pkg/wshrpc/wshclient"
|
|
"github.com/wavetermdev/waveterm/pkg/wshutil"
|
|
)
|
|
|
|
type TermGetScrollbackToolInput struct {
|
|
WidgetId string `json:"widget_id"`
|
|
LineStart int `json:"line_start,omitempty"`
|
|
Count int `json:"count,omitempty"`
|
|
}
|
|
|
|
type TermGetScrollbackToolOutput struct {
|
|
TotalLines int `json:"total_lines"`
|
|
LineStart int `json:"line_start"`
|
|
LineEnd int `json:"line_end"`
|
|
ReturnedLines int `json:"returned_lines"`
|
|
Content string `json:"content"`
|
|
SinceLastOutputSec *int `json:"since_last_output_sec,omitempty"`
|
|
HasMore bool `json:"has_more"`
|
|
NextStart *int `json:"next_start"`
|
|
}
|
|
|
|
func parseTermGetScrollbackInput(input any) (*TermGetScrollbackToolInput, error) {
|
|
const (
|
|
DefaultCount = 200
|
|
MaxCount = 1000
|
|
)
|
|
|
|
result := &TermGetScrollbackToolInput{
|
|
LineStart: 0,
|
|
Count: 0,
|
|
}
|
|
|
|
if input == nil {
|
|
result.Count = DefaultCount
|
|
return result, nil
|
|
}
|
|
|
|
inputBytes, err := json.Marshal(input)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to marshal input: %w", err)
|
|
}
|
|
|
|
if err := json.Unmarshal(inputBytes, result); err != nil {
|
|
return nil, fmt.Errorf("failed to unmarshal input: %w", err)
|
|
}
|
|
|
|
if result.Count == 0 {
|
|
result.Count = DefaultCount
|
|
}
|
|
|
|
if result.Count < 0 {
|
|
return nil, fmt.Errorf("count must be positive")
|
|
}
|
|
|
|
result.Count = min(result.Count, MaxCount)
|
|
|
|
return result, nil
|
|
}
|
|
|
|
func GetTermGetScrollbackToolDefinition(tabId string) uctypes.ToolDefinition {
|
|
return uctypes.ToolDefinition{
|
|
Name: "term_get_scrollback",
|
|
DisplayName: "Get Terminal Scrollback",
|
|
Description: "Fetch terminal scrollback from a widget as plain text. Index 0 is the most recent line; indices increase going upward (older lines).",
|
|
ToolLogName: "term:getscrollback",
|
|
InputSchema: map[string]any{
|
|
"type": "object",
|
|
"properties": map[string]any{
|
|
"widget_id": map[string]any{
|
|
"type": "string",
|
|
"description": "8-character widget ID of the terminal widget",
|
|
},
|
|
"line_start": map[string]any{
|
|
"type": "integer",
|
|
"minimum": 0,
|
|
"description": "Logical start index where 0 = most recent line (default: 0)",
|
|
},
|
|
"count": map[string]any{
|
|
"type": "integer",
|
|
"minimum": 1,
|
|
"description": "Number of lines to return from line_start (default: 200)",
|
|
},
|
|
},
|
|
"required": []string{"widget_id"},
|
|
"additionalProperties": false,
|
|
},
|
|
ToolInputDesc: func(input any) string {
|
|
parsed, err := parseTermGetScrollbackInput(input)
|
|
if err != nil {
|
|
return fmt.Sprintf("error parsing input: %v", err)
|
|
}
|
|
|
|
if parsed.LineStart == 0 && parsed.Count == 200 {
|
|
return fmt.Sprintf("reading terminal output from %s (most recent %d lines)", parsed.WidgetId, parsed.Count)
|
|
}
|
|
lineEnd := parsed.LineStart + parsed.Count
|
|
return fmt.Sprintf("reading terminal output from %s (lines %d-%d)", parsed.WidgetId, parsed.LineStart, lineEnd)
|
|
},
|
|
ToolAnyCallback: func(input any) (any, error) {
|
|
parsed, err := parseTermGetScrollbackInput(input)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
ctx, cancelFn := context.WithTimeout(context.Background(), 5*time.Second)
|
|
defer cancelFn()
|
|
|
|
fullBlockId, err := wcore.ResolveBlockIdFromPrefix(ctx, tabId, parsed.WidgetId)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
lineEnd := parsed.LineStart + parsed.Count
|
|
|
|
rpcClient := wshclient.GetBareRpcClient()
|
|
result, err := wshclient.TermGetScrollbackLinesCommand(
|
|
rpcClient,
|
|
wshrpc.CommandTermGetScrollbackLinesData{
|
|
LineStart: parsed.LineStart,
|
|
LineEnd: lineEnd,
|
|
},
|
|
&wshrpc.RpcOpts{Route: wshutil.MakeFeBlockRouteId(fullBlockId)},
|
|
)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to get terminal scrollback: %w", err)
|
|
}
|
|
|
|
content := strings.Join(result.Lines, "\n")
|
|
effectiveLineEnd := min(lineEnd, result.TotalLines)
|
|
hasMore := effectiveLineEnd < result.TotalLines
|
|
|
|
var sinceLastOutputSec *int
|
|
if result.LastUpdated > 0 {
|
|
sec := max(0, int((time.Now().UnixMilli()-result.LastUpdated)/1000))
|
|
sinceLastOutputSec = &sec
|
|
}
|
|
|
|
var nextStart *int
|
|
if hasMore {
|
|
nextStart = &effectiveLineEnd
|
|
}
|
|
|
|
return &TermGetScrollbackToolOutput{
|
|
TotalLines: result.TotalLines,
|
|
LineStart: result.LineStart,
|
|
LineEnd: effectiveLineEnd,
|
|
ReturnedLines: len(result.Lines),
|
|
Content: content,
|
|
SinceLastOutputSec: sinceLastOutputSec,
|
|
HasMore: hasMore,
|
|
NextStart: nextStart,
|
|
}, nil
|
|
},
|
|
}
|
|
}
|