From aa69b693e39dd7eda9eb478d2d7888c943975b87 Mon Sep 17 00:00:00 2001 From: Max Date: Fri, 14 Nov 2025 08:41:40 +0800 Subject: [PATCH] Enhance context handling and metadata management in assistant operations - Introduced a new test context creation function to streamline test setup for assistant operations. - Refactored context structure to replace the deprecated 'Data' field with 'Metadata', improving clarity and consistency. - Updated various methods to utilize the new 'Metadata' field, ensuring proper handling of request metadata across the system. - Adjusted tests to reflect changes in metadata handling, enhancing validation of context fields in JavaScript integration. --- agent/assistant/hook/create_test.go | 81 ++++++---- agent/context/context.go | 13 +- agent/context/jsapi.go | 67 ++++++++- agent/context/jsapi_test.go | 223 +++++++++++++++++++++++++++- agent/context/openapi.go | 80 +++++----- agent/context/openapi_test.go | 50 +++---- agent/context/types.go | 14 +- 7 files changed, 420 insertions(+), 108 deletions(-) diff --git a/agent/assistant/hook/create_test.go b/agent/assistant/hook/create_test.go index be4c681e..4ff8b31e 100644 --- a/agent/assistant/hook/create_test.go +++ b/agent/assistant/hook/create_test.go @@ -1,14 +1,60 @@ package hook_test import ( - defaultContext "context" + stdContext "context" "testing" + "github.com/yaoapp/gou/plan" "github.com/yaoapp/yao/agent/assistant" "github.com/yaoapp/yao/agent/context" "github.com/yaoapp/yao/agent/testutils" + "github.com/yaoapp/yao/openapi/oauth/types" ) +// newTestContext creates a Context for testing with commonly used fields pre-populated. +// You can override any fields after creation as needed for specific test scenarios. +func newTestContext(chatID, assistantID string) *context.Context { + return &context.Context{ + Context: stdContext.Background(), + Space: plan.NewMemorySharedSpace(), + ChatID: chatID, + AssistantID: assistantID, + Connector: "", + Locale: "en-us", + Theme: "light", + Client: context.Client{ + Type: "web", + UserAgent: "TestAgent/1.0", + IP: "127.0.0.1", + }, + Referer: context.RefererAPI, + Accept: context.AcceptWebCUI, + Route: "", + Metadata: make(map[string]interface{}), + Authorized: &types.AuthorizedInfo{ + Subject: "test-user", + ClientID: "test-client-id", + Scope: "openid profile email", + SessionID: "test-session-id", + UserID: "test-user-123", + TeamID: "test-team-456", + TenantID: "test-tenant-789", + RememberMe: true, + Constraints: types.DataConstraints{ + OwnerOnly: false, + CreatorOnly: false, + EditorOnly: false, + TeamOnly: true, + Extra: map[string]interface{}{ + "department": "engineering", + "region": "us-west", + "project": "yao", + }, + }, + }, + } +} + // TestCreate test the create hook func TestCreate(t *testing.T) { testutils.Prepare(t) @@ -23,12 +69,8 @@ func TestCreate(t *testing.T) { t.Fatalf("The tests.create assistant has no script") } - ctx := &context.Context{ - Context: defaultContext.Background(), - ChatID: "chat-test-create-hook", - AssistantID: "tests.create", - Sid: "test-session-create-hook", - } + // Use the helper function to create a test context + ctx := newTestContext("chat-test-create-hook", "tests.create") // Test scenario 1: Return null (should get nil response) t.Run("ReturnNull", func(t *testing.T) { @@ -120,18 +162,6 @@ func TestCreate(t *testing.T) { } else if *res.MaxCompletionTokens != 1500 { t.Errorf("Expected max_completion_tokens 1500, got: %d", *res.MaxCompletionTokens) } - - // Verify metadata - if res.Metadata == nil { - t.Error("Expected metadata, got nil") - } else { - if res.Metadata["test"] != "full_response" { - t.Errorf("Expected metadata['test'] = 'full_response', got: %s", res.Metadata["test"]) - } - if res.Metadata["user_id"] != "test_user_123" { - t.Errorf("Expected metadata['user_id'] = 'test_user_123', got: %s", res.Metadata["user_id"]) - } - } }) // Test scenario 5: Return partial response @@ -190,19 +220,6 @@ func TestCreate(t *testing.T) { } } } - - // Verify metadata - if res.Metadata == nil { - t.Error("Expected metadata, got nil") - } else { - if res.Metadata["test"] != "process_call" { - t.Errorf("Expected metadata['test'] = 'process_call', got: %s", res.Metadata["test"]) - } - // roles_count should be present - if _, ok := res.Metadata["roles_count"]; !ok { - t.Error("Expected metadata['roles_count'] to be present") - } - } }) // Test scenario 7: Default response diff --git a/agent/context/context.go b/agent/context/context.go index 26c7a16e..dd071a2c 100644 --- a/agent/context/context.go +++ b/agent/context/context.go @@ -92,12 +92,21 @@ func (ctx *Context) Map() map[string]interface{} { data := map[string]interface{}{} // Authorized information + if ctx.Authorized != nil { + data["authorized"] = ctx.Authorized + } if ctx.ChatID != "" { data["chat_id"] = ctx.ChatID } if ctx.AssistantID != "" { data["assistant_id"] = ctx.AssistantID } + if ctx.Connector != "" { + data["connector"] = ctx.Connector + } + if ctx.Search != nil { + data["search"] = *ctx.Search + } // Arguments for call if len(ctx.Args) > 0 { @@ -137,8 +146,8 @@ func (ctx *Context) Map() map[string]interface{} { if ctx.Route != "" { data["route"] = ctx.Route } - if len(ctx.Data) > 0 { - data["data"] = ctx.Data + if len(ctx.Metadata) > 0 { + data["metadata"] = ctx.Metadata } return data diff --git a/agent/context/jsapi.go b/agent/context/jsapi.go index a9799f53..e6ffb20f 100644 --- a/agent/context/jsapi.go +++ b/agent/context/jsapi.go @@ -4,6 +4,7 @@ import ( "sync" "github.com/google/uuid" + "github.com/yaoapp/gou/runtime/v8/bridge" "rogchap.com/v8go" ) @@ -25,15 +26,75 @@ func (ctx *Context) NewObject(v8ctx *v8go.Context) (*v8go.Value, error) { jsObject.Set("__id", id) jsObject.Set("__release", ctx.objectRelease(v8ctx.Isolate(), id)) - jsObject.Set("ChatID", ctx.ChatID) - jsObject.Set("AssistantID", ctx.AssistantID) - jsObject.Set("Sid", ctx.Sid) + // Set primitive fields in template + jsObject.Set("chat_id", ctx.ChatID) + jsObject.Set("assistant_id", ctx.AssistantID) + jsObject.Set("connector", ctx.Connector) + if ctx.Search != nil { + jsObject.Set("search", *ctx.Search) + } + + jsObject.Set("retry", ctx.Retry) + jsObject.Set("retry_times", uint32(ctx.RetryTimes)) + jsObject.Set("locale", ctx.Locale) + jsObject.Set("theme", ctx.Theme) + jsObject.Set("referer", ctx.Referer) + jsObject.Set("accept", string(ctx.Accept)) + jsObject.Set("route", ctx.Route) + + // Create instance instance, err := jsObject.NewInstance(v8ctx) if err != nil { ctx.objectRelease(v8ctx.Isolate(), id) return nil, err } + obj, err := instance.Value.AsObject() + if err != nil { + ctx.objectRelease(v8ctx.Isolate(), id) + return nil, err + } + + // Set complex objects (maps, arrays) after instance creation using bridge + // Args array + if ctx.Args != nil { + argsVal, err := bridge.JsValue(v8ctx, ctx.Args) + if err == nil { + obj.Set("args", argsVal) + argsVal.Release() // Release Go-side Persistent handle, V8 internal reference remains + } + } + + // Client object + clientData := map[string]interface{}{ + "type": ctx.Client.Type, + "user_agent": ctx.Client.UserAgent, + "ip": ctx.Client.IP, + } + clientVal, err := bridge.JsValue(v8ctx, clientData) + if err == nil { + obj.Set("client", clientVal) + clientVal.Release() // Release Go-side Persistent handle, V8 internal reference remains + } + + // Metadata object + if ctx.Metadata != nil { + metadataVal, err := bridge.JsValue(v8ctx, ctx.Metadata) + if err == nil { + obj.Set("metadata", metadataVal) + metadataVal.Release() // Release Go-side Persistent handle, V8 internal reference remains + } + } + + // Authorized object + if ctx.Authorized != nil { + authorizedVal, err := bridge.JsValue(v8ctx, ctx.Authorized) + if err == nil { + obj.Set("authorized", authorizedVal) + authorizedVal.Release() // Release Go-side Persistent handle, V8 internal reference remains + } + } + return instance.Value, nil } diff --git a/agent/context/jsapi_test.go b/agent/context/jsapi_test.go index 8aabb7ad..818bbe3b 100644 --- a/agent/context/jsapi_test.go +++ b/agent/context/jsapi_test.go @@ -9,6 +9,7 @@ import ( v8 "github.com/yaoapp/gou/runtime/v8" "github.com/yaoapp/gou/runtime/v8/bridge" "github.com/yaoapp/yao/config" + "github.com/yaoapp/yao/openapi/oauth/types" "github.com/yaoapp/yao/test" "rogchap.com/v8go" ) @@ -52,7 +53,7 @@ func testContextJsvalueFunction(info *v8go.FunctionCallbackInfo) *v8go.Value { return bridge.JsException(info.Context(), err) } - chatID, err := ctx.Get("ChatID") + chatID, err := ctx.Get("chat_id") if err != nil { return bridge.JsException(info.Context(), err) } @@ -221,3 +222,223 @@ func testContextRegistrationFunction(info *v8go.FunctionCallbackInfo) *v8go.Valu } return val } + +// TestJsValueAllFields test that all Context fields are properly exported to JavaScript +func TestJsValueAllFields(t *testing.T) { + + test.Prepare(t, config.Conf) + defer test.Clean() + + searchTrue := true + cxt := &Context{ + ChatID: "test-chat-id", + AssistantID: "test-assistant-id", + Connector: "test-connector", + Search: &searchTrue, + Args: []interface{}{"arg1", "arg2", 123}, + Retry: true, + RetryTimes: 3, + Locale: "zh-cn", + Theme: "dark", + Client: Client{ + Type: "web", + UserAgent: "Mozilla/5.0", + IP: "127.0.0.1", + }, + Referer: "api", + Accept: "cui-web", + Route: "/dashboard/home", + Metadata: map[string]interface{}{ + "key1": "value1", + "key2": 123, + "key3": true, + }, + Authorized: &types.AuthorizedInfo{ + Subject: "test-user", + ClientID: "test-client", + UserID: "user-123", + TeamID: "team-456", + TenantID: "tenant-789", + Constraints: types.DataConstraints{ + OwnerOnly: true, + CreatorOnly: false, + TeamOnly: true, + Extra: map[string]interface{}{ + "department": "engineering", + "region": "us-west", + }, + }, + }, + } + + v8.RegisterFunction("testAllFields", testAllFieldsEmbed) + res, err := v8.Call(v8.CallOptions{}, ` + function test(cxt) { + return testAllFields(cxt) + }`, cxt) + if err != nil { + t.Fatalf("Call failed: %v", err) + } + + result, ok := res.(map[string]interface{}) + if !ok { + t.Fatalf("Expected map result, got %T", res) + } + + // Verify all fields + assert.Equal(t, "test-chat-id", result["chat_id"], "chat_id mismatch") + assert.Equal(t, "test-assistant-id", result["assistant_id"], "assistant_id mismatch") + assert.Equal(t, "test-connector", result["connector"], "connector mismatch") + assert.Equal(t, true, result["search"], "search mismatch") + assert.Equal(t, true, result["retry"], "retry mismatch") + assert.Equal(t, float64(3), result["retry_times"], "retry_times mismatch") + assert.Equal(t, "zh-cn", result["locale"], "locale mismatch") + assert.Equal(t, "dark", result["theme"], "theme mismatch") + assert.Equal(t, "api", result["referer"], "referer mismatch") + assert.Equal(t, "cui-web", result["accept"], "accept mismatch") + assert.Equal(t, "/dashboard/home", result["route"], "route mismatch") + + // Verify args array + args, ok := result["args"].([]interface{}) + assert.True(t, ok, "args should be an array") + assert.Equal(t, 3, len(args), "args length mismatch") + + // Verify client object + client, ok := result["client"].(map[string]interface{}) + assert.True(t, ok, "client should be an object") + assert.Equal(t, "web", client["type"], "client.type mismatch") + assert.Equal(t, "Mozilla/5.0", client["user_agent"], "client.user_agent mismatch") + assert.Equal(t, "127.0.0.1", client["ip"], "client.ip mismatch") + + // Verify metadata object + metadata, ok := result["metadata"].(map[string]interface{}) + assert.True(t, ok, "metadata should be an object") + assert.Equal(t, "value1", metadata["key1"], "metadata.key1 mismatch") + assert.Equal(t, float64(123), metadata["key2"], "metadata.key2 mismatch") + assert.Equal(t, true, metadata["key3"], "metadata.key3 mismatch") + + // Verify authorized object + authorized, ok := result["authorized"].(map[string]interface{}) + assert.True(t, ok, "authorized should be an object") + assert.Equal(t, "test-user", authorized["sub"], "authorized.sub mismatch") + assert.Equal(t, "test-client", authorized["client_id"], "authorized.client_id mismatch") + assert.Equal(t, "user-123", authorized["user_id"], "authorized.user_id mismatch") + assert.Equal(t, "team-456", authorized["team_id"], "authorized.team_id mismatch") + assert.Equal(t, "tenant-789", authorized["tenant_id"], "authorized.tenant_id mismatch") + + // Verify authorized.constraints object + constraints, ok := authorized["constraints"].(map[string]interface{}) + assert.True(t, ok, "authorized.constraints should be an object") + assert.Equal(t, true, constraints["owner_only"], "constraints.owner_only mismatch") + // creator_only is false, and with omitempty it may not be present + if creatorOnly, exists := constraints["creator_only"]; exists { + assert.Equal(t, false, creatorOnly, "constraints.creator_only mismatch") + } + assert.Equal(t, true, constraints["team_only"], "constraints.team_only mismatch") + + // Verify constraints.extra object + extra, ok := constraints["extra"].(map[string]interface{}) + assert.True(t, ok, "constraints.extra should be an object") + assert.Equal(t, "engineering", extra["department"], "constraints.extra.department mismatch") + assert.Equal(t, "us-west", extra["region"], "constraints.extra.region mismatch") + + // Verify deprecated fields are NOT exported + _, hasSid := result["sid"] + assert.False(t, hasSid, "sid (deprecated) should not be exported") + _, hasSilent := result["silent"] + assert.False(t, hasSilent, "silent (deprecated) should not be exported") + + assert.Equal(t, 0, len(objects)) +} + +func testAllFieldsEmbed(iso *v8go.Isolate) *v8go.FunctionTemplate { + return v8go.NewFunctionTemplate(iso, testAllFieldsFunction) +} + +func testAllFieldsFunction(info *v8go.FunctionCallbackInfo) *v8go.Value { + var args = info.Args() + if len(args) < 1 { + return bridge.JsException(info.Context(), "Missing parameters") + } + + ctx, err := args[0].AsObject() + if err != nil { + return bridge.JsException(info.Context(), err) + } + + // Extract all fields and return as a map + result := map[string]interface{}{} + + // Helper function to get field value + getField := func(name string) (interface{}, bool) { + val, err := ctx.Get(name) + if err != nil || val.IsUndefined() { + return nil, false + } + goVal, err := bridge.GoValue(val, info.Context()) + if err != nil { + return nil, false + } + return goVal, true + } + + if val, ok := getField("chat_id"); ok { + result["chat_id"] = val + } + if val, ok := getField("assistant_id"); ok { + result["assistant_id"] = val + } + if val, ok := getField("connector"); ok { + result["connector"] = val + } + if val, ok := getField("search"); ok { + result["search"] = val + } + if val, ok := getField("args"); ok { + result["args"] = val + } + if val, ok := getField("retry"); ok { + result["retry"] = val + } + if val, ok := getField("retry_times"); ok { + result["retry_times"] = val + } + if val, ok := getField("locale"); ok { + result["locale"] = val + } + if val, ok := getField("theme"); ok { + result["theme"] = val + } + if val, ok := getField("client"); ok { + result["client"] = val + } + if val, ok := getField("referer"); ok { + result["referer"] = val + } + if val, ok := getField("accept"); ok { + result["accept"] = val + } + if val, ok := getField("route"); ok { + result["route"] = val + } + if val, ok := getField("metadata"); ok { + result["metadata"] = val + } + if val, ok := getField("authorized"); ok { + result["authorized"] = val + } + + // Check for deprecated fields - they should NOT exist + if val, ok := getField("sid"); ok { + result["sid"] = val + } + if val, ok := getField("silent"); ok { + result["silent"] = val + } + + jsVal, err := bridge.JsValue(info.Context(), result) + if err != nil { + return bridge.JsException(info.Context(), err) + } + return jsVal +} diff --git a/agent/context/openapi.go b/agent/context/openapi.go index e6ffd830..d4e54ef0 100644 --- a/agent/context/openapi.go +++ b/agent/context/openapi.go @@ -62,8 +62,8 @@ func GetCompletionRequest(c *gin.Context, cache store.Store) (*CompletionRequest UserAgent: userAgent, IP: clientIP, }, - Route: GetRoute(c, completionReq), - Data: GetData(c, completionReq), + Route: GetRoute(c, completionReq), + Metadata: GetMetadata(c, completionReq), } return completionReq, ctx, nil @@ -184,8 +184,10 @@ func GetLocale(c *gin.Context, req *CompletionRequest) string { // Priority 3: From CompletionRequest metadata if req != nil && req.Metadata != nil { - if locale, ok := req.Metadata["locale"]; ok && locale != "" { - return strings.ToLower(locale) + if locale, ok := req.Metadata["locale"]; ok { + if localeStr, ok := locale.(string); ok && localeStr != "" { + return strings.ToLower(localeStr) + } } } @@ -209,8 +211,10 @@ func GetTheme(c *gin.Context, req *CompletionRequest) string { // Priority 3: From CompletionRequest metadata if req != nil && req.Metadata != nil { - if theme, ok := req.Metadata["theme"]; ok && theme != "" { - return strings.ToLower(theme) + if theme, ok := req.Metadata["theme"]; ok { + if themeStr, ok := theme.(string); ok && themeStr != "" { + return strings.ToLower(themeStr) + } } } @@ -235,8 +239,10 @@ func GetReferer(c *gin.Context, req *CompletionRequest) string { // Priority 3: From CompletionRequest metadata if req != nil && req.Metadata != nil { - if referer, ok := req.Metadata["referer"]; ok && referer != "" { - return validateReferer(referer) + if referer, ok := req.Metadata["referer"]; ok { + if refererStr, ok := referer.(string); ok && refererStr != "" { + return validateReferer(refererStr) + } } } @@ -262,8 +268,10 @@ func GetAccept(c *gin.Context, req *CompletionRequest) Accept { // Priority 3: From CompletionRequest metadata if req != nil && req.Metadata != nil { - if accept, ok := req.Metadata["accept"]; ok && accept != "" { - return validateAccept(accept) + if accept, ok := req.Metadata["accept"]; ok { + if acceptStr, ok := accept.(string); ok && acceptStr != "" { + return validateAccept(acceptStr) + } } } @@ -292,8 +300,10 @@ func GetChatID(c *gin.Context, cache store.Store, req *CompletionRequest) (strin // Priority 3: From CompletionRequest metadata if req != nil && req.Metadata != nil { - if chatID, ok := req.Metadata["chat_id"]; ok && chatID != "" { - return chatID, nil + if chatID, ok := req.Metadata["chat_id"]; ok { + if chatIDStr, ok := chatID.(string); ok && chatIDStr != "" { + return chatIDStr, nil + } } } @@ -312,12 +322,12 @@ func GetChatID(c *gin.Context, cache store.Store, req *CompletionRequest) (strin } // GetRoute extracts route from request with priority: -// 1. Query parameter "yao_route" +// 1. Query parameter "route" // 2. Header "X-Yao-Route" // 3. CompletionRequest.Route (from payload) func GetRoute(c *gin.Context, req *CompletionRequest) string { // Priority 1: Query parameter - if route := c.Query("yao_route"); route != "" { + if route := c.Query("route"); route != "" { return route } @@ -334,38 +344,38 @@ func GetRoute(c *gin.Context, req *CompletionRequest) string { return "" } -// GetData extracts data from request with priority: -// 1. Query parameter "yao_data" (JSON string) -// 2. Header "X-Yao-Data" (Base64 encoded JSON string) -// 3. CompletionRequest.Data (from payload) -func GetData(c *gin.Context, req *CompletionRequest) map[string]interface{} { +// GetMetadata extracts metadata from request with priority: +// 1. Query parameter "metadata" (JSON string) +// 2. Header "X-Yao-Metadata" (Base64 encoded JSON string) +// 3. CompletionRequest.Metadata (from payload) +func GetMetadata(c *gin.Context, req *CompletionRequest) map[string]interface{} { // Priority 1: Query parameter (JSON string) - if dataJSON := c.Query("yao_data"); dataJSON != "" { - var data map[string]interface{} - if err := json.Unmarshal([]byte(dataJSON), &data); err == nil { - return data + if metadataJSON := c.Query("metadata"); metadataJSON != "" { + var metadata map[string]interface{} + if err := json.Unmarshal([]byte(metadataJSON), &metadata); err == nil { + return metadata } } // Priority 2: Header (Base64 encoded JSON string) - if dataBase64 := c.GetHeader("X-Yao-Data"); dataBase64 != "" { + if metadataBase64 := c.GetHeader("X-Yao-Metadata"); metadataBase64 != "" { // Try to decode Base64 - if decoded, err := base64.StdEncoding.DecodeString(dataBase64); err == nil { - var data map[string]interface{} - if err := json.Unmarshal(decoded, &data); err == nil { - return data + if decoded, err := base64.StdEncoding.DecodeString(metadataBase64); err == nil { + var metadata map[string]interface{} + if err := json.Unmarshal(decoded, &metadata); err == nil { + return metadata } } - // Fallback: try to parse as plain JSON (for backward compatibility) - var data map[string]interface{} - if err := json.Unmarshal([]byte(dataBase64), &data); err == nil { - return data + // Fallback: try to parse as plain JSON + var metadata map[string]interface{} + if err := json.Unmarshal([]byte(metadataBase64), &metadata); err == nil { + return metadata } } // Priority 3: From CompletionRequest - if req != nil && req.Data != nil { - return req.Data + if req != nil && req.Metadata != nil { + return req.Metadata } return nil @@ -469,7 +479,7 @@ func parseCompletionRequestData(c *gin.Context) (*CompletionRequest, error) { // Metadata from query (JSON string) if metadataJSON := c.Query("metadata"); metadataJSON != "" { - var metadata map[string]string + var metadata map[string]interface{} if err := json.Unmarshal([]byte(metadataJSON), &metadata); err == nil { req.Metadata = metadata } diff --git a/agent/context/openapi_test.go b/agent/context/openapi_test.go index 65cc1bda..1c0b807b 100644 --- a/agent/context/openapi_test.go +++ b/agent/context/openapi_test.go @@ -195,7 +195,7 @@ func TestGetChatID_FromMetadata(t *testing.T) { "messages": []map[string]interface{}{ {"role": "user", "content": "Test"}, }, - "metadata": map[string]string{ + "metadata": map[string]interface{}{ "chat_id": expectedChatID, }, } @@ -327,7 +327,7 @@ func TestGetChatID_Priority(t *testing.T) { requestBody := map[string]interface{}{ "model": "gpt-4", "messages": messages, - "metadata": map[string]string{ + "metadata": map[string]interface{}{ "chat_id": metadataChatID, }, } @@ -392,7 +392,7 @@ func TestGetLocale_FromMetadata(t *testing.T) { c.Request = req completionReq := &CompletionRequest{ - Metadata: map[string]string{ + Metadata: map[string]interface{}{ "locale": "ja-JP", }, } @@ -413,7 +413,7 @@ func TestGetLocale_Priority(t *testing.T) { c.Request = req completionReq := &CompletionRequest{ - Metadata: map[string]string{ + Metadata: map[string]interface{}{ "locale": "de-DE", }, } @@ -462,7 +462,7 @@ func TestGetTheme_FromMetadata(t *testing.T) { c.Request = req completionReq := &CompletionRequest{ - Metadata: map[string]string{ + Metadata: map[string]interface{}{ "theme": "auto", }, } @@ -482,7 +482,7 @@ func TestGetReferer_FromMetadata(t *testing.T) { c.Request = req completionReq := &CompletionRequest{ - Metadata: map[string]string{ + Metadata: map[string]interface{}{ "referer": "tool", }, } @@ -502,7 +502,7 @@ func TestGetAccept_FromMetadata(t *testing.T) { c.Request = req completionReq := &CompletionRequest{ - Metadata: map[string]string{ + Metadata: map[string]interface{}{ "accept": "cui-native", }, } @@ -561,7 +561,7 @@ func TestGetAssistantID_Priority(t *testing.T) { func TestGetRoute_FromQuery(t *testing.T) { gin.SetMode(gin.TestMode) - req := httptest.NewRequest("GET", "/chat/completions?yao_route=/dashboard/home", nil) + req := httptest.NewRequest("GET", "/chat/completions?route=/dashboard/home", nil) w := httptest.NewRecorder() c, _ := gin.CreateTestContext(w) c.Request = req @@ -608,7 +608,7 @@ func TestGetRoute_FromPayload(t *testing.T) { func TestGetRoute_Priority(t *testing.T) { gin.SetMode(gin.TestMode) - req := httptest.NewRequest("GET", "/chat/completions?yao_route=/from/query", nil) + req := httptest.NewRequest("GET", "/chat/completions?route=/from/query", nil) req.Header.Set("X-Yao-Route", "/from/header") w := httptest.NewRecorder() c, _ := gin.CreateTestContext(w) @@ -624,7 +624,7 @@ func TestGetRoute_Priority(t *testing.T) { } } -func TestGetData_FromQuery(t *testing.T) { +func TestGetMetadata_FromQuery(t *testing.T) { gin.SetMode(gin.TestMode) data := map[string]interface{}{ @@ -633,12 +633,12 @@ func TestGetData_FromQuery(t *testing.T) { } dataJSON, _ := json.Marshal(data) - req := httptest.NewRequest("GET", "/chat/completions?yao_data="+string(dataJSON), nil) + req := httptest.NewRequest("GET", "/chat/completions?metadata="+string(dataJSON), nil) w := httptest.NewRecorder() c, _ := gin.CreateTestContext(w) c.Request = req - result := GetData(c, nil) + result := GetMetadata(c, nil) if result == nil { t.Fatal("Expected data to be returned") } @@ -652,18 +652,18 @@ func TestGetData_FromQuery(t *testing.T) { } } -func TestGetData_FromHeader_Base64(t *testing.T) { +func TestGetMetadata_FromHeader_Base64(t *testing.T) { gin.SetMode(gin.TestMode) dataBase64 := "eyJ1c2VyX2lkIjo0NTYsImFjdGlvbiI6ImNyZWF0ZSJ9" // base64 of {"user_id":456,"action":"create"} req := httptest.NewRequest("GET", "/chat/completions", nil) - req.Header.Set("X-Yao-Data", dataBase64) + req.Header.Set("X-Yao-Metadata", dataBase64) w := httptest.NewRecorder() c, _ := gin.CreateTestContext(w) c.Request = req - result := GetData(c, nil) + result := GetMetadata(c, nil) if result == nil { t.Fatal("Expected data to be returned") } @@ -677,7 +677,7 @@ func TestGetData_FromHeader_Base64(t *testing.T) { } } -func TestGetData_FromPayload(t *testing.T) { +func TestGetMetadata_FromPayload(t *testing.T) { gin.SetMode(gin.TestMode) req := httptest.NewRequest("POST", "/chat/completions", nil) @@ -691,10 +691,10 @@ func TestGetData_FromPayload(t *testing.T) { } completionReq := &CompletionRequest{ - Data: data, + Metadata: data, } - result := GetData(c, completionReq) + result := GetMetadata(c, completionReq) if result == nil { t.Fatal("Expected data to be returned") } @@ -708,7 +708,7 @@ func TestGetData_FromPayload(t *testing.T) { } } -func TestGetData_Priority(t *testing.T) { +func TestGetMetadata_Priority(t *testing.T) { gin.SetMode(gin.TestMode) queryData := map[string]interface{}{ @@ -718,8 +718,8 @@ func TestGetData_Priority(t *testing.T) { headerDataBase64 := "eyJzb3VyY2UiOiJoZWFkZXIifQ==" // base64 of {"source":"header"} - req := httptest.NewRequest("GET", "/chat/completions?yao_data="+string(queryDataJSON), nil) - req.Header.Set("X-Yao-Data", headerDataBase64) + req := httptest.NewRequest("GET", "/chat/completions?metadata="+string(queryDataJSON), nil) + req.Header.Set("X-Yao-Metadata", headerDataBase64) w := httptest.NewRecorder() c, _ := gin.CreateTestContext(w) c.Request = req @@ -729,10 +729,10 @@ func TestGetData_Priority(t *testing.T) { } completionReq := &CompletionRequest{ - Data: payloadData, + Metadata: payloadData, } - result := GetData(c, completionReq) + result := GetMetadata(c, completionReq) if result == nil { t.Fatal("Expected data to be returned") } @@ -742,7 +742,7 @@ func TestGetData_Priority(t *testing.T) { } } -func TestGetData_EmptyData(t *testing.T) { +func TestGetMetadata_EmptyData(t *testing.T) { gin.SetMode(gin.TestMode) req := httptest.NewRequest("GET", "/chat/completions", nil) @@ -750,7 +750,7 @@ func TestGetData_EmptyData(t *testing.T) { c, _ := gin.CreateTestContext(w) c.Request = req - result := GetData(c, nil) + result := GetMetadata(c, nil) if result != nil { t.Errorf("Expected nil data, got '%v'", result) } diff --git a/agent/context/types.go b/agent/context/types.go index 1e383232..d37a6105 100644 --- a/agent/context/types.go +++ b/agent/context/types.go @@ -149,8 +149,8 @@ type Context struct { Accept Accept `json:"accept,omitempty"` // Response format: standard, cui-web, cui-native, cui-desktop // CUI Context information - Route string `json:"yao_route,omitempty"` // The route of the request, it will be used to identify the route of the request - Data map[string]interface{} `json:"yao_data,omitempty"` // The data of the request, it will be used to pass data to the page + Route string `json:"route,omitempty"` // The route of the request, it will be used to identify the route of the request + Metadata map[string]interface{} `json:"metadata,omitempty"` // The metadata of the request, it will be used to pass data to the page Silent bool `json:"silent,omitempty"` // Silent mode (Deprecated, use Referer instead) } @@ -204,9 +204,6 @@ type HookCreateResponse struct { Temperature *float64 `json:"temperature,omitempty"` MaxTokens *int `json:"max_tokens,omitempty"` MaxCompletionTokens *int `json:"max_completion_tokens,omitempty"` - - // Request metadata - Metadata map[string]string `json:"metadata,omitempty"` // Optional: developer-defined tags and values for tracking requests } // ResponseHookDone the response of the done hook @@ -335,12 +332,9 @@ type CompletionRequest struct { Stream *bool `json:"stream,omitempty"` // Optional: if true, stream partial message deltas StreamOptions *StreamOptions `json:"stream_options,omitempty"` // Optional: options for streaming response - // Request metadata - Metadata map[string]string `json:"metadata,omitempty"` // Optional: developer-defined tags and values for tracking requests - // CUI Context information - Route string `json:"yao_route,omitempty"` // Optional: route of the request for CUI context - Data map[string]interface{} `json:"yao_data,omitempty"` // Optional: data to pass to the page for CUI context + Route string `json:"route,omitempty"` // Optional: route of the request for CUI context + Metadata map[string]interface{} `json:"metadata,omitempty"` // Optional: metadata to pass to the page for CUI context } // AudioConfig represents the audio output configuration for models that support audio