diff --git a/adk/intro/http-sse-service/go.mod b/adk/intro/http-sse-service/go.mod index 8711a18e..750ea447 100644 --- a/adk/intro/http-sse-service/go.mod +++ b/adk/intro/http-sse-service/go.mod @@ -5,7 +5,7 @@ go 1.24.9 replace github.com/cloudwego/eino-examples => ../../.. require ( - github.com/cloudwego/eino v0.7.14 + github.com/cloudwego/eino v0.8.0-alpha.9.0.20260211023821-b67e4f278166 github.com/cloudwego/eino-examples v0.0.0-00010101000000-000000000000 github.com/cloudwego/hertz v0.10.3 github.com/hertz-contrib/sse v0.1.0 diff --git a/adk/intro/http-sse-service/go.sum b/adk/intro/http-sse-service/go.sum index e5b7a202..baecbb7f 100644 --- a/adk/intro/http-sse-service/go.sum +++ b/adk/intro/http-sse-service/go.sum @@ -109,6 +109,15 @@ github.com/cloudwego/eino v0.7.8/go.mod h1:nA8Vacmuqv3pqKBQbTWENBLQ8MmGmPt/WqiyL github.com/cloudwego/eino v0.7.11/go.mod h1:nA8Vacmuqv3pqKBQbTWENBLQ8MmGmPt/WqiyLeB8ohQ= github.com/cloudwego/eino v0.7.14-0.20251225084034-ff42791c540f/go.mod h1:nA8Vacmuqv3pqKBQbTWENBLQ8MmGmPt/WqiyLeB8ohQ= github.com/cloudwego/eino v0.7.14/go.mod h1:nA8Vacmuqv3pqKBQbTWENBLQ8MmGmPt/WqiyLeB8ohQ= +github.com/cloudwego/eino v0.7.29-0.20260130121528-3fb823425d31/go.mod h1:0iLy/Uz4g59+g25C6gc09GW0eIyFBeTuyiLN9QhdsHM= +github.com/cloudwego/eino v0.7.29-0.20260202090314-89ba5ca5a9be/go.mod h1:0iLy/Uz4g59+g25C6gc09GW0eIyFBeTuyiLN9QhdsHM= +github.com/cloudwego/eino v0.7.31-0.20260204074929-977c05998483/go.mod h1:0iLy/Uz4g59+g25C6gc09GW0eIyFBeTuyiLN9QhdsHM= +github.com/cloudwego/eino v0.7.31-0.20260205105245-cb09e7460a97/go.mod h1:0iLy/Uz4g59+g25C6gc09GW0eIyFBeTuyiLN9QhdsHM= +github.com/cloudwego/eino v0.8.0-alpha.7.0.20260205152710-8af2c0187369/go.mod h1:R/UcCjduEJKpdX4rSYPmBd61NP/NN8gdqQxh7skdv4c= +github.com/cloudwego/eino v0.8.0-alpha.7.0.20260206030624-f887fed57622/go.mod h1:R/UcCjduEJKpdX4rSYPmBd61NP/NN8gdqQxh7skdv4c= +github.com/cloudwego/eino v0.8.0-alpha.9.0.20260210082916-506fc587712e/go.mod h1:R/UcCjduEJKpdX4rSYPmBd61NP/NN8gdqQxh7skdv4c= +github.com/cloudwego/eino v0.8.0-alpha.9.0.20260210144928-3c889d42331c/go.mod h1:R/UcCjduEJKpdX4rSYPmBd61NP/NN8gdqQxh7skdv4c= +github.com/cloudwego/eino v0.8.0-alpha.9.0.20260211023821-b67e4f278166/go.mod h1:R/UcCjduEJKpdX4rSYPmBd61NP/NN8gdqQxh7skdv4c= 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/openai v0.1.5 h1:+yvGbTPw93li9GSmdm6Rix88Yy8AXg5NNBcRbWx3CQU= diff --git a/adk/middlewares/summarization/history.json b/adk/middlewares/summarization/history.json new file mode 100644 index 00000000..f31ed632 --- /dev/null +++ b/adk/middlewares/summarization/history.json @@ -0,0 +1,82 @@ +[ + { + "role": "system", + "content": "You are a helpful assistant that can help users plan their trips." + }, + { + "role": "user", + "content": "Hello" + }, + { + "role": "assistant", + "content": "Hi! What can I help you with? For example: itinerary planning, information lookup, or organizing things into a table." + }, + { + "role": "user", + "content": "I'd like to do a one-day trip to Hangzhou this weekend. I prefer a relaxed route. Can you plan it for me?" + }, + { + "role": "assistant", + "content": "Sure. I'll first check the weather in Hangzhou this weekend so we can balance outdoor vs. indoor activities.", + "tool_calls": [ + { + "id": "call_001", + "type": "function", + "function": { + "name": "get_weather", + "arguments": "{\"city\":\"Hangzhou\",\"date\":\"2026-02-07\"}" + } + } + ] + }, + { + "role": "tool", + "tool_name": "get_weather", + "tool_call_id": "call_001", + "content": "{\"city\":\"Hangzhou\",\"date\":\"2026-02-07\",\"forecast\":\"Cloudy turning to light rain\",\"temp_c\":\"6~12\",\"wind\":\"Northeast wind, level 3\",\"advice\":[\"Bring an umbrella\",\"Wear a waterproof jacket\",\"Schedule outdoor activities earlier\"]}" + }, + { + "role": "assistant", + "content": "The forecast is cloudy turning to light rain. I'd recommend doing the main outdoor part in the morning, and leaving more indoor / easily-switchable activities for the afternoon.\n\nHere's a relaxed one-day route (default starting from Hangzhou East Railway Station (Hangzhou Dongzhan) / downtown):\n1) 09:00-11:30 West Lake (Xihu): Broken Bridge (Duanqiao) - Bai Causeway (Bai Di) - Su Causeway (Su Di), slow-paced walk\n2) 11:30-12:30 Lunch (choose around West Lake to avoid backtracking)\n3) 13:00-14:30 China National Silk Museum / Zhejiang Provincial Museum (prefer indoor if it rains)\n4) 15:00-16:30 Hefang Street (Hefang Jie) / Southern Song Imperial Street (Nansong Yujie) (walkable in light rain; watch for slippery ground)\n5) 17:00-18:30 Dinner and return\n\nDo you prefer nature scenery (West Lake / Jiuxi (Jiuxi Shibajian)) or museums (Zhejiang Provincial Museum / Silk Museum)? I can fine-tune the plan based on your preference." + }, + { + "role": "user", + "content": "I prefer staying around West Lake. Budget is within 150 CNY per person. I'd like Hangzhou cuisine for lunch, ideally with shorter queues." + }, + { + "role": "assistant", + "content": "Got it. I'll look up lunch options around West Lake with per-person budget <= 150 CNY, Hangzhou cuisine, and usually manageable queue times.", + "tool_calls": [ + { + "id": "call_002", + "type": "function", + "function": { + "name": "search_restaurants", + "arguments": "{\"city\":\"Hangzhou\",\"area\":\"Around West Lake Scenic Area\",\"cuisine\":\"Hangzhou cuisine\",\"price_per_person_max\":150,\"constraints\":[\"shorter queues\",\"lunch\"]}" + } + } + ] + }, + { + "role": "tool", + "tool_name": "search_restaurants", + "tool_call_id": "call_002", + "content": "{\n \"candidates\":[\n {\"name\":\"Hangwei Xiaoguan (West Lake Branch)\",\"price_per_person\":90,\"distance\":\"~1.2km from Broken Bridge (Duanqiao)\",\"queue_level\":\"Low~Medium\",\"recommended\":[\"West Lake Vinegar Fish\",\"Longjing Shrimp\",\"Pian'erchuan noodles\"],\"note\":\"Shorter queues on weekdays / arriving early helps\"},\n {\"name\":\"Home-Style Hangzhou Cuisine (Hubin Branch)\",\"price_per_person\":110,\"distance\":\"~0.6km from Hubin Pedestrian Street\",\"queue_level\":\"Medium\",\"recommended\":[\"Dongpo Pork\",\"Beggar's Chicken\",\"Sister Song Fish Soup\"],\"note\":\"At lunch peak, try to arrive before 11:10\"},\n {\"name\":\"Xiaohe Straight Street Hangzhou Cuisine\",\"price_per_person\":120,\"distance\":\"~20 minutes by taxi\",\"queue_level\":\"Low\",\"recommended\":[\"Soy-braised duck\",\"Stir-fried river shrimp\",\"Bamboo shoots & duck soup\"],\"note\":\"A bit farther from West Lake but quieter\"}\n ]\n}" + }, + { + "role": "assistant", + "content": "Based on your budget (<= 150 CNY), Hangzhou cuisine, and trying to minimize waiting, here are 3 lunch options (from \"most convenient\" to \"quietest\"): \n\nA) Hangwei Xiaoguan (West Lake Branch) (best fit with the West Lake walking route)\n- Suggested arrival: around 11:10\n- Recommended: Longjing Shrimp + Pian'erchuan noodles + seasonal greens\n\nB) Home-Style Hangzhou Cuisine (Hubin Branch) (close to the pedestrian street; easy to continue after lunch)\n- Suggested arrival: 11:00-11:15\n- Recommended: Dongpo Pork + Sister Song Fish Soup + seasonal greens\n\nC) Xiaohe Straight Street area (quieter and usually shorter queues, but breaks the West Lake walking flow)\n- Best if: you want a more comfortable dining pace\n\nWhere are you starting from (Hangzhou East Railway Station / Wulin Square / Hubin area)? I can insert the lunch spot into your West Lake route precisely to avoid backtracking." + }, + { + "role": "user", + "content": "Starting from Hangzhou East Railway Station. Please organize your one-day itinerary into a table including time / place / transportation / notes." + }, + { + "role": "assistant", + "content": "| Time | Place | Transportation | Notes |\n|---|---|---|---|\n| 09:00 | Hangzhou East Railway Station (Hangzhou Dongzhan) → Broken Bridge (Duanqiao), West Lake (Xihu) | Metro / taxi (either) | Leave early to avoid crowds and finish outdoor parts first |\n| 09:30-11:30 | West Lake (Xihu): Broken Bridge - Bai Causeway - Su Causeway (relaxed walk) | Walk | Cloudy turning to light rain; bring an umbrella and wear non-slip shoes |\n| 11:30-12:30 | Lunch (Hangzhou cuisine) | Walk / short taxi ride | Arrive before ~11:10 to reduce waiting |\n| 13:00-14:30 | Indoor backup: China National Silk Museum / Zhejiang Provincial Museum | Taxi / bus | If it rains, prioritize indoor; keep the pace relaxed |\n| 15:00-16:30 | Hefang Street (Hefang Jie) / Southern Song Imperial Street (Nansong Yujie) | Taxi / metro + walk | Walkable in light rain; watch for slippery ground |\n| 17:00-18:30 | Dinner & return | Taxi / metro depending on location | If you're not energetic, pick a dinner spot near a metro station |" + }, + { + "role": "user", + "content": "Finally, give me a summary within 50 words, and list 3 things to note." + } +] \ No newline at end of file diff --git a/adk/middlewares/summarization/main.go b/adk/middlewares/summarization/main.go new file mode 100644 index 00000000..09f86dd1 --- /dev/null +++ b/adk/middlewares/summarization/main.go @@ -0,0 +1,104 @@ +/* + * Copyright 2026 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" + "encoding/json" + "fmt" + "log" + "os" + "path/filepath" + + "github.com/bytedance/sonic" + "github.com/cloudwego/eino-ext/components/model/ark" + "github.com/cloudwego/eino/adk" + "github.com/cloudwego/eino/adk/middlewares/summarization" + "github.com/cloudwego/eino/schema" +) + +func loadMessagesFromJSONFile(fileName string) ([]adk.Message, error) { + wd, err := os.Getwd() + if err != nil { + return nil, fmt.Errorf("get current working directory failed: %w", err) + } + + filePath := filepath.Join(wd, "adk", "middlewares", "summarization", fileName) + + data, err := os.ReadFile(filePath) + if err != nil { + return nil, fmt.Errorf("read messages json failed: %w", err) + } + + var msgs []*schema.Message + if err := json.Unmarshal(data, &msgs); err != nil { + return nil, fmt.Errorf("unmarshal into []*schema.Message failed: %w", err) + } + + return msgs, nil +} + +func main() { + ctx := context.Background() + + adk.SetLanguage(adk.LanguageChinese) + + cm, err := ark.NewChatModel(ctx, &ark.ChatModelConfig{ + APIKey: os.Getenv("ARK_API_KEY"), + Model: os.Getenv("ARK_MODEL_ID"), + }) + if err != nil { + log.Fatalf("failed to create chat model: %v", err) + } + + mw, err := summarization.New(ctx, &summarization.Config{ + Model: cm, + Trigger: &summarization.TriggerCondition{ + ContextTokens: 500, + }, + TranscriptFilePath: "/adk/middlewares/summarization/history.json", + }) + if err != nil { + log.Fatalf("failed to create summarization middleware: %v", err) + } + + msgs, err := loadMessagesFromJSONFile("history.json") + if err != nil { + log.Fatalf("failed to load messages: %v", err) + } + + state := &adk.ChatModelAgentState{Messages: msgs} + + _, newState, err := mw.BeforeModelRewriteState(ctx, state, &adk.ModelContext{}) + if err != nil { + log.Fatalf("failed to summarize messages: %v", err) + } + + output, err := cm.Generate(ctx, newState.Messages) + if err != nil { + log.Fatalf("failed to generate messages: %v", err) + } + + history := append(newState.Messages, output) + + s, err := sonic.MarshalIndent(history, "", " ") + if err != nil { + log.Fatalf("failed to marshal messages: %v", err) + } + + fmt.Println(string(s)) +} diff --git a/go.mod b/go.mod index f0389cd6..784333ea 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/alicebob/miniredis/v2 v2.35.0 github.com/bytedance/sonic v1.14.2 github.com/chromedp/chromedp v0.9.5 - github.com/cloudwego/eino v0.7.22 + github.com/cloudwego/eino v0.8.0-alpha.9.0.20260211023821-b67e4f278166 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 diff --git a/go.sum b/go.sum index bc21f9c6..2378ed59 100644 --- a/go.sum +++ b/go.sum @@ -127,14 +127,14 @@ 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.7.14 h1:Ff62Z3dhdaGMFKG0cAVjcWfY7lb6mTkkBv4WFfdDU2k= -github.com/cloudwego/eino v0.7.14/go.mod h1:nA8Vacmuqv3pqKBQbTWENBLQ8MmGmPt/WqiyLeB8ohQ= -github.com/cloudwego/eino v0.7.21 h1:kkq7hlHYzwkGOAMbY4ffym4oBT7e9g5hXpJTsZbhsik= -github.com/cloudwego/eino v0.7.21/go.mod h1:nA8Vacmuqv3pqKBQbTWENBLQ8MmGmPt/WqiyLeB8ohQ= -github.com/cloudwego/eino v0.7.22-0.20260119120351-c3d518fff972 h1:qxtj2YY+Z0aMzBCyzeD/S9grWDguOJinAjyadlsXsaU= -github.com/cloudwego/eino v0.7.22-0.20260119120351-c3d518fff972/go.mod h1:nA8Vacmuqv3pqKBQbTWENBLQ8MmGmPt/WqiyLeB8ohQ= -github.com/cloudwego/eino v0.7.22 h1:GiDt+MHoOsgjIN3rI6ECiQ+NX1UIr0NzLKMdjOltHBc= -github.com/cloudwego/eino v0.7.22/go.mod h1:nA8Vacmuqv3pqKBQbTWENBLQ8MmGmPt/WqiyLeB8ohQ= +github.com/cloudwego/eino v0.8.0-alpha.9.0.20260210081918-b9b81899ad08 h1:D02BZu1qDL54uvMZc4CsQzEzrED5JH04sih1iVk99QQ= +github.com/cloudwego/eino v0.8.0-alpha.9.0.20260210081918-b9b81899ad08/go.mod h1:R/UcCjduEJKpdX4rSYPmBd61NP/NN8gdqQxh7skdv4c= +github.com/cloudwego/eino v0.8.0-alpha.9.0.20260210082916-506fc587712e h1:1umN5N1cVu2ozBRzPPfdYAJdI3ZB+6IsqNplXjU89ZQ= +github.com/cloudwego/eino v0.8.0-alpha.9.0.20260210082916-506fc587712e/go.mod h1:R/UcCjduEJKpdX4rSYPmBd61NP/NN8gdqQxh7skdv4c= +github.com/cloudwego/eino v0.8.0-alpha.9.0.20260210144928-3c889d42331c h1:pvQdnJE1rY+4t1q23nEzU/aBQiC4YNMEHptGpoTID+E= +github.com/cloudwego/eino v0.8.0-alpha.9.0.20260210144928-3c889d42331c/go.mod h1:R/UcCjduEJKpdX4rSYPmBd61NP/NN8gdqQxh7skdv4c= +github.com/cloudwego/eino v0.8.0-alpha.9.0.20260211023821-b67e4f278166 h1:+YFzMlv+6wXCGTb6yxFfJjsuV4eubrc5iJ9/o+hpNcI= +github.com/cloudwego/eino v0.8.0-alpha.9.0.20260211023821-b67e4f278166/go.mod h1:R/UcCjduEJKpdX4rSYPmBd61NP/NN8gdqQxh7skdv4c= 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-20251117090452-bd6375a0b3cf h1:Uwh3VT+xPrfDjM677dj1pSidCzBFoTrYlC274kEci5w=