diff --git a/adk/intro/agent_with_summarization/agent.go b/adk/intro/agent_with_summarization/agent.go new file mode 100644 index 0000000..148da20 --- /dev/null +++ b/adk/intro/agent_with_summarization/agent.go @@ -0,0 +1,118 @@ +/* + * 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 main + +import ( + "context" + "log" + "time" + + "github.com/cloudwego/eino/adk" + "github.com/cloudwego/eino/components/tool" + "github.com/cloudwego/eino/compose" + + "github.com/cloudwego/eino-examples/adk/common/model" + "github.com/cloudwego/eino-examples/adk/common/prints" + "github.com/cloudwego/eino-examples/adk/common/trace" + "github.com/cloudwego/eino-examples/adk/intro/agent_with_summarization/summarization" + "github.com/cloudwego/eino-examples/internal/logs" +) + +const ( + summaryMaxTokensBefore = 10 * 1024 + summaryMaxTokensRecent = 2 * 1024 + agentMaxIterations = 30 +) + +func main() { + ctx := context.Background() + + a, err := newAgent(ctx) + if err != nil { + logs.Fatalf("create agent failed, err=%v", err) + } + + traceCloseFn, startSpanFn := trace.AppendCozeLoopCallbackIfConfigured(ctx) + defer traceCloseFn(ctx) + + runner := adk.NewRunner(ctx, adk.RunnerConfig{ + EnableStreaming: true, // you can disable streaming here + Agent: a, + }) + + query := `Write a very long report on the history of artificial intelligence.` + ctx, endSpanFn := startSpanFn(ctx, "Agent", query) + + iter := runner.Query(ctx, query) + + var lastMessage adk.Message + for { + event, ok := iter.Next() + if !ok { + break + } + if event.Err != nil { + log.Fatal(event.Err) + } + + prints.Event(event) + + if event.Output != nil { + lastMessage, _, err = adk.GetMessage(event) + } + + } + + endSpanFn(ctx, lastMessage) + + // wait for all span to be ended + time.Sleep(10 * time.Second) +} + +func newAgent(ctx context.Context) (adk.Agent, error) { + sumMW, err := summarization.New(ctx, &summarization.Config{ + Model: model.NewChatModel(), + MaxTokensBeforeSummary: summaryMaxTokensBefore, + MaxTokensForRecentMessages: summaryMaxTokensRecent, + }) + if err != nil { + return nil, err + } + + a, err := adk.NewChatModelAgent(ctx, &adk.ChatModelAgentConfig{ + Name: "main_agent", + Description: "A long-form report assistant", + Instruction: `You are a long-form report writer working in ReAct mode. +Think step by step, call tools to expand content by repeating paragraphs, then synthesize a cohesive response. +one time call one tool, do not call multiple tools in one turn. +Each tool call should indicate the call number. After 20 tool calls, produce a final summary.`, + Model: model.NewChatModel(), + Middlewares: []adk.AgentMiddleware{sumMW}, + ToolsConfig: adk.ToolsConfig{ + ToolsNodeConfig: compose.ToolsNodeConfig{ + Tools: []tool.BaseTool{ + NewRepeatSectionsTool(), + }, + }, + }, + MaxIterations: agentMaxIterations, + }) + if err != nil { + return nil, err + } + return a, nil +} diff --git a/adk/intro/agent_with_summarization/summarization/prompt.go b/adk/intro/agent_with_summarization/summarization/prompt.go new file mode 100644 index 0000000..2995bd9 --- /dev/null +++ b/adk/intro/agent_with_summarization/summarization/prompt.go @@ -0,0 +1,77 @@ +/* + * 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 summarization + +const DefaultMaxTokensBeforeSummary = 128 * 1024 +const DefaultMaxTokensForRecentMessages = 25 * 1024 // 20% of DefaultMaxTokensBeforeSummary +const PromptOfSummary = ` +Conversation Summarization Assistant for Multi-turn LLM Agent + + + +Summarize the older portion of the conversation history into a concise, accurate, and information-rich context summary. +The summary must preserve essential reasoning, actions, outcomes, and lessons learned, +allowing the agent to continue reasoning seamlessly without re-accessing the raw conversation data. + + + +- Include major progress, decisions made, reasoning steps, intermediate or final results, and lessons (both successes and failures). +- Emphasize failed attempts, misunderstandings, and improvements or adjustments that followed. +- Exclude irrelevant details, casual talk, and redundant confirmations. +- Maintain consistency with the current System Prompt and the user’s long-term goals. + + + +1. You will receive five tagged sections: + - The **system_prompt tag** — provides the current System Prompt (for reference only, do not summarize). + - The **user_messages tag** — contains early or persistent user instructions, preferences, and goals. Use it to maintain alignment with the user's long-term intent(for reference only, do not summarize). + - The **previous_summary tag** — contains the existing long-term summary, if available. + - The **older_messages tag** — includes earlier conversation messages to be summarized. + - The **recent_messages tag** — contains the most recent conversation window (for reference only, do not summarize). + +2. Your task: + - Merge the content from the previous_summary tag and the older_messages tag into a new refined long-term summary. + - When summarizing, integrate the key takeaways, decisions, lessons, and relevant state information. + - Use the user_messages tag to ensure the summary preserves the user's persistent intent and constraints (ignore transient chit-chat). + - Use the recent_messages tag only to maintain temporal and contextual continuity across turns. + +3. Output requirements: + - Respond **only** with the updated long-term summary that replaces the older conversation history. + - Do **not** include any extra headers, XML tags, or meta explanations in your output. + + + + +{system_prompt} + + + +{user_messages} + + + +{previous_summary} + + + +{older_messages} + + + +{recent_messages} + +` diff --git a/adk/intro/agent_with_summarization/summarization/summary.go b/adk/intro/agent_with_summarization/summarization/summary.go new file mode 100644 index 0000000..3a45465 --- /dev/null +++ b/adk/intro/agent_with_summarization/summarization/summary.go @@ -0,0 +1,403 @@ +/* + * 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 summarization + +import ( + "context" + "fmt" + "strings" + + "github.com/pkoukk/tiktoken-go" + + "github.com/cloudwego/eino/adk" + "github.com/cloudwego/eino/components/model" + "github.com/cloudwego/eino/components/prompt" + "github.com/cloudwego/eino/compose" + "github.com/cloudwego/eino/schema" +) + +type TokenCounter func(ctx context.Context, msgs []adk.Message) (tokenNum []int64, err error) + +// Config defines parameters for the conversation summarization middleware. +// It controls when summarization is triggered and how much recent context is retained. +// Required: Model. Optional: SystemPrompt, Counter, and token budgets. +type Config struct { + // MaxTokensBeforeSummary is the max token threshold to trigger summarization based on total context + // (system prompt + history). Uses DefaultMaxTokensBeforeSummary when <= 0. + MaxTokensBeforeSummary int + + // MaxTokensForRecentMessages is the max token budget reserved for recent messages after summarization. + // Uses DefaultMaxTokensForRecentMessages when <= 0. + MaxTokensForRecentMessages int + + // Counter custom token counter. + // Optional + Counter TokenCounter + + // Model used to generate the summary. Must be provided. + // Required. + Model model.BaseChatModel + + // SystemPrompt is the system prompt for the summarizer. + // Optional. If empty, PromptOfSummary is used. + SystemPrompt string +} + +// New creates an AgentMiddleware that compacts long conversation history +// into a single summary message when the token threshold is exceeded. +// The summarizer chain is: ChatTemplate(SystemPrompt) -> ChatModel(Model). +// It applies defaults for token budgets and allows a custom Counter. +func New(ctx context.Context, cfg *Config) (adk.AgentMiddleware, error) { + if cfg == nil { + return adk.AgentMiddleware{}, fmt.Errorf("config is nil") + } + + systemPrompt := cfg.SystemPrompt + if systemPrompt == "" { + systemPrompt = PromptOfSummary + } + maxBefore := DefaultMaxTokensBeforeSummary + if cfg.MaxTokensBeforeSummary > 0 { + maxBefore = cfg.MaxTokensBeforeSummary + } + maxRecent := DefaultMaxTokensForRecentMessages + if cfg.MaxTokensForRecentMessages > 0 { + maxRecent = cfg.MaxTokensForRecentMessages + } + + tpl := prompt.FromMessages(schema.FString, + schema.SystemMessage(systemPrompt), + schema.UserMessage("summarize 'older_messages': ")) + + summarizer, err := compose.NewChain[map[string]any, *schema.Message](). + AppendChatTemplate(tpl). + AppendChatModel(cfg.Model). + Compile(ctx, compose.WithGraphName("Summarizer")) + if err != nil { + return adk.AgentMiddleware{}, fmt.Errorf("compile summarizer failed, err=%w", err) + } + + sm := &summaryMiddleware{ + counter: defaultCounterToken, + maxBefore: maxBefore, + maxRecent: maxRecent, + summarizer: summarizer, + } + if cfg.Counter != nil { + sm.counter = cfg.Counter + } + return adk.AgentMiddleware{BeforeChatModel: sm.BeforeModel}, nil +} + +const summaryMessageFlag = "_agent_middleware_summary_message" + +type summaryMiddleware struct { + counter TokenCounter + maxBefore int + maxRecent int + + summarizer compose.Runnable[map[string]any, *schema.Message] +} + +func (s *summaryMiddleware) BeforeModel(ctx context.Context, state *adk.ChatModelAgentState) (err error) { + if state == nil || len(state.Messages) == 0 { + return nil + } + + messages := state.Messages + msgsToken, err := s.counter(ctx, messages) + if err != nil { + return fmt.Errorf("count token failed, err=%w", err) + } + if len(messages) != len(msgsToken) { + return fmt.Errorf("token count mismatch, msgNum=%d, tokenCountNum=%d", len(messages), len(msgsToken)) + } + + var total int64 + for _, t := range msgsToken { + total += t + } + // Trigger summarization only when exceeding threshold + if total <= int64(s.maxBefore) { + return nil + } + + // Build blocks with user-messages, summary-message, tool-call pairings + type block struct { + msgs []*schema.Message + tokens int64 + } + idx := 0 + + systemBlock := block{} + if idx < len(messages) { + m := messages[idx] + if m != nil && m.Role == schema.System { + systemBlock.msgs = append(systemBlock.msgs, m) + systemBlock.tokens += msgsToken[idx] + idx++ + } + } + userBlock := block{} + for idx < len(messages) { + m := messages[idx] + if m == nil { + idx++ + continue + } + if m.Role != schema.User { + break + } + userBlock.msgs = append(userBlock.msgs, m) + userBlock.tokens += msgsToken[idx] + idx++ + } + summaryBlock := block{} + if idx < len(messages) { + m := messages[idx] + if m != nil && m.Role == schema.Assistant { + if _, ok := m.Extra[summaryMessageFlag]; ok { + summaryBlock.msgs = append(summaryBlock.msgs, m) + summaryBlock.tokens += msgsToken[idx] + idx++ + } + } + } + + toolBlocks := make([]block, 0) + for i := idx; i < len(messages); i++ { + m := messages[i] + if m == nil { + continue + } + if m.Role == schema.Assistant && len(m.ToolCalls) > 0 { + b := block{msgs: []*schema.Message{m}, tokens: msgsToken[i]} + // Collect subsequent tool messages matching any tool call id + callIDs := make(map[string]struct{}, len(m.ToolCalls)) + for _, tc := range m.ToolCalls { + callIDs[tc.ID] = struct{}{} + } + j := i + 1 + for j < len(messages) { + nm := messages[j] + if nm == nil || nm.Role != schema.Tool { + break + } + // Match by ToolCallID when available; if empty, include but keep boundary + if nm.ToolCallID == "" { + b.msgs = append(b.msgs, nm) + b.tokens += msgsToken[j] + } else { + if _, ok := callIDs[nm.ToolCallID]; !ok { + // Tool message not belonging to this assistant call -> end pairing + break + } + b.msgs = append(b.msgs, nm) + b.tokens += msgsToken[j] + } + j++ + } + toolBlocks = append(toolBlocks, b) + i = j - 1 + continue + } + toolBlocks = append(toolBlocks, block{msgs: []*schema.Message{m}, tokens: msgsToken[i]}) + } + + // Split into recent and older within token budget, from newest to oldest + var recentBlocks []block + var olderBlocks []block + var recentTokens int64 + for i := len(toolBlocks) - 1; i >= 0; i-- { + b := toolBlocks[i] + if recentTokens+b.tokens > int64(s.maxRecent) { + olderBlocks = append([]block{b}, olderBlocks...) + continue + } + recentBlocks = append([]block{b}, recentBlocks...) + recentTokens += b.tokens + } + + joinBlocks := func(bs []block) string { + var sb strings.Builder + for _, b := range bs { + for _, m := range b.msgs { + sb.WriteString(renderMsg(m)) + sb.WriteString("\n") + } + } + return sb.String() + } + + olderText := joinBlocks(olderBlocks) + recentText := joinBlocks(recentBlocks) + + msg, err := s.summarizer.Invoke(ctx, map[string]any{ + "system_prompt": joinBlocks([]block{systemBlock}), + "user_messages": joinBlocks([]block{userBlock}), + "previous_summary": joinBlocks([]block{summaryBlock}), + "older_messages": olderText, + "recent_messages": recentText, + }) + if err != nil { + return fmt.Errorf("summarize failed, err=%w", err) + } + + summaryMsg := schema.AssistantMessage(msg.Content, nil) + msg.Name = "summary" + summaryMsg.Extra = map[string]any{ + summaryMessageFlag: true, + } + + // Build new state: prepend summary message, keep recent messages + newMessages := make([]*schema.Message, 0, len(messages)) + newMessages = append(newMessages, systemBlock.msgs...) + newMessages = append(newMessages, userBlock.msgs...) + newMessages = append(newMessages, summaryMsg) + for _, b := range recentBlocks { + newMessages = append(newMessages, b.msgs...) + } + + state.Messages = newMessages + return nil +} + +// Render messages into strings +func renderMsg(m *schema.Message) string { + if m == nil { + return "" + } + var sb strings.Builder + if m.Role == schema.Tool { + if m.ToolName != "" { + sb.WriteString("[tool:") + sb.WriteString(m.ToolName) + sb.WriteString("]\n") + } else { + sb.WriteString("[tool]\n") + } + } else { + sb.WriteString("[") + sb.WriteString(string(m.Role)) + sb.WriteString("]\n") + } + if m.Content != "" { + sb.WriteString(m.Content) + sb.WriteString("\n") + } + if m.Role == schema.Assistant && len(m.ToolCalls) > 0 { + for _, tc := range m.ToolCalls { + if tc.Function.Name != "" { + sb.WriteString("tool_call: ") + sb.WriteString(tc.Function.Name) + sb.WriteString("\n") + } + if tc.Function.Arguments != "" { + sb.WriteString("args: ") + sb.WriteString(tc.Function.Arguments) + sb.WriteString("\n") + } + } + } + for _, part := range m.UserInputMultiContent { + if part.Type == schema.ChatMessagePartTypeText && part.Text != "" { + sb.WriteString(part.Text) + sb.WriteString("\n") + } + } + for _, part := range m.AssistantGenMultiContent { + if part.Type == schema.ChatMessagePartTypeText && part.Text != "" { + sb.WriteString(part.Text) + sb.WriteString("\n") + } + } + return sb.String() +} + +func defaultCounterToken(ctx context.Context, msgs []adk.Message) (tokenNum []int64, err error) { + encoding := "cl100k_base" + tkt, err := tiktoken.GetEncoding(encoding) + if err != nil { + return nil, fmt.Errorf("get encoding failed, encoding=%v, err=%w", encoding, err) + } + tokenNum = make([]int64, len(msgs)) + + for i, m := range msgs { + if m == nil { + tokenNum[i] = 0 + continue + } + + var sb strings.Builder + + // Message role contributes to chat tokenization overhead; include it as text. + if m.Role != "" { + sb.WriteString(string(m.Role)) + sb.WriteString("\n") + } + + // Core text content + if m.Content != "" { + sb.WriteString(m.Content) + sb.WriteString("\n") + } + + // Reasoning content if present + // Reasoning Content is not used by model + // if m.ReasoningContent != "" { + // sb.WriteString(m.ReasoningContent) + // sb.WriteString("\n") + // } + + // Multi modal input/output text parts + for _, part := range m.UserInputMultiContent { + if part.Type == schema.ChatMessagePartTypeText && part.Text != "" { + sb.WriteString(part.Text) + sb.WriteString("\n") + } + } + for _, part := range m.AssistantGenMultiContent { + if part.Type == schema.ChatMessagePartTypeText && part.Text != "" { + sb.WriteString(part.Text) + sb.WriteString("\n") + } + } + + // Tool call textual context (name + arguments) + for _, tc := range m.ToolCalls { + if tc.Function.Name != "" { + sb.WriteString(tc.Function.Name) + sb.WriteString("\n") + } + if tc.Function.Arguments != "" { + sb.WriteString(tc.Function.Arguments) + sb.WriteString("\n") + } + } + + text := sb.String() + if text == "" { + tokenNum[i] = 0 + continue + } + + tokens := tkt.Encode(text, nil, nil) + tokenNum[i] = int64(len(tokens)) + } + + return tokenNum, nil +} diff --git a/adk/intro/agent_with_summarization/tools.go b/adk/intro/agent_with_summarization/tools.go new file mode 100644 index 0000000..5700bc8 --- /dev/null +++ b/adk/intro/agent_with_summarization/tools.go @@ -0,0 +1,77 @@ +/* + * 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 main + +import ( + "context" + "fmt" + "log" + "strconv" + "strings" + + "github.com/cloudwego/eino/adk" + "github.com/cloudwego/eino/components/tool" + "github.com/cloudwego/eino/components/tool/utils" +) + +type RepeatSectionsInput struct { + Title string `json:"title" jsonschema_description:"Section title"` + Paragraphs []string `json:"paragraphs" jsonschema_description:"Paragraphs to be repeated"` + RepeatCount int `json:"repeat_count" jsonschema_description:"Times to repeat paragraphs, default 2"` +} + +func NewRepeatSectionsTool() tool.InvokableTool { + t, err := utils.InferTool( + "repeat_sections", + "Repeat given paragraphs to quickly accumulate context", + func(ctx context.Context, in *RepeatSectionsInput) (string, error) { + if in.RepeatCount <= 0 { + in.RepeatCount = 2 + } + var b strings.Builder + b.WriteString("## ") + b.WriteString(in.Title) + b.WriteString("\n") + idx := 0 + for i := 0; i < in.RepeatCount; i++ { + for _, sec := range in.Paragraphs { + b.WriteString(strconv.Itoa(idx + 1)) + b.WriteString(". ") + b.WriteString(sec) + b.WriteString("\n") + idx++ + } + } + callCount := 0 + times, ok := adk.GetSessionValue(ctx, "_tool_call_count") + if !ok { + times = 0 + } else { + callCount = times.(int) + } + callCount++ + adk.AddSessionValue(ctx, "_tool_call_count", callCount) + + b.WriteString(fmt.Sprintf("Tool calls so far: %d", callCount)) + return b.String(), nil + }, + ) + if err != nil { + log.Fatalf("failed to create repeat_sections tool: %v", err) + } + return t +} diff --git a/flow/agent/multiagent/host/journal/answer_with_journal_specialist.go b/flow/agent/multiagent/host/journal/answer_with_journal_specialist.go index bd2c376..fe29748 100644 --- a/flow/agent/multiagent/host/journal/answer_with_journal_specialist.go +++ b/flow/agent/multiagent/host/journal/answer_with_journal_specialist.go @@ -29,7 +29,6 @@ import ( "github.com/cloudwego/eino/flow/agent" "github.com/cloudwego/eino/flow/agent/multiagent/host" "github.com/cloudwego/eino/schema" - "github.com/ollama/ollama/api" ) // search journal: user ask a question, this specialist load today's journal and ground its answer onto it. @@ -58,7 +57,7 @@ func newAnswerWithJournalSpecialist(ctx context.Context, baseURL, model string) BaseURL: baseURL, Model: model, - Options: &api.Options{ + Options: &ollama.Options{ Temperature: 0.000001, }, }) diff --git a/flow/agent/multiagent/host/journal/write_journal_specialist.go b/flow/agent/multiagent/host/journal/write_journal_specialist.go index 7578a9d..008a23c 100644 --- a/flow/agent/multiagent/host/journal/write_journal_specialist.go +++ b/flow/agent/multiagent/host/journal/write_journal_specialist.go @@ -27,7 +27,6 @@ import ( "github.com/cloudwego/eino/flow/agent" "github.com/cloudwego/eino/flow/agent/multiagent/host" "github.com/cloudwego/eino/schema" - "github.com/ollama/ollama/api" ) // create a specialist who can append text to the right local journal file @@ -81,7 +80,7 @@ func newWriteJournalSpecialist(ctx context.Context, baseURL, model string) (*hos BaseURL: baseURL, Model: model, - Options: &api.Options{ + Options: &ollama.Options{ Temperature: 0.000001, }, }) diff --git a/go.mod b/go.mod index afff774..879568f 100644 --- a/go.mod +++ b/go.mod @@ -7,17 +7,17 @@ toolchain go1.24.9 require ( github.com/bytedance/sonic v1.14.2 github.com/cloudwego/eino v0.7.0 - github.com/cloudwego/eino-ext/callbacks/cozeloop v0.1.4 - github.com/cloudwego/eino-ext/components/document/parser/html v0.0.0-20250117061805-cd80d1780d76 - github.com/cloudwego/eino-ext/components/document/parser/pdf v0.0.0-20250117061805-cd80d1780d76 - github.com/cloudwego/eino-ext/components/model/ark v0.1.41 - github.com/cloudwego/eino-ext/components/model/deepseek v0.0.0-20250826125654-37d4a5029810 - github.com/cloudwego/eino-ext/components/model/ollama v0.1.2 - github.com/cloudwego/eino-ext/components/model/openai v0.0.0-20250826125654-37d4a5029810 - github.com/cloudwego/eino-ext/components/retriever/volc_vikingdb v0.0.0-20250319082935-6219ec437e56 - github.com/cloudwego/eino-ext/components/tool/commandline v0.0.0-20251111090228-91a10bbc864f - github.com/cloudwego/eino-ext/components/tool/duckduckgo/v2 v2.0.0-20250826125654-37d4a5029810 - github.com/cloudwego/eino-ext/devops v0.1.7 + github.com/cloudwego/eino-ext/callbacks/cozeloop v0.1.6 + github.com/cloudwego/eino-ext/components/document/parser/html v0.0.0-20251117090452-bd6375a0b3cf + github.com/cloudwego/eino-ext/components/document/parser/pdf v0.0.0-20251117090452-bd6375a0b3cf + github.com/cloudwego/eino-ext/components/model/ark v0.1.45 + github.com/cloudwego/eino-ext/components/model/deepseek v0.0.0-20251117090452-bd6375a0b3cf + github.com/cloudwego/eino-ext/components/model/ollama v0.1.6 + github.com/cloudwego/eino-ext/components/model/openai v0.1.5 + github.com/cloudwego/eino-ext/components/retriever/volc_vikingdb v0.0.0-20251120060928-25485ef519b5 + github.com/cloudwego/eino-ext/components/tool/commandline v0.0.0-20251117090452-bd6375a0b3cf + github.com/cloudwego/eino-ext/components/tool/duckduckgo/v2 v2.0.0-20251117090452-bd6375a0b3cf + github.com/cloudwego/eino-ext/devops v0.1.8 github.com/coze-dev/cozeloop-go v0.1.11 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc github.com/eino-contrib/jsonschema v1.0.2 @@ -43,12 +43,14 @@ require ( github.com/bytedance/sonic/loader v0.4.0 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cloudwego/base64x v0.1.6 // indirect - github.com/cloudwego/eino-ext/libs/acl/openai v0.0.0-20250826113018-8c6f6358d4bb // indirect + github.com/cloudwego/eino-ext/libs/acl/openai v0.1.2 // indirect github.com/cohesion-org/deepseek-go v1.3.2 // indirect github.com/corpix/uarand v0.2.0 // indirect - github.com/coze-dev/cozeloop-go/spec v0.1.4 // indirect + github.com/coze-dev/cozeloop-go/spec v0.1.5 // indirect + github.com/dlclark/regexp2 v1.11.4 // indirect github.com/dslipak/pdf v0.0.2 // indirect 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 @@ -65,7 +67,7 @@ require ( github.com/mailru/easyjson v0.9.0 // indirect github.com/matoous/go-nanoid v1.5.1 // indirect github.com/mattn/go-colorable v0.1.14 // indirect - github.com/meguminnnnnnnnn/go-openai v0.0.0-20250821095446-07791bea23a0 // indirect + github.com/meguminnnnnnnnn/go-openai v0.1.0 // indirect 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 @@ -76,6 +78,7 @@ require ( 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 +93,7 @@ require ( 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.196 // indirect + github.com/volcengine/volc-sdk-golang v1.0.199 // indirect github.com/xuri/efp v0.0.1 // indirect github.com/xuri/nfp v0.0.2-0.20250530014748-2ddeb826f9a9 // indirect github.com/yargevad/filepathx v1.0.0 // indirect diff --git a/go.sum b/go.sum index d5de1f5..0d3b0ca 100644 --- a/go.sum +++ b/go.sum @@ -127,28 +127,52 @@ 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= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= @@ -162,12 +186,16 @@ github.com/coze-dev/cozeloop-go v0.1.11 h1:NzdBKK3klhRgnPEH/PCjtP21+cRuz6qZlKPmJ 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= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dlclark/regexp2 v1.11.4 h1:rPYF9/LECdNymJufQKmri9gV604RvvABwgOA8un7yAo= +github.com/dlclark/regexp2 v1.11.4/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= github.com/dslipak/pdf v0.0.2 h1:djAvcM5neg9Ush+zR6QXB+VMJzR6TdnX766HPIg1JmI= github.com/dslipak/pdf v0.0.2/go.mod h1:2L3SnkI9cQwnAS9gfPz2iUoLC0rUZwbucpbKi5R1mUo= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= @@ -180,6 +208,8 @@ github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFP github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/eino-contrib/jsonschema v1.0.2 h1:HaxruBMUdnXa7Lg/lX8g0Hk71ZIfdTZXmBQz0e3esr8= github.com/eino-contrib/jsonschema v1.0.2/go.mod h1:cpnX4SyKjWjGC7iN2EbhxaTdLqGjCi0e9DxpLYxddD4= +github.com/eino-contrib/ollama v0.1.0 h1:z1NaMdKW6X1ftP8g5xGGR5zDRPUtuTKFq35vBQgxsN4= +github.com/eino-contrib/ollama v0.1.0/go.mod h1:mYsQ7b3DeqY8bHPuD3MZJYTqkgyL6LoemxoP/B7ZNhA= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= @@ -433,6 +463,8 @@ github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D 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= github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= github.com/microcosm-cc/bluemonday v1.0.27 h1:MpEUotklkwCSLeH+Qdx1VJgNqLlpY2KXwXFM08ygZfk= @@ -510,6 +542,8 @@ github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= +github.com/pkoukk/tiktoken-go v0.1.8 h1:85ENo+3FpWgAACBaEUVp+lctuTcYUO7BtmfhlN/QTRo= +github.com/pkoukk/tiktoken-go v0.1.8/go.mod h1:9NiV+i9mJKGj1rYOT+njbv+ZwA/zJxYdewGl6qVatpg= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -616,6 +650,8 @@ github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+ 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= github.com/volcengine/volcengine-go-sdk v1.1.44/go.mod h1:oxoVo+A17kvkwPkIeIHPVLjSw7EQAm+l/Vau1YGHN+A= github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc=