Files
2026-06-11 18:07:44 +08:00

133 lines
4.6 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package timeagent
import (
"encoding/json"
"fmt"
"strings"
"time"
"github.com/volcengine/volcengine-go-sdk/service/arkruntime/model"
)
const (
ToolName = "time"
ActivationPrompt = "提供当前日期、时间和常用时间范围。当用户问题包含今天、今日、明天、昨天、本周、本月、本年、最近、历史上的今天、日程安排等相对时间表达时,应先调用此工具;如果后续还需要联网搜索或查数据库,可继续调用 search 或 sql。"
)
type ToolArgs struct {
Reason string `json:"reason"`
}
type Range struct {
Start time.Time
End time.Time
}
type Context struct {
Now time.Time
Today Range
Tomorrow Range
Yesterday Range
ThisWeek Range
ThisMonth Range
ThisYear Range
}
func ToolDefinition(description string) *model.Tool {
description = strings.TrimSpace(description)
if description == "" {
description = ActivationPrompt
}
return &model.Tool{
Type: model.ToolTypeFunction,
Function: &model.FunctionDefinition{
Name: ToolName,
Description: description,
Parameters: map[string]any{
"type": "object",
"properties": map[string]any{
"reason": map[string]any{
"type": "string",
"description": "调用时间工具的原因。",
},
},
},
},
}
}
func ExecuteTool(args string, now time.Time) (string, error) {
var parsed ToolArgs
if strings.TrimSpace(args) != "" {
if err := json.Unmarshal([]byte(args), &parsed); err != nil {
return "", fmt.Errorf("解析时间工具参数失败: %w", err)
}
}
return BuildContext(Resolve(now), parsed.Reason), nil
}
func Resolve(now time.Time) Context {
loc := now.Location()
today := Range{Start: startOfDay(now), End: startOfDay(now).AddDate(0, 0, 1)}
tomorrowStart := today.End
tomorrow := Range{Start: tomorrowStart, End: tomorrowStart.AddDate(0, 0, 1)}
yesterdayEnd := today.Start
yesterday := Range{Start: yesterdayEnd.AddDate(0, 0, -1), End: yesterdayEnd}
weekdayOffset := (int(now.Weekday()) + 6) % 7
weekStart := today.Start.AddDate(0, 0, -weekdayOffset)
monthStart := time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, loc)
yearStart := time.Date(now.Year(), 1, 1, 0, 0, 0, 0, loc)
return Context{
Now: now,
Today: today,
Tomorrow: tomorrow,
Yesterday: yesterday,
ThisWeek: Range{Start: weekStart, End: weekStart.AddDate(0, 0, 7)},
ThisMonth: Range{Start: monthStart, End: monthStart.AddDate(0, 1, 0)},
ThisYear: Range{Start: yearStart, End: yearStart.AddDate(1, 0, 0)},
}
}
func BuildContext(ctx Context, routeReason string) string {
var b strings.Builder
b.WriteString("时间工具结果。请优先使用这里的绝对日期解释用户问题中的相对时间,不要自行猜测当前日期。\n")
fmt.Fprintf(&b, "当前本地日期时间:%s%s\n", ctx.Now.Format("2006-01-02 15:04:05 MST"), FormatWeekday(ctx.Now))
fmt.Fprintf(&b, "今天:%s%s\n", FormatDateWeekday(ctx.Today.Start), FormatSQLRangeWithWeekday(ctx.Today))
fmt.Fprintf(&b, "明天:%s%s\n", FormatDateWeekday(ctx.Tomorrow.Start), FormatSQLRangeWithWeekday(ctx.Tomorrow))
fmt.Fprintf(&b, "昨天:%s%s\n", FormatDateWeekday(ctx.Yesterday.Start), FormatSQLRangeWithWeekday(ctx.Yesterday))
fmt.Fprintf(&b, "本周:%s\n", FormatSQLRangeWithWeekday(ctx.ThisWeek))
fmt.Fprintf(&b, "本月:%s\n", FormatSQLRangeWithWeekday(ctx.ThisMonth))
fmt.Fprintf(&b, "本年:%s\n", FormatSQLRangeWithWeekday(ctx.ThisYear))
b.WriteString("SQL 日期过滤建议:对日程/事件类表使用半开区间,例如 event_time >= start AND event_time < end;如果实际字段名不同,必须使用 schema 中存在的时间字段。\n")
if strings.TrimSpace(routeReason) != "" {
b.WriteString("激活原因:" + strings.TrimSpace(routeReason) + "\n")
}
return b.String()
}
func FormatDate(t time.Time) string {
return t.Format("2006-01-02")
}
func FormatWeekday(t time.Time) string {
weekdays := []string{"星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"}
return weekdays[t.Weekday()]
}
func FormatDateWeekday(t time.Time) string {
return fmt.Sprintf("%s%s", FormatDate(t), FormatWeekday(t))
}
func FormatSQLRange(r Range) string {
return fmt.Sprintf("start=%s, end_exclusive=%s", r.Start.Format("2006-01-02 15:04:05"), r.End.Format("2006-01-02 15:04:05"))
}
func FormatSQLRangeWithWeekday(r Range) string {
return fmt.Sprintf("start=%s%s, end_exclusive=%s%s", r.Start.Format("2006-01-02 15:04:05"), FormatWeekday(r.Start), r.End.Format("2006-01-02 15:04:05"), FormatWeekday(r.End))
}
func startOfDay(t time.Time) time.Time {
y, m, d := t.Date()
return time.Date(y, m, d, 0, 0, 0, 0, t.Location())
}