diff --git a/compose/chain/main.go b/compose/chain/main.go index 3d7bddb..97b7348 100644 --- a/compose/chain/main.go +++ b/compose/chain/main.go @@ -31,6 +31,7 @@ import ( "github.com/cloudwego/eino/schema" "github.com/coze-dev/cozeloop-go" + "github.com/cloudwego/eino-examples/devops/visualize" "github.com/cloudwego/eino-examples/internal/gptr" "github.com/cloudwego/eino-examples/internal/logs" ) @@ -142,7 +143,7 @@ func main() { })) // compile - r, err := chain.Compile(ctx) + r, err := chain.Compile(ctx, compose.WithGraphCompileCallbacks(visualize.NewMermaidGenerator("compose/chain")), compose.WithGraphName("chain")) if err != nil { log.Panic(err) return diff --git a/compose/graph/simple/graph.go b/compose/graph/simple/graph.go index 9122595..b3d15e4 100644 --- a/compose/graph/simple/graph.go +++ b/compose/graph/simple/graph.go @@ -29,6 +29,8 @@ import ( "github.com/cloudwego/eino/compose" "github.com/cloudwego/eino/schema" "github.com/coze-dev/cozeloop-go" + + "github.com/cloudwego/eino-examples/devops/visualize" ) const ( @@ -68,11 +70,18 @@ func main() { _ = g.AddEdge(nodeOfPrompt, nodeOfModel) _ = g.AddEdge(nodeOfModel, compose.END) - r, err := g.Compile(ctx, compose.WithMaxRunSteps(10)) + gen := visualize.NewMermaidGenerator("compose/graph/simple") + r, err := g.Compile(ctx, + compose.WithMaxRunSteps(10), + compose.WithGraphCompileCallbacks(gen), + compose.WithGraphName("SimpleGraph"), + ) if err != nil { panic(err) } + // Mermaid markdown and images are auto-generated in compose/graph/simple + in := map[string]any{"location": "beijing"} ret, err := r.Invoke(ctx, in) if err != nil { diff --git a/compose/workflow/4_control_only_branch/main.go b/compose/workflow/4_control_only_branch/main.go index 0d9d2e6..6d6e8a2 100644 --- a/compose/workflow/4_control_only_branch/main.go +++ b/compose/workflow/4_control_only_branch/main.go @@ -25,6 +25,7 @@ import ( "github.com/cloudwego/eino/compose" "github.com/coze-dev/cozeloop-go" + "github.com/cloudwego/eino-examples/devops/visualize" "github.com/cloudwego/eino-examples/internal/logs" ) @@ -90,12 +91,15 @@ func main() { wf.End().AddInput("b1", compose.ToField("bidder1")). AddInput("b2", compose.ToField("bidder2")) - runner, err := wf.Compile(context.Background()) + gen := visualize.NewMermaidGenerator("compose/workflow/4_control_only_branch") + runner, err := wf.Compile(context.Background(), compose.WithGraphCompileCallbacks(gen), compose.WithGraphName("Workflow-Control-Only-Branch")) if err != nil { logs.Errorf("workflow compile error: %v", err) return } + // Mermaid markdown and images are auto-generated in compose/workflow/4_control_only_branch + result, err := runner.Invoke(context.Background(), 3.0) if err != nil { logs.Errorf("workflow run err: %v", err) diff --git a/devops/visualize/mermaid.go b/devops/visualize/mermaid.go new file mode 100644 index 0000000..6b3163f --- /dev/null +++ b/devops/visualize/mermaid.go @@ -0,0 +1,456 @@ +/* + * Copyright 2025 CloudWeGo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package visualize + +import ( + "context" + "fmt" + "io" + "os" + "os/exec" + "path/filepath" + "sort" + "strings" + + "github.com/chromedp/chromedp" + "github.com/cloudwego/eino/compose" +) + +// MermaidGenerator renders a Mermaid diagram from a compiled Eino graph (Graph/Chain/Workflow). +// +// Core concepts and mapping: +// - Nodes: labeled with their key and component type. Lambda nodes use rounded shapes. +// - Special nodes: START/END are rendered with safe IDs (start_node/end_node) to avoid Mermaid keyword conflicts. +// - SubGraphs: nested Graph/Chain/Workflow are rendered as Mermaid sub-graphs with their component type in the title. +// - Edges: +// - In general graphs/chains: a single solid arrow (-->), representing standard control+data execution. +// - In workflows (workflowStyle=true): edges are distinguished by semantics: +// - control+data: normal arrow with label "control+data" ("-- control+data -->") +// - control-only: bold arrow with label "control-only" ("== control-only ==>") +// - data-only: dotted arrow with label "data-only" ("-. data-only .->") +// Branch decision diamonds and their incoming/outgoing edges are treated as control-only in workflows. +// +// Usage: +// +// buf := &bytes.Buffer{} +// gen := visualize.NewMermaidGenerator(buf) // for Graph/Chain +// // or +// gen := visualize.NewMermaidGeneratorWorkflow(buf) // for Workflow with labeled edges +// _, _ = g.Compile(ctx, compose.WithGraphCompileCallbacks(gen), compose.WithGraphName("MyGraph")) +// // Write to a Markdown file: +// md := "```mermaid\n" + buf.String() + "\n```\n" +// _ = os.WriteFile("my_graph.md", []byte(md), 0644) +type MermaidGenerator struct { + w io.Writer + workflowStyle bool + autoWrite bool + outDir string + baseName string + makeImages bool +} + +// NewMermaidGenerator creates a generator that auto-writes Markdown and attempts PNG/SVG generation. +// If dir is empty, current working directory is used. File name is derived from graph name or defaults to "topology". +func NewMermaidGenerator(dir string) *MermaidGenerator { + return &MermaidGenerator{autoWrite: true, outDir: dir, makeImages: true} +} + +// OnFinish is the compile callback entrypoint invoked by Eino after graph compilation. +// It reads the compile-time GraphInfo and writes a complete Mermaid diagram to the writer. +func (m *MermaidGenerator) OnFinish(_ context.Context, info *compose.GraphInfo) { + m.generate(info) +} + +// generate orchestrates diagram construction by delegating to renderGraph. +// The top-level direction is TD (top-down) for readability and consistency. +func (m *MermaidGenerator) generate(info *compose.GraphInfo) { + var isWorkflow bool + if len(info.Edges) > len(info.DataEdges) { + isWorkflow = true + } + + if !isWorkflow { + for from, edges := range info.Edges { + dataEdges, ok := info.DataEdges[from] + if !ok { + isWorkflow = true + break + } + + if len(edges) != len(dataEdges) { + isWorkflow = true + break + } + + for i := range edges { + edge := edges[i] + found := false + for _, dEdge := range dataEdges { + if dEdge == edge { + found = true + break + } + } + if !found { + isWorkflow = true + break + } + } + } + } + + sb := &strings.Builder{} + sb.WriteString("graph TD\n") + m.renderGraph(sb, info, "", 1, isWorkflow) + if m.w != nil && !m.autoWrite { + _, _ = fmt.Fprint(m.w, sb.String()) + return + } + + dir := m.outDir + if dir == "" { + if wd, err := os.Getwd(); err == nil { + dir = wd + } else { + dir = "." + } + } + name := m.baseName + if name == "" { + if len(info.Name) > 0 { + name = sanitize(info.Name) + } else { + name = "topology" + } + } + mdPath := filepath.Join(dir, name+".md") + content := sb.String() + _ = os.WriteFile(mdPath, []byte("```mermaid\n"+content+"\n```"), 0644) + if m.makeImages { + mmdPath := filepath.Join(dir, name+".mmd") + _ = os.WriteFile(mmdPath, []byte(content), 0644) + m.renderImage(mmdPath, filepath.Join(dir, name+".png")) + _ = os.Remove(mmdPath) + } +} + +// renderGraph builds a Mermaid diagram section for the given GraphInfo. +// It: +// 1) Collects and sorts node keys for deterministic output +// 2) Renders nodes (including nested sub-graphs) +// 3) Renders control/data edges with workflow-aware styles +// 4) Renders branches with decision diamonds and proper edge types +func (m *MermaidGenerator) renderGraph(sb *strings.Builder, info *compose.GraphInfo, prefix string, indentLevel int, style bool) { + indent := strings.Repeat(" ", indentLevel) + + // Collect all nodes from info.Nodes, Edges, and Branches + allNodes := make(map[string]bool) + for k := range info.Nodes { + allNodes[k] = true + } + for start, ends := range info.Edges { + allNodes[start] = true + for _, end := range ends { + allNodes[end] = true + } + } + for start, branches := range info.Branches { + allNodes[start] = true + for _, branch := range branches { + endNodes := branch.GetEndNode() + for end := range endNodes { + allNodes[end] = true + } + } + } + + // Sort nodes for deterministic output + nodes := make([]string, 0, len(allNodes)) + for k := range allNodes { + nodes = append(nodes, k) + } + sort.Strings(nodes) + + // Render Nodes + for _, nodeKey := range nodes { + nodeID := m.nodeID(prefix, nodeKey) + + if nodeInfo, ok := info.Nodes[nodeKey]; ok { + if nodeInfo.GraphInfo != nil { + // Subgraph + subgraphLabel := nodeKey + if nodeInfo.Component == compose.ComponentOfChain { + subgraphLabel = fmt.Sprintf("%s (Chain)", nodeKey) + } else if nodeInfo.Component == compose.ComponentOfWorkflow { + subgraphLabel = fmt.Sprintf("%s (Workflow)", nodeKey) + } else if nodeInfo.Component == compose.ComponentOfGraph { + subgraphLabel = fmt.Sprintf("%s (Graph)", nodeKey) + } + sb.WriteString(fmt.Sprintf("%ssubgraph %s [\"%s\"]\n", indent, nodeID, subgraphLabel)) + childStyle := style + if nodeInfo.Component == compose.ComponentOfWorkflow { + childStyle = true + } else if nodeInfo.Component == compose.ComponentOfGraph || nodeInfo.Component == compose.ComponentOfChain { + // for explicit Graph/Chain sub-graphs, do not apply workflow styling + childStyle = false + } + m.renderGraph(sb, nodeInfo.GraphInfo, nodeID+"_", indentLevel+1, childStyle) + sb.WriteString(fmt.Sprintf("%send\n", indent)) + } else { + // Regular Node + shapeStart, shapeEnd := "[", "]" + if nodeInfo.Component == compose.ComponentOfLambda { + shapeStart, shapeEnd = "(", ")" + } + + label := fmt.Sprintf("%s
(%s)", nodeKey, nodeInfo.Component) + sb.WriteString(fmt.Sprintf("%s%s%s\"%s\"%s\n", indent, nodeID, shapeStart, label, shapeEnd)) + } + } else if nodeKey == compose.START || nodeKey == compose.END { + // Special nodes: avoid reserved keyword conflict with 'end' + safeID := nodeID + if nodeKey == compose.START { + safeID = m.nodeID(prefix, "start_node") + } else { + safeID = m.nodeID(prefix, "end_node") + } + sb.WriteString(fmt.Sprintf("%s%s([%s])\n", indent, safeID, nodeKey)) + } + } + + // Render Control Edges + // Sort edges for deterministic output + startNodes := make([]string, 0, len(info.Edges)) + for k := range info.Edges { + startNodes = append(startNodes, k) + } + sort.Strings(startNodes) + + for _, start := range startNodes { + ends := info.Edges[start] + for _, end := range ends { + startID := m.nodeID(prefix, start) + endID := m.nodeID(prefix, end) + if start == compose.START { + startID = m.nodeID(prefix, "start_node") + } + if end == compose.END { + endID = m.nodeID(prefix, "end_node") + } + // Determine edge semantics by checking if a matching data edge exists. + hasData := false + if des, ok := info.DataEdges[start]; ok { + for _, de := range des { + if de == end { + hasData = true + break + } + } + } + if style { + if hasData { + sb.WriteString(fmt.Sprintf("%s%s -- control+data --> %s\n", indent, startID, endID)) + } else { + sb.WriteString(fmt.Sprintf("%s%s == control-only ==> %s\n", indent, startID, endID)) + } + } else { + sb.WriteString(fmt.Sprintf("%s%s --> %s\n", indent, startID, endID)) + } + } + } + + // Render Data Edges + // Only render if they differ from control edges; otherwise already represented as control+data. + dataStartNodes := make([]string, 0, len(info.DataEdges)) + for k := range info.DataEdges { + dataStartNodes = append(dataStartNodes, k) + } + sort.Strings(dataStartNodes) + + for _, start := range dataStartNodes { + ends := info.DataEdges[start] + for _, end := range ends { + // Check if this edge already exists as a control edge + alreadyExists := false + for _, controlEnd := range info.Edges[start] { + if controlEnd == end { + alreadyExists = true + break + } + } + if !alreadyExists { + startID := m.nodeID(prefix, start) + endID := m.nodeID(prefix, end) + if start == compose.START { + startID = m.nodeID(prefix, "start_node") + } + if end == compose.END { + endID = m.nodeID(prefix, "end_node") + } + if style { + sb.WriteString(fmt.Sprintf("%s%s -. data-only .-> %s\n", indent, startID, endID)) + } else { + sb.WriteString(fmt.Sprintf("%s%s -.-> %s\n", indent, startID, endID)) + } + } + } + } + + // Render Branches + branchStarts := make([]string, 0, len(info.Branches)) + for k := range info.Branches { + branchStarts = append(branchStarts, k) + } + sort.Strings(branchStarts) + + for _, start := range branchStarts { + branches := info.Branches[start] + for i, branch := range branches { + // Branch decision node (diamond) + // We need a unique ID for the decision point if there are multiple branches from the same node? + // Actually, `info.Branches` maps startNode -> []GraphBranch. + // Usually a node has one set of branches. + // Let's represent the branch condition as a diamond. + + // If there are multiple branches, they might be parallel or sequential conditions. + // Eino `AddBranch` adds a branch. + + // For visualization, maybe we just draw arrows from startNode to endNodes with a label? + // Or introduce a "decision" node? + + // Decision node visualization: startNode -> decision{branch} -> endNodes + + decisionID := fmt.Sprintf("%s_branch_%d", m.nodeID(prefix, start), i) + sb.WriteString(fmt.Sprintf("%s%s{\"%s\"}\n", indent, decisionID, "branch")) + startID := m.nodeID(prefix, start) + if start == compose.START { + startID = m.nodeID(prefix, "start_node") + } + if style { + sb.WriteString(fmt.Sprintf("%s%s ==> %s\n", indent, startID, decisionID)) + } else { + sb.WriteString(fmt.Sprintf("%s%s --> %s\n", indent, startID, decisionID)) + } + + // Sort end nodes + endNodesMap := branch.GetEndNode() + endNodes := make([]string, 0, len(endNodesMap)) + for k := range endNodesMap { + endNodes = append(endNodes, k) + } + sort.Strings(endNodes) + + for _, end := range endNodes { + endID := m.nodeID(prefix, end) + if end == compose.END { + endID = m.nodeID(prefix, "end_node") + } + if style { + sb.WriteString(fmt.Sprintf("%s%s ==> %s\n", indent, decisionID, endID)) + } else { + sb.WriteString(fmt.Sprintf("%s%s --> %s\n", indent, decisionID, endID)) + } + } + } + } +} + +// nodeID sanitizes a node key to be a valid Mermaid identifier, and adds a caller-provided prefix +// to ensure uniqueness when rendering nested graphs. +func (m *MermaidGenerator) nodeID(prefix, key string) string { + // Sanitize key for Mermaid ID + safeKey := strings.ReplaceAll(key, " ", "_") + safeKey = strings.ReplaceAll(safeKey, "-", "_") + return prefix + safeKey +} + +func (m *MermaidGenerator) renderImage(input, output string) { + if _, err := exec.LookPath("mmdc"); err != nil { + // fallback to chromedp rendering + data, rErr := os.ReadFile(input) + if rErr != nil { + return + } + _ = renderWithChromedp(string(data), output) + return + } + cmd := exec.Command("mmdc", "-i", input, "-o", output) + _ = cmd.Run() +} + +func sanitize(s string) string { + s = strings.TrimSpace(s) + s = strings.ReplaceAll(s, " ", "_") + s = strings.ReplaceAll(s, "/", "_") + s = strings.ReplaceAll(s, "\\", "_") + return s +} + +func renderWithChromedp(mermaidCode, output string) error { + html := buildMermaidHTML(mermaidCode) + ctx, cancel := chromedp.NewContext(context.Background()) + defer cancel() + + var err error + ext := strings.ToLower(filepath.Ext(output)) + switch ext { + case ".png": + var buf []byte + err = chromedp.Run(ctx, + chromedp.Navigate("data:text/html,"+urlEncode(html)), + chromedp.WaitVisible(`#container svg`, chromedp.ByQuery), + chromedp.Screenshot(`#container svg`, &buf, chromedp.NodeVisible, chromedp.ByQuery), + ) + if err == nil { + err = os.WriteFile(output, buf, 0644) + } + case ".svg": + var svg string + err = chromedp.Run(ctx, + chromedp.Navigate("data:text/html,"+urlEncode(html)), + chromedp.WaitVisible(`#container svg`, chromedp.ByQuery), + chromedp.OuterHTML(`#container svg`, &svg, chromedp.ByQuery), + ) + if err == nil { + err = os.WriteFile(output, []byte(svg), 0644) + } + default: + // unsupported extension + return nil + } + return err +} + +func buildMermaidHTML(code string) string { + return ` + + + + + + + + +
` + code + `
+ +` +} + +func urlEncode(s string) string { // minimal percent-encoding for data URL + r := strings.NewReplacer("%", "%25", "#", "%23", "\n", "%0A", "\r", "%0D") + return r.Replace(s) +} diff --git a/flow/agent/multiagent/host/journal/main.go b/flow/agent/multiagent/host/journal/main.go index e22ae1b..e3c7a15 100644 --- a/flow/agent/multiagent/host/journal/main.go +++ b/flow/agent/multiagent/host/journal/main.go @@ -22,8 +22,11 @@ import ( "io" "os" + "github.com/cloudwego/eino/compose" "github.com/cloudwego/eino/flow/agent/multiagent/host" "github.com/cloudwego/eino/schema" + + "github.com/cloudwego/eino-examples/devops/visualize" ) func main() { @@ -68,6 +71,17 @@ func main() { panic(err) } + // export the graph via API and render mermaid (non-critical path) + { + anyG, opts := hostMA.ExportGraph() + gen := visualize.NewMermaidGenerator("flow/agent/multiagent/host/journal") + g := compose.NewGraph[[]*schema.Message, *schema.Message]() + _ = g.AddGraphNode("host_multiagent", anyG, opts...) + _ = g.AddEdge(compose.START, "host_multiagent") + _ = g.AddEdge("host_multiagent", compose.END) + _, _ = g.Compile(context.Background(), compose.WithGraphCompileCallbacks(gen)) + } + cb := &logCallback{} for { // 多轮对话,除非用户输入了 "exit",否则一直循环 diff --git a/flow/agent/multiagent/plan_execute/compose.go b/flow/agent/multiagent/plan_execute/compose.go index 0888e4d..fadfbe3 100644 --- a/flow/agent/multiagent/plan_execute/compose.go +++ b/flow/agent/multiagent/plan_execute/compose.go @@ -27,6 +27,7 @@ import ( "github.com/cloudwego/eino/flow/agent" "github.com/cloudwego/eino/schema" + "github.com/cloudwego/eino-examples/devops/visualize" "github.com/cloudwego/eino-examples/flow/agent/multiagent/plan_execute/prompt" ) @@ -196,12 +197,20 @@ func NewMultiAgent(ctx context.Context, config *Config) (*PlanExecuteMultiAgent, })) _ = graph.AddEdge(nodeKeyReviserToList, nodeKeyExecutor) - // 编译 graph,将节点、边、分支转化为面向运行时的结构。由于 graph 中存在环,使用 AnyPredecessor 模式,同时设置运行时最大步数。 - runnable, err := graph.Compile(ctx, compose.WithNodeTriggerMode(compose.AnyPredecessor), compose.WithMaxRunSteps(maxStep)) + // 编译 graph,并生成 Mermaid 拓扑图。由于 graph 中存在环,使用 AnyPredecessor 模式,同时设置运行时最大步数。 + gen := visualize.NewMermaidGenerator("flow/agent/multiagent/plan_execute") + runnable, err := graph.Compile(ctx, + compose.WithNodeTriggerMode(compose.AnyPredecessor), + compose.WithMaxRunSteps(maxStep), + compose.WithGraphCompileCallbacks(gen), + compose.WithGraphName("PlanExecuteMultiAgent"), + ) if err != nil { return nil, err } + // Mermaid markdown and images are auto-generated in flow/agent/multiagent/plan_execute + return &PlanExecuteMultiAgent{ runnable: runnable, }, nil diff --git a/flow/agent/multiagent/plan_execute/main.go b/flow/agent/multiagent/plan_execute/main.go index f015f33..a5eab09 100644 --- a/flow/agent/multiagent/plan_execute/main.go +++ b/flow/agent/multiagent/plan_execute/main.go @@ -27,8 +27,6 @@ import ( "time" "github.com/bytedance/sonic" - "github.com/cloudwego/eino-examples/flow/agent/multiagent/plan_execute/debug" - "github.com/cloudwego/eino-examples/flow/agent/multiagent/plan_execute/tools" clc "github.com/cloudwego/eino-ext/callbacks/cozeloop" "github.com/cloudwego/eino-ext/components/model/ark" "github.com/cloudwego/eino-ext/components/model/deepseek" @@ -40,6 +38,9 @@ import ( "github.com/cloudwego/eino/schema" "github.com/cloudwego/eino/utils/callbacks" "github.com/coze-dev/cozeloop-go" + + "github.com/cloudwego/eino-examples/flow/agent/multiagent/plan_execute/debug" + "github.com/cloudwego/eino-examples/flow/agent/multiagent/plan_execute/tools" ) func main() { diff --git a/flow/agent/react/react.go b/flow/agent/react/react.go index fe01979..eaa339b 100644 --- a/flow/agent/react/react.go +++ b/flow/agent/react/react.go @@ -35,6 +35,7 @@ import ( "github.com/cloudwego/eino/schema" "github.com/coze-dev/cozeloop-go" + "github.com/cloudwego/eino-examples/devops/visualize" "github.com/cloudwego/eino-examples/flow/agent/react/tools" "github.com/cloudwego/eino-examples/internal/logs" ) @@ -60,14 +61,15 @@ func main() { } callbacks.AppendGlobalHandlers(handlers...) - config := &ark.ChatModelConfig{ - APIKey: arkApiKey, - Model: arkModelName, - } + // minimal: we will export graph via API when available and compile a mermaid diagram // Create a new cached ark chat model. //arkModel, err = NewCachedARKChatModel(ctx, config) + config := &ark.ChatModelConfig{ + APIKey: arkApiKey, + Model: arkModelName, + } arkModel, err := ark.NewChatModel(ctx, config) if err != nil { logs.Errorf("failed to create chat model: %v", err) @@ -75,8 +77,8 @@ func main() { } // prepare tools - restaurantTool := tools.GetRestaurantTool() // 查询餐厅信息的工具 - dishTool := tools.GetDishTool() // 查询餐厅菜品信息的工具 + restaurantTool := tools.GetRestaurantTool() + dishTool := tools.GetDishTool() // prepare persona (system prompt) (optional) persona := `# Character: @@ -106,7 +108,7 @@ func main() { return false, nil }*/ - ragent, err := react.NewAgent(ctx, &react.AgentConfig{ + rAgent, err := react.NewAgent(ctx, &react.AgentConfig{ ToolCallingModel: arkModel, ToolsConfig: compose.ToolsNodeConfig{ Tools: []tool.BaseTool{restaurantTool, dishTool}, @@ -145,7 +147,18 @@ func main() { //react.WithChatModelOptions(ark.WithCache(cacheOption)), } - sr, err := ragent.Stream(ctx, []*schema.Message{ + // Export graph and compile with mermaid (non-critical path) + { + anyG, opts := rAgent.ExportGraph() + gen := visualize.NewMermaidGenerator("flow/agent/react") + g := compose.NewGraph[[]*schema.Message, *schema.Message]() + _ = g.AddGraphNode("react_agent", anyG, opts...) + _ = g.AddEdge(compose.START, "react_agent") + _ = g.AddEdge("react_agent", compose.END) + _, _ = g.Compile(context.Background(), compose.WithGraphCompileCallbacks(gen)) + } + + sr, err := rAgent.Stream(ctx, []*schema.Message{ { Role: schema.System, Content: persona, diff --git a/go.mod b/go.mod index 879568f..80b6b89 100644 --- a/go.mod +++ b/go.mod @@ -6,6 +6,7 @@ toolchain go1.24.9 require ( github.com/bytedance/sonic v1.14.2 + github.com/chromedp/chromedp v0.9.5 github.com/cloudwego/eino v0.7.0 github.com/cloudwego/eino-ext/callbacks/cozeloop v0.1.6 github.com/cloudwego/eino-ext/components/document/parser/html v0.0.0-20251117090452-bd6375a0b3cf @@ -24,7 +25,7 @@ require ( github.com/google/uuid v1.6.0 github.com/json-iterator/go v1.1.12 github.com/kaptinlin/jsonrepair v0.2.4 - github.com/ollama/ollama v0.11.4 + github.com/pkoukk/tiktoken-go v0.1.8 github.com/stretchr/testify v1.11.1 github.com/volcengine/volcengine-go-sdk v1.1.44 github.com/wk8/go-ordered-map/v2 v2.1.8 @@ -42,6 +43,8 @@ require ( github.com/bytedance/gopkg v0.1.3 // indirect github.com/bytedance/sonic/loader v0.4.0 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect + github.com/chromedp/cdproto v0.0.0-20240202021202-6d0b6a386732 // indirect + github.com/chromedp/sysutil v1.0.0 // indirect github.com/cloudwego/base64x v0.1.6 // indirect github.com/cloudwego/eino-ext/libs/acl/openai v0.1.2 // indirect github.com/cohesion-org/deepseek-go v1.3.2 // indirect @@ -52,14 +55,13 @@ require ( github.com/dustin/go-humanize v1.0.1 // indirect github.com/eino-contrib/ollama v0.1.0 // indirect github.com/evanphx/json-patch v0.5.2 // indirect - github.com/getkin/kin-openapi v0.118.0 // indirect - github.com/go-openapi/jsonpointer v0.21.1 // indirect - github.com/go-openapi/swag v0.23.1 // indirect + github.com/gobwas/httphead v0.1.0 // indirect + github.com/gobwas/pool v0.2.1 // indirect + github.com/gobwas/ws v1.3.2 // indirect github.com/golang-jwt/jwt v3.2.2+incompatible // indirect github.com/goph/emperror v0.17.2 // indirect github.com/gorilla/css v1.0.1 // indirect github.com/gorilla/mux v1.8.1 // indirect - github.com/invopop/yaml v0.3.1 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/joho/godotenv v1.5.1 // indirect github.com/josharian/intern v1.0.0 // indirect @@ -71,14 +73,12 @@ require ( github.com/microcosm-cc/bluemonday v1.0.27 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect - github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect github.com/nikolalohinski/gonja v1.5.3 // indirect github.com/nikolalohinski/gonja/v2 v2.3.1 // indirect + github.com/ollama/ollama v0.11.4 // indirect github.com/openai/openai-go v1.10.1 // indirect github.com/pelletier/go-toml/v2 v2.2.4 // indirect - github.com/perimeterx/marshmallow v1.1.5 // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/pkoukk/tiktoken-go v0.1.8 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/richardlehane/mscfb v1.0.4 // indirect github.com/richardlehane/msoleps v1.0.4 // indirect @@ -90,7 +90,6 @@ require ( github.com/tidwall/sjson v1.2.5 // indirect github.com/tiendc/go-deepcopy v1.7.1 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect - github.com/ugorji/go/codec v1.3.0 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasttemplate v1.2.2 // indirect github.com/volcengine/volc-sdk-golang v1.0.199 // indirect diff --git a/go.sum b/go.sum index 0d3b0ca..ffc9381 100644 --- a/go.sum +++ b/go.sum @@ -104,6 +104,12 @@ github.com/certifi/gocertifi v0.0.0-20190105021004-abcd57078448/go.mod h1:GJKEex github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/chromedp/cdproto v0.0.0-20240202021202-6d0b6a386732 h1:XYUCaZrW8ckGWlCRJKCSoh/iFwlpX316a8yY9IFEzv8= +github.com/chromedp/cdproto v0.0.0-20240202021202-6d0b6a386732/go.mod h1:GKljq0VrfU4D5yc+2qA6OVr8pmO/MBbPEWqWQ/oqGEs= +github.com/chromedp/chromedp v0.9.5 h1:viASzruPJOiThk7c5bueOUY91jGLJVximoEMGoH93rg= +github.com/chromedp/chromedp v0.9.5/go.mod h1:D4I2qONslauw/C7INoCir1BJkSwBYMyZgx8X276z3+Y= +github.com/chromedp/sysutil v1.0.0 h1:+ZxhTpfpZlmchB58ih/LBHX52ky7w2VhQVKQMucy3Ic= +github.com/chromedp/sysutil v1.0.0/go.mod h1:kgWmDdq8fTzXYcKIBqIYvRRTnYb9aNS9moAV0xufSww= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= @@ -113,64 +119,30 @@ github.com/clbanning/mxj v1.8.4/go.mod h1:BVjHeAH+rl9rs6f+QIpeRl0tfu10SXn1pUSa5P github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cloudwego/base64x v0.1.6 h1:t11wG9AECkCDk5fMSoxmufanudBtJ+/HemLstXDLI2M= github.com/cloudwego/base64x v0.1.6/go.mod h1:OFcloc187FXDaYHvrNIjxSe8ncn0OOM8gEHfghB2IPU= -github.com/cloudwego/eino v0.5.14 h1:cthGepU40W75YXYGjpbfakVHrsBOXJhqXVLLcpY+UqM= -github.com/cloudwego/eino v0.5.14/go.mod h1:N6E+toMzWw/3ql0IVM5n5lbYFCeblCYx7ebH16kt1JQ= -github.com/cloudwego/eino v0.6.2-0.20251119064845-207bfdd551a5 h1:wMWSasWJf7/VSe+AA4ZBgnP9Si6zEqZfAB86wtZwszg= -github.com/cloudwego/eino v0.6.2-0.20251119064845-207bfdd551a5/go.mod h1:JNapfU+QUrFFpboNDrNOFvmz0m9wjBFHHCr77RH6a50= -github.com/cloudwego/eino v0.6.2-0.20251120035928-4a4f0c16bdd3 h1:dUQXYicmUNZO/xM8wMKdICGJervM2JGwL37E92wVuW4= -github.com/cloudwego/eino v0.6.2-0.20251120035928-4a4f0c16bdd3/go.mod h1:JNapfU+QUrFFpboNDrNOFvmz0m9wjBFHHCr77RH6a50= -github.com/cloudwego/eino v0.6.2-0.20251120060359-fd8688de61e0 h1:UG+RnyF4kkD3G7W86JuuCcUUM2wE1VhxCVykqd3yo4c= -github.com/cloudwego/eino v0.6.2-0.20251120060359-fd8688de61e0/go.mod h1:JNapfU+QUrFFpboNDrNOFvmz0m9wjBFHHCr77RH6a50= -github.com/cloudwego/eino v0.6.2-0.20251120060852-4c29682b927c h1:XupuM1TJ8qEzADtqAnNkmZxbejg8kKvEzTlADOCcpfE= -github.com/cloudwego/eino v0.6.2-0.20251120060852-4c29682b927c/go.mod h1:JNapfU+QUrFFpboNDrNOFvmz0m9wjBFHHCr77RH6a50= github.com/cloudwego/eino v0.7.0 h1:XDGdGMZCAVx+OC0IxiLlyNFELoLN+56THUhYYqEujuM= github.com/cloudwego/eino v0.7.0/go.mod h1:JNapfU+QUrFFpboNDrNOFvmz0m9wjBFHHCr77RH6a50= -github.com/cloudwego/eino-ext/callbacks/cozeloop v0.1.4 h1:Cwm80+fMEAoY7uI9XUukDEV5J3Adb9HiXKmcXpXcDiM= -github.com/cloudwego/eino-ext/callbacks/cozeloop v0.1.4/go.mod h1:xxjNsJeZwdIooEYTt6tjw/YJzkA6xPcxn1u/HvA5xc0= github.com/cloudwego/eino-ext/callbacks/cozeloop v0.1.6 h1:gS4nAOpQQC5WItt1k32yjZt9O2UWMpnbgF6vkMQAWhg= github.com/cloudwego/eino-ext/callbacks/cozeloop v0.1.6/go.mod h1:ZniRkgN+9FUFxtN60X7yzD6UOruqrKQusjrOiGcH4I8= -github.com/cloudwego/eino-ext/components/document/parser/html v0.0.0-20250117061805-cd80d1780d76 h1:kK4f2kunb5xlc0XTkg6wkjy8Z/BDfJjWAVm9EOdRErg= -github.com/cloudwego/eino-ext/components/document/parser/html v0.0.0-20250117061805-cd80d1780d76/go.mod h1:LWR+h0EfIELl/I1tDSVH0Tgx8j2gymxa174U1C8BNps= github.com/cloudwego/eino-ext/components/document/parser/html v0.0.0-20251117090452-bd6375a0b3cf h1:Uwh3VT+xPrfDjM677dj1pSidCzBFoTrYlC274kEci5w= github.com/cloudwego/eino-ext/components/document/parser/html v0.0.0-20251117090452-bd6375a0b3cf/go.mod h1:DBwsPrdNxPeE3HNr5XyjjFreG4ypqCUjN0T2C2JSy6k= -github.com/cloudwego/eino-ext/components/document/parser/pdf v0.0.0-20250117061805-cd80d1780d76 h1:GJ4OqxyBH8la8Gu4PhTHXZNZFmrtEIrrymkCEpJ7XZU= -github.com/cloudwego/eino-ext/components/document/parser/pdf v0.0.0-20250117061805-cd80d1780d76/go.mod h1:swAgO0nNekTSKGgFqiy4zShKaCDhiIZoKEFwpi7NBFE= github.com/cloudwego/eino-ext/components/document/parser/pdf v0.0.0-20251117090452-bd6375a0b3cf h1:0KFSxuvFqs9dJ3Pu9Lk+4+Stt43I2u9eu3L4gDNcZ4A= github.com/cloudwego/eino-ext/components/document/parser/pdf v0.0.0-20251117090452-bd6375a0b3cf/go.mod h1:kHC3xkGM/gv3IHpOk33p75BfBaEIYATOs2XmYFKffcs= -github.com/cloudwego/eino-ext/components/model/ark v0.1.41 h1:l+WDY/nR1A5CzNkOJ+394EY+TxaW+NC5if1gnwcsvtE= -github.com/cloudwego/eino-ext/components/model/ark v0.1.41/go.mod h1:RIJTJsjS1Z1Xrldk6oeIkM0IHFasmYVfPh4b6ceExpY= github.com/cloudwego/eino-ext/components/model/ark v0.1.45 h1:LWvSHJVlvS1S/IxN9XUKNw/MI0I7YPePt3LMNxyCrZ0= github.com/cloudwego/eino-ext/components/model/ark v0.1.45/go.mod h1:e8P5dGVI/JMQ1FYNgmu5EFRWA8fivBc6NwNJ9g8FBK8= -github.com/cloudwego/eino-ext/components/model/deepseek v0.0.0-20250826125654-37d4a5029810 h1:zichoSWCoGqhUUwWscRNiTSH9j3KA8hReeEBMvr4i5w= -github.com/cloudwego/eino-ext/components/model/deepseek v0.0.0-20250826125654-37d4a5029810/go.mod h1:O6leaZBwE5s1wSsf5idW52Yaj1zWzhtjinSnfPXASNU= github.com/cloudwego/eino-ext/components/model/deepseek v0.0.0-20251117090452-bd6375a0b3cf h1:JA2W09VU+9zG9qRXheARRbi31cH+xHVzSJ/kFMxZvlo= github.com/cloudwego/eino-ext/components/model/deepseek v0.0.0-20251117090452-bd6375a0b3cf/go.mod h1:3AlAYkxwlOAP0SnFj7Yu1Lsgp8XHpbSMaE3l0+vDHKQ= -github.com/cloudwego/eino-ext/components/model/ollama v0.1.2 h1:WxJ+7oXnr3AhM6u4VbFF3L2ionxCrPfmLetx7V+zthw= -github.com/cloudwego/eino-ext/components/model/ollama v0.1.2/go.mod h1:OgGMCiR/G/RnOWaJvdK8pVSxAzoz2SlCqim43oFTuwo= github.com/cloudwego/eino-ext/components/model/ollama v0.1.6 h1:ZbrhV91uE0hGIOYXhb2i3G6tQJ/rK2SLYtoYrmocZXM= github.com/cloudwego/eino-ext/components/model/ollama v0.1.6/go.mod h1:GDXrvorGdRNV6g2mK5jdla2D8Xc/hh7XDrTeGDteLLo= -github.com/cloudwego/eino-ext/components/model/openai v0.0.0-20250826125654-37d4a5029810 h1:M8A7666rddupncJ4p3p1lH5jkNKtjzD7ULPE/I02o64= -github.com/cloudwego/eino-ext/components/model/openai v0.0.0-20250826125654-37d4a5029810/go.mod h1:QQhCuQxuBAVWvu/YAZBhs/RsR76mUigw59Tl0kh04C8= github.com/cloudwego/eino-ext/components/model/openai v0.1.5 h1:+yvGbTPw93li9GSmdm6Rix88Yy8AXg5NNBcRbWx3CQU= github.com/cloudwego/eino-ext/components/model/openai v0.1.5/go.mod h1:IPVYMFoZcuHeVEsDTGN6SZjvue0xr1iZFhdpq1SBWdQ= -github.com/cloudwego/eino-ext/components/retriever/volc_vikingdb v0.0.0-20250319082935-6219ec437e56 h1:yL7nTthGoz35dh7RK9lazxDedGmSmlss8HrtXmd0O3Q= -github.com/cloudwego/eino-ext/components/retriever/volc_vikingdb v0.0.0-20250319082935-6219ec437e56/go.mod h1:OPQYefu4EWAUcP0HhtzJK+UjLtQc8T9YzmxcAwFf29o= github.com/cloudwego/eino-ext/components/retriever/volc_vikingdb v0.0.0-20251120060928-25485ef519b5 h1:HoXqcYm3x4eXk6i2HLBklvx8WeFW7/MxijpCsEBQLSE= github.com/cloudwego/eino-ext/components/retriever/volc_vikingdb v0.0.0-20251120060928-25485ef519b5/go.mod h1:He7AHJpLTs0MXKPx5JpI8MdYtLUcKhUAZwCsgNtaq6k= -github.com/cloudwego/eino-ext/components/tool/commandline v0.0.0-20251111090228-91a10bbc864f h1:JkELXl5NquNnDgi81T3uiPfgpfcXzH81e3B/NDO4cwM= -github.com/cloudwego/eino-ext/components/tool/commandline v0.0.0-20251111090228-91a10bbc864f/go.mod h1:WfhOxJY7J2ZqY9muahNOMtypoe4ovcAG1E97y4bQPfU= github.com/cloudwego/eino-ext/components/tool/commandline v0.0.0-20251117090452-bd6375a0b3cf h1:LLyVGanJpHpSSiqsbRXkuSpdpc1UmuaUIEs/BiOQkH4= github.com/cloudwego/eino-ext/components/tool/commandline v0.0.0-20251117090452-bd6375a0b3cf/go.mod h1:cMZb1KM71kM+2hTJwxLwXT+HC66HimZirDDA5Oo64Hw= -github.com/cloudwego/eino-ext/components/tool/duckduckgo/v2 v2.0.0-20250826125654-37d4a5029810 h1:VtmhPdOY6wFR34Hdm4HNzWF9bwGz11x1TqBr8VpJDoc= -github.com/cloudwego/eino-ext/components/tool/duckduckgo/v2 v2.0.0-20250826125654-37d4a5029810/go.mod h1:QB9TkAu6OVDvQm5hEoK+VFVIbfDHO+ZQyUR2cPSo6jk= github.com/cloudwego/eino-ext/components/tool/duckduckgo/v2 v2.0.0-20251117090452-bd6375a0b3cf h1:54xcNETtXP1gYieDuNyOIvzE4Mk/jOxjlqCERr4cxTk= github.com/cloudwego/eino-ext/components/tool/duckduckgo/v2 v2.0.0-20251117090452-bd6375a0b3cf/go.mod h1:Np0BXy/9hPRu3wCgn+ij6L7YsjFcybVzg1k7uYOXh0M= -github.com/cloudwego/eino-ext/devops v0.1.7 h1:w8q4SGDtrZk+8WUrLyVidX7GNsyWFsYPPz5HoJKgRcA= -github.com/cloudwego/eino-ext/devops v0.1.7/go.mod h1:W53NPBmkmM7ClyQqwOcFUC2kV4bsvCfh2FtHUcyMzMY= github.com/cloudwego/eino-ext/devops v0.1.8 h1:qBg5vjZSDnd9tHzCHG8YsjnGB5vKG2EoZuuQCI8qrGs= github.com/cloudwego/eino-ext/devops v0.1.8/go.mod h1:8yjvPNTaB5Ve4aJmJ0ysFgB10y3YbIuqMh0/Uwt5Fnw= -github.com/cloudwego/eino-ext/libs/acl/openai v0.0.0-20250826113018-8c6f6358d4bb h1:RMslzyijc3bi9EkqCulpS0hZupTl1y/wayR3+fVRN/c= -github.com/cloudwego/eino-ext/libs/acl/openai v0.0.0-20250826113018-8c6f6358d4bb/go.mod h1:fHn/6OqPPY1iLLx9wzz+MEVT5Dl9gwuZte1oLEnCoYw= github.com/cloudwego/eino-ext/libs/acl/openai v0.1.2 h1:r9Id2wzJ05PoHl+Km7jQgNMgciaZI93TVnUYso89esM= github.com/cloudwego/eino-ext/libs/acl/openai v0.1.2/go.mod h1:S4OkvglPY9hsm9tXeShODrf/WN1Cgu4bqu4nn/CnIic= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= @@ -184,8 +156,6 @@ github.com/corpix/uarand v0.2.0 h1:U98xXwud/AVuCpkpgfPF7J5TQgr7R5tqT8VZP5KWbzE= github.com/corpix/uarand v0.2.0/go.mod h1:/3Z1QIqWkDIhf6XWn/08/uMHoQ8JUoTIKc2iPchBOmM= github.com/coze-dev/cozeloop-go v0.1.11 h1:NzdBKK3klhRgnPEH/PCjtP21+cRuz6qZlKPmJC7bkiM= github.com/coze-dev/cozeloop-go v0.1.11/go.mod h1:GDF+MpqsUsq4oKy+L1FTd6Giy2cAmr/xXl9rOnub39A= -github.com/coze-dev/cozeloop-go/spec v0.1.4 h1:6yhjFQ39yn9VkZ68QG2W5WjzICl6GgwVsXmDmn75ySg= -github.com/coze-dev/cozeloop-go/spec v0.1.4/go.mod h1:/f3BrWehffwXIpd4b5rYIqktLd/v5dlLBw0h9F/LQIU= github.com/coze-dev/cozeloop-go/spec v0.1.5 h1:tEQ82qlz9/HZv8MqyZq+043SaHs5C44MWslyGm5UcNI= github.com/coze-dev/cozeloop-go/spec v0.1.5/go.mod h1:/f3BrWehffwXIpd4b5rYIqktLd/v5dlLBw0h9F/LQIU= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= @@ -229,8 +199,6 @@ github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2 github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/getkin/kin-openapi v0.118.0 h1:z43njxPmJ7TaPpMSCQb7PN0dEYno4tyBPQcrFdHoLuM= -github.com/getkin/kin-openapi v0.118.0/go.mod h1:l5e9PaFUo9fyLJCPGQeXI2ML8c3P8BHOEV2VaAVf/pc= github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-check/check v0.0.0-20180628173108-788fd7840127 h1:0gkP6mzaMqkmpcJYCFOLkIBwI7xFExG03bbkOkCvUPI= @@ -249,19 +217,17 @@ github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= -github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= -github.com/go-openapi/jsonpointer v0.21.1 h1:whnzv/pNXtK2FbX/W9yJfRmE2gsmkfahjMKB0fZvcic= -github.com/go-openapi/jsonpointer v0.21.1/go.mod h1:50I1STOfbY1ycR8jGz8DaMeLCdXiI6aDteEdRNNzpdk= -github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= -github.com/go-openapi/swag v0.23.1 h1:lpsStH0n2ittzTnbaSloVZLuB5+fvSY/+hnagBjSNZU= -github.com/go-openapi/swag v0.23.1/go.mod h1:STZs8TbRvEQQKUA+JZNAm3EWlgaOBGpyFDqQnDHMef0= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= -github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM= -github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= github.com/go-zookeeper/zk v1.0.2/go.mod h1:nOB03cncLtlp4t+UAkGSV+9beXP/akpekBwL+UX1Qcw= +github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU= +github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM= +github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og= +github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= +github.com/gobwas/ws v1.3.2 h1:zlnbNHxumkRvfPWgfXu8RBwyNR1x8wh9cf5PTOCqs9Q= +github.com/gobwas/ws v1.3.2/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= @@ -385,9 +351,6 @@ github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpO github.com/hudl/fargo v1.4.0/go.mod h1:9Ai6uvFy5fQNq6VPKtg+Ceq1+eTY4nKUlR2JElEOcDo= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/influxdata/influxdb1-client v0.0.0-20200827194710-b269163b24ab/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= -github.com/invopop/yaml v0.1.0/go.mod h1:2XuRLgs/ouIrW3XNzuNj7J3Nvu/Dig5MXvbCEdiBN3Q= -github.com/invopop/yaml v0.3.1 h1:f0+ZpmhfBSS4MhG+4HYseMdJhoeeopbSKbq5Rpeelso= -github.com/invopop/yaml v0.3.1/go.mod h1:PMOp3nn4/12yEZUFfmOuNHJsZToEEOwoWsT+D81KkeA= github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs= github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM= github.com/jcmturner/gofork v1.0.0/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o= @@ -439,8 +402,8 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80 h1:6Yzfa6GP0rIo/kULo2bwGEkFvCePZ3qHDDTC3/J9Swo= +github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80/go.mod h1:imJHygn/1yfhB7XSJJKlFZKl/J+dCPAknuiaGOshXAs= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4= github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= @@ -461,8 +424,6 @@ github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27k github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/meguminnnnnnnnn/go-openai v0.0.0-20250821095446-07791bea23a0 h1:nIohpHs1ViKR0SVgW/cbBstHjmnqFZDM9RqgX9m9Xu8= -github.com/meguminnnnnnnnn/go-openai v0.0.0-20250821095446-07791bea23a0/go.mod h1:qs96ysDmxhE4BZoU45I43zcyfnaYxU3X+aRzLko/htY= github.com/meguminnnnnnnnn/go-openai v0.1.0 h1:BGzB1PlS2Epq0mBB2TGLwzMihbR7BANrlMH3w4ZnY88= github.com/meguminnnnnnnnn/go-openai v0.1.0/go.mod h1:qs96ysDmxhE4BZoU45I43zcyfnaYxU3X+aRzLko/htY= github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4= @@ -487,8 +448,6 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw= -github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/nats-io/jwt v1.2.2/go.mod h1:/xX356yQA6LuXI9xWW7mZNpxgF2mBmGecH+Fj34sP5Q= @@ -527,14 +486,13 @@ github.com/openai/openai-go v1.10.1 h1:7VR8z1foqJDjlaFZsNH5zZIYTWKYz97tdsVSzXDHQ github.com/openai/openai-go v1.10.1/go.mod h1:g461MYGXEXBVdV5SaR/5tNzNbSfwTBBefwc+LlDCK0Y= github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= github.com/openzipkin/zipkin-go v0.2.5/go.mod h1:KpXfKdgRDnnhsxw4pNIH9Md5lyFqKUa4YDFlwRYAMyE= +github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde h1:x0TT0RDC7UhAVbbWWBzr41ElhJx5tXPWkIHA2HWPRuw= +github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde/go.mod h1:nZgzbfBr3hhjoZnS66nKrHmduYNpc34ny7RK4z5/HM0= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= github.com/performancecopilot/speed/v4 v4.0.0/go.mod h1:qxrSyuDGrTOWfV+uKRFhfxw6h/4HXRGUiZiufxo49BM= -github.com/perimeterx/marshmallow v1.1.4/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw= -github.com/perimeterx/marshmallow v1.1.5 h1:a2LALqQ1BlHM8PZblsDdidgv1mWi1DgC2UmX50IvK2s= -github.com/perimeterx/marshmallow v1.1.5/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw= github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -618,7 +576,6 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= @@ -638,18 +595,12 @@ github.com/tiendc/go-deepcopy v1.7.1/go.mod h1:4bKjNC2r7boYOkD2IOuZpYjmlDdzjbpTR github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= -github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M= -github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= -github.com/ugorji/go/codec v1.3.0 h1:Qd2W2sQawAfG8XSvzwhBeoGq71zXOC/Q1E9y/wUcsUA= -github.com/ugorji/go/codec v1.3.0/go.mod h1:pRBVtBSKl77K30Bv8R2P+cLSGaTtex6fsA2Wjqmfxj4= github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= github.com/volcengine/volc-sdk-golang v1.0.23/go.mod h1:AfG/PZRUkHJ9inETvbjNifTDgut25Wbkm2QoYBTbvyU= -github.com/volcengine/volc-sdk-golang v1.0.196 h1:KYbX76ibTlNhgm6Kq3sDTjrujDBd0za8ULg0v7+sCag= -github.com/volcengine/volc-sdk-golang v1.0.196/go.mod h1:stZX+EPgv1vF4nZwOlEe8iGcriUPRBKX8zA19gXycOQ= github.com/volcengine/volc-sdk-golang v1.0.199 h1:zv9QOqTl/IsLwtfC37GlJtcz6vMAHi+pjq8ILWjLYUc= github.com/volcengine/volc-sdk-golang v1.0.199/go.mod h1:stZX+EPgv1vF4nZwOlEe8iGcriUPRBKX8zA19gXycOQ= github.com/volcengine/volcengine-go-sdk v1.1.44 h1:WLoLlzt67ZlJeow55PPx65/Mh52DewVXqkHcFSodM9w= @@ -901,9 +852,11 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= @@ -1118,7 +1071,6 @@ gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=