Merge pull request #1301 from trheyi/main
Enhance context handling and metadata management in assistant operations
This commit is contained in:
commit
1f5a2bf600
7 changed files with 420 additions and 108 deletions
|
|
@ -1,14 +1,60 @@
|
||||||
package hook_test
|
package hook_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
defaultContext "context"
|
stdContext "context"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/yaoapp/gou/plan"
|
||||||
"github.com/yaoapp/yao/agent/assistant"
|
"github.com/yaoapp/yao/agent/assistant"
|
||||||
"github.com/yaoapp/yao/agent/context"
|
"github.com/yaoapp/yao/agent/context"
|
||||||
"github.com/yaoapp/yao/agent/testutils"
|
"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
|
// TestCreate test the create hook
|
||||||
func TestCreate(t *testing.T) {
|
func TestCreate(t *testing.T) {
|
||||||
testutils.Prepare(t)
|
testutils.Prepare(t)
|
||||||
|
|
@ -23,12 +69,8 @@ func TestCreate(t *testing.T) {
|
||||||
t.Fatalf("The tests.create assistant has no script")
|
t.Fatalf("The tests.create assistant has no script")
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx := &context.Context{
|
// Use the helper function to create a test context
|
||||||
Context: defaultContext.Background(),
|
ctx := newTestContext("chat-test-create-hook", "tests.create")
|
||||||
ChatID: "chat-test-create-hook",
|
|
||||||
AssistantID: "tests.create",
|
|
||||||
Sid: "test-session-create-hook",
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test scenario 1: Return null (should get nil response)
|
// Test scenario 1: Return null (should get nil response)
|
||||||
t.Run("ReturnNull", func(t *testing.T) {
|
t.Run("ReturnNull", func(t *testing.T) {
|
||||||
|
|
@ -120,18 +162,6 @@ func TestCreate(t *testing.T) {
|
||||||
} else if *res.MaxCompletionTokens != 1500 {
|
} else if *res.MaxCompletionTokens != 1500 {
|
||||||
t.Errorf("Expected max_completion_tokens 1500, got: %d", *res.MaxCompletionTokens)
|
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
|
// 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
|
// Test scenario 7: Default response
|
||||||
|
|
|
||||||
|
|
@ -92,12 +92,21 @@ func (ctx *Context) Map() map[string]interface{} {
|
||||||
data := map[string]interface{}{}
|
data := map[string]interface{}{}
|
||||||
|
|
||||||
// Authorized information
|
// Authorized information
|
||||||
|
if ctx.Authorized != nil {
|
||||||
|
data["authorized"] = ctx.Authorized
|
||||||
|
}
|
||||||
if ctx.ChatID != "" {
|
if ctx.ChatID != "" {
|
||||||
data["chat_id"] = ctx.ChatID
|
data["chat_id"] = ctx.ChatID
|
||||||
}
|
}
|
||||||
if ctx.AssistantID != "" {
|
if ctx.AssistantID != "" {
|
||||||
data["assistant_id"] = 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
|
// Arguments for call
|
||||||
if len(ctx.Args) > 0 {
|
if len(ctx.Args) > 0 {
|
||||||
|
|
@ -137,8 +146,8 @@ func (ctx *Context) Map() map[string]interface{} {
|
||||||
if ctx.Route != "" {
|
if ctx.Route != "" {
|
||||||
data["route"] = ctx.Route
|
data["route"] = ctx.Route
|
||||||
}
|
}
|
||||||
if len(ctx.Data) > 0 {
|
if len(ctx.Metadata) > 0 {
|
||||||
data["data"] = ctx.Data
|
data["metadata"] = ctx.Metadata
|
||||||
}
|
}
|
||||||
|
|
||||||
return data
|
return data
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
|
"github.com/yaoapp/gou/runtime/v8/bridge"
|
||||||
"rogchap.com/v8go"
|
"rogchap.com/v8go"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -25,15 +26,75 @@ func (ctx *Context) NewObject(v8ctx *v8go.Context) (*v8go.Value, error) {
|
||||||
jsObject.Set("__id", id)
|
jsObject.Set("__id", id)
|
||||||
jsObject.Set("__release", ctx.objectRelease(v8ctx.Isolate(), id))
|
jsObject.Set("__release", ctx.objectRelease(v8ctx.Isolate(), id))
|
||||||
|
|
||||||
jsObject.Set("ChatID", ctx.ChatID)
|
// Set primitive fields in template
|
||||||
jsObject.Set("AssistantID", ctx.AssistantID)
|
jsObject.Set("chat_id", ctx.ChatID)
|
||||||
jsObject.Set("Sid", ctx.Sid)
|
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)
|
instance, err := jsObject.NewInstance(v8ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.objectRelease(v8ctx.Isolate(), id)
|
ctx.objectRelease(v8ctx.Isolate(), id)
|
||||||
return nil, err
|
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
|
return instance.Value, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import (
|
||||||
v8 "github.com/yaoapp/gou/runtime/v8"
|
v8 "github.com/yaoapp/gou/runtime/v8"
|
||||||
"github.com/yaoapp/gou/runtime/v8/bridge"
|
"github.com/yaoapp/gou/runtime/v8/bridge"
|
||||||
"github.com/yaoapp/yao/config"
|
"github.com/yaoapp/yao/config"
|
||||||
|
"github.com/yaoapp/yao/openapi/oauth/types"
|
||||||
"github.com/yaoapp/yao/test"
|
"github.com/yaoapp/yao/test"
|
||||||
"rogchap.com/v8go"
|
"rogchap.com/v8go"
|
||||||
)
|
)
|
||||||
|
|
@ -52,7 +53,7 @@ func testContextJsvalueFunction(info *v8go.FunctionCallbackInfo) *v8go.Value {
|
||||||
return bridge.JsException(info.Context(), err)
|
return bridge.JsException(info.Context(), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
chatID, err := ctx.Get("ChatID")
|
chatID, err := ctx.Get("chat_id")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return bridge.JsException(info.Context(), err)
|
return bridge.JsException(info.Context(), err)
|
||||||
}
|
}
|
||||||
|
|
@ -221,3 +222,223 @@ func testContextRegistrationFunction(info *v8go.FunctionCallbackInfo) *v8go.Valu
|
||||||
}
|
}
|
||||||
return val
|
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
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -62,8 +62,8 @@ func GetCompletionRequest(c *gin.Context, cache store.Store) (*CompletionRequest
|
||||||
UserAgent: userAgent,
|
UserAgent: userAgent,
|
||||||
IP: clientIP,
|
IP: clientIP,
|
||||||
},
|
},
|
||||||
Route: GetRoute(c, completionReq),
|
Route: GetRoute(c, completionReq),
|
||||||
Data: GetData(c, completionReq),
|
Metadata: GetMetadata(c, completionReq),
|
||||||
}
|
}
|
||||||
|
|
||||||
return completionReq, ctx, nil
|
return completionReq, ctx, nil
|
||||||
|
|
@ -184,8 +184,10 @@ func GetLocale(c *gin.Context, req *CompletionRequest) string {
|
||||||
|
|
||||||
// Priority 3: From CompletionRequest metadata
|
// Priority 3: From CompletionRequest metadata
|
||||||
if req != nil && req.Metadata != nil {
|
if req != nil && req.Metadata != nil {
|
||||||
if locale, ok := req.Metadata["locale"]; ok && locale != "" {
|
if locale, ok := req.Metadata["locale"]; ok {
|
||||||
return strings.ToLower(locale)
|
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
|
// Priority 3: From CompletionRequest metadata
|
||||||
if req != nil && req.Metadata != nil {
|
if req != nil && req.Metadata != nil {
|
||||||
if theme, ok := req.Metadata["theme"]; ok && theme != "" {
|
if theme, ok := req.Metadata["theme"]; ok {
|
||||||
return strings.ToLower(theme)
|
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
|
// Priority 3: From CompletionRequest metadata
|
||||||
if req != nil && req.Metadata != nil {
|
if req != nil && req.Metadata != nil {
|
||||||
if referer, ok := req.Metadata["referer"]; ok && referer != "" {
|
if referer, ok := req.Metadata["referer"]; ok {
|
||||||
return validateReferer(referer)
|
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
|
// Priority 3: From CompletionRequest metadata
|
||||||
if req != nil && req.Metadata != nil {
|
if req != nil && req.Metadata != nil {
|
||||||
if accept, ok := req.Metadata["accept"]; ok && accept != "" {
|
if accept, ok := req.Metadata["accept"]; ok {
|
||||||
return validateAccept(accept)
|
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
|
// Priority 3: From CompletionRequest metadata
|
||||||
if req != nil && req.Metadata != nil {
|
if req != nil && req.Metadata != nil {
|
||||||
if chatID, ok := req.Metadata["chat_id"]; ok && chatID != "" {
|
if chatID, ok := req.Metadata["chat_id"]; ok {
|
||||||
return chatID, nil
|
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:
|
// GetRoute extracts route from request with priority:
|
||||||
// 1. Query parameter "yao_route"
|
// 1. Query parameter "route"
|
||||||
// 2. Header "X-Yao-Route"
|
// 2. Header "X-Yao-Route"
|
||||||
// 3. CompletionRequest.Route (from payload)
|
// 3. CompletionRequest.Route (from payload)
|
||||||
func GetRoute(c *gin.Context, req *CompletionRequest) string {
|
func GetRoute(c *gin.Context, req *CompletionRequest) string {
|
||||||
// Priority 1: Query parameter
|
// Priority 1: Query parameter
|
||||||
if route := c.Query("yao_route"); route != "" {
|
if route := c.Query("route"); route != "" {
|
||||||
return route
|
return route
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -334,38 +344,38 @@ func GetRoute(c *gin.Context, req *CompletionRequest) string {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetData extracts data from request with priority:
|
// GetMetadata extracts metadata from request with priority:
|
||||||
// 1. Query parameter "yao_data" (JSON string)
|
// 1. Query parameter "metadata" (JSON string)
|
||||||
// 2. Header "X-Yao-Data" (Base64 encoded JSON string)
|
// 2. Header "X-Yao-Metadata" (Base64 encoded JSON string)
|
||||||
// 3. CompletionRequest.Data (from payload)
|
// 3. CompletionRequest.Metadata (from payload)
|
||||||
func GetData(c *gin.Context, req *CompletionRequest) map[string]interface{} {
|
func GetMetadata(c *gin.Context, req *CompletionRequest) map[string]interface{} {
|
||||||
// Priority 1: Query parameter (JSON string)
|
// Priority 1: Query parameter (JSON string)
|
||||||
if dataJSON := c.Query("yao_data"); dataJSON != "" {
|
if metadataJSON := c.Query("metadata"); metadataJSON != "" {
|
||||||
var data map[string]interface{}
|
var metadata map[string]interface{}
|
||||||
if err := json.Unmarshal([]byte(dataJSON), &data); err == nil {
|
if err := json.Unmarshal([]byte(metadataJSON), &metadata); err == nil {
|
||||||
return data
|
return metadata
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Priority 2: Header (Base64 encoded JSON string)
|
// 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
|
// Try to decode Base64
|
||||||
if decoded, err := base64.StdEncoding.DecodeString(dataBase64); err == nil {
|
if decoded, err := base64.StdEncoding.DecodeString(metadataBase64); err == nil {
|
||||||
var data map[string]interface{}
|
var metadata map[string]interface{}
|
||||||
if err := json.Unmarshal(decoded, &data); err == nil {
|
if err := json.Unmarshal(decoded, &metadata); err == nil {
|
||||||
return data
|
return metadata
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Fallback: try to parse as plain JSON (for backward compatibility)
|
// Fallback: try to parse as plain JSON
|
||||||
var data map[string]interface{}
|
var metadata map[string]interface{}
|
||||||
if err := json.Unmarshal([]byte(dataBase64), &data); err == nil {
|
if err := json.Unmarshal([]byte(metadataBase64), &metadata); err == nil {
|
||||||
return data
|
return metadata
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Priority 3: From CompletionRequest
|
// Priority 3: From CompletionRequest
|
||||||
if req != nil && req.Data != nil {
|
if req != nil && req.Metadata != nil {
|
||||||
return req.Data
|
return req.Metadata
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
@ -469,7 +479,7 @@ func parseCompletionRequestData(c *gin.Context) (*CompletionRequest, error) {
|
||||||
|
|
||||||
// Metadata from query (JSON string)
|
// Metadata from query (JSON string)
|
||||||
if metadataJSON := c.Query("metadata"); metadataJSON != "" {
|
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 {
|
if err := json.Unmarshal([]byte(metadataJSON), &metadata); err == nil {
|
||||||
req.Metadata = metadata
|
req.Metadata = metadata
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -195,7 +195,7 @@ func TestGetChatID_FromMetadata(t *testing.T) {
|
||||||
"messages": []map[string]interface{}{
|
"messages": []map[string]interface{}{
|
||||||
{"role": "user", "content": "Test"},
|
{"role": "user", "content": "Test"},
|
||||||
},
|
},
|
||||||
"metadata": map[string]string{
|
"metadata": map[string]interface{}{
|
||||||
"chat_id": expectedChatID,
|
"chat_id": expectedChatID,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
@ -327,7 +327,7 @@ func TestGetChatID_Priority(t *testing.T) {
|
||||||
requestBody := map[string]interface{}{
|
requestBody := map[string]interface{}{
|
||||||
"model": "gpt-4",
|
"model": "gpt-4",
|
||||||
"messages": messages,
|
"messages": messages,
|
||||||
"metadata": map[string]string{
|
"metadata": map[string]interface{}{
|
||||||
"chat_id": metadataChatID,
|
"chat_id": metadataChatID,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
@ -392,7 +392,7 @@ func TestGetLocale_FromMetadata(t *testing.T) {
|
||||||
c.Request = req
|
c.Request = req
|
||||||
|
|
||||||
completionReq := &CompletionRequest{
|
completionReq := &CompletionRequest{
|
||||||
Metadata: map[string]string{
|
Metadata: map[string]interface{}{
|
||||||
"locale": "ja-JP",
|
"locale": "ja-JP",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
@ -413,7 +413,7 @@ func TestGetLocale_Priority(t *testing.T) {
|
||||||
c.Request = req
|
c.Request = req
|
||||||
|
|
||||||
completionReq := &CompletionRequest{
|
completionReq := &CompletionRequest{
|
||||||
Metadata: map[string]string{
|
Metadata: map[string]interface{}{
|
||||||
"locale": "de-DE",
|
"locale": "de-DE",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
@ -462,7 +462,7 @@ func TestGetTheme_FromMetadata(t *testing.T) {
|
||||||
c.Request = req
|
c.Request = req
|
||||||
|
|
||||||
completionReq := &CompletionRequest{
|
completionReq := &CompletionRequest{
|
||||||
Metadata: map[string]string{
|
Metadata: map[string]interface{}{
|
||||||
"theme": "auto",
|
"theme": "auto",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
@ -482,7 +482,7 @@ func TestGetReferer_FromMetadata(t *testing.T) {
|
||||||
c.Request = req
|
c.Request = req
|
||||||
|
|
||||||
completionReq := &CompletionRequest{
|
completionReq := &CompletionRequest{
|
||||||
Metadata: map[string]string{
|
Metadata: map[string]interface{}{
|
||||||
"referer": "tool",
|
"referer": "tool",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
@ -502,7 +502,7 @@ func TestGetAccept_FromMetadata(t *testing.T) {
|
||||||
c.Request = req
|
c.Request = req
|
||||||
|
|
||||||
completionReq := &CompletionRequest{
|
completionReq := &CompletionRequest{
|
||||||
Metadata: map[string]string{
|
Metadata: map[string]interface{}{
|
||||||
"accept": "cui-native",
|
"accept": "cui-native",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
@ -561,7 +561,7 @@ func TestGetAssistantID_Priority(t *testing.T) {
|
||||||
func TestGetRoute_FromQuery(t *testing.T) {
|
func TestGetRoute_FromQuery(t *testing.T) {
|
||||||
gin.SetMode(gin.TestMode)
|
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()
|
w := httptest.NewRecorder()
|
||||||
c, _ := gin.CreateTestContext(w)
|
c, _ := gin.CreateTestContext(w)
|
||||||
c.Request = req
|
c.Request = req
|
||||||
|
|
@ -608,7 +608,7 @@ func TestGetRoute_FromPayload(t *testing.T) {
|
||||||
func TestGetRoute_Priority(t *testing.T) {
|
func TestGetRoute_Priority(t *testing.T) {
|
||||||
gin.SetMode(gin.TestMode)
|
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")
|
req.Header.Set("X-Yao-Route", "/from/header")
|
||||||
w := httptest.NewRecorder()
|
w := httptest.NewRecorder()
|
||||||
c, _ := gin.CreateTestContext(w)
|
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)
|
gin.SetMode(gin.TestMode)
|
||||||
|
|
||||||
data := map[string]interface{}{
|
data := map[string]interface{}{
|
||||||
|
|
@ -633,12 +633,12 @@ func TestGetData_FromQuery(t *testing.T) {
|
||||||
}
|
}
|
||||||
dataJSON, _ := json.Marshal(data)
|
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()
|
w := httptest.NewRecorder()
|
||||||
c, _ := gin.CreateTestContext(w)
|
c, _ := gin.CreateTestContext(w)
|
||||||
c.Request = req
|
c.Request = req
|
||||||
|
|
||||||
result := GetData(c, nil)
|
result := GetMetadata(c, nil)
|
||||||
if result == nil {
|
if result == nil {
|
||||||
t.Fatal("Expected data to be returned")
|
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)
|
gin.SetMode(gin.TestMode)
|
||||||
|
|
||||||
dataBase64 := "eyJ1c2VyX2lkIjo0NTYsImFjdGlvbiI6ImNyZWF0ZSJ9" // base64 of {"user_id":456,"action":"create"}
|
dataBase64 := "eyJ1c2VyX2lkIjo0NTYsImFjdGlvbiI6ImNyZWF0ZSJ9" // base64 of {"user_id":456,"action":"create"}
|
||||||
|
|
||||||
req := httptest.NewRequest("GET", "/chat/completions", nil)
|
req := httptest.NewRequest("GET", "/chat/completions", nil)
|
||||||
req.Header.Set("X-Yao-Data", dataBase64)
|
req.Header.Set("X-Yao-Metadata", dataBase64)
|
||||||
w := httptest.NewRecorder()
|
w := httptest.NewRecorder()
|
||||||
c, _ := gin.CreateTestContext(w)
|
c, _ := gin.CreateTestContext(w)
|
||||||
c.Request = req
|
c.Request = req
|
||||||
|
|
||||||
result := GetData(c, nil)
|
result := GetMetadata(c, nil)
|
||||||
if result == nil {
|
if result == nil {
|
||||||
t.Fatal("Expected data to be returned")
|
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)
|
gin.SetMode(gin.TestMode)
|
||||||
|
|
||||||
req := httptest.NewRequest("POST", "/chat/completions", nil)
|
req := httptest.NewRequest("POST", "/chat/completions", nil)
|
||||||
|
|
@ -691,10 +691,10 @@ func TestGetData_FromPayload(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
completionReq := &CompletionRequest{
|
completionReq := &CompletionRequest{
|
||||||
Data: data,
|
Metadata: data,
|
||||||
}
|
}
|
||||||
|
|
||||||
result := GetData(c, completionReq)
|
result := GetMetadata(c, completionReq)
|
||||||
if result == nil {
|
if result == nil {
|
||||||
t.Fatal("Expected data to be returned")
|
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)
|
gin.SetMode(gin.TestMode)
|
||||||
|
|
||||||
queryData := map[string]interface{}{
|
queryData := map[string]interface{}{
|
||||||
|
|
@ -718,8 +718,8 @@ func TestGetData_Priority(t *testing.T) {
|
||||||
|
|
||||||
headerDataBase64 := "eyJzb3VyY2UiOiJoZWFkZXIifQ==" // base64 of {"source":"header"}
|
headerDataBase64 := "eyJzb3VyY2UiOiJoZWFkZXIifQ==" // base64 of {"source":"header"}
|
||||||
|
|
||||||
req := httptest.NewRequest("GET", "/chat/completions?yao_data="+string(queryDataJSON), nil)
|
req := httptest.NewRequest("GET", "/chat/completions?metadata="+string(queryDataJSON), nil)
|
||||||
req.Header.Set("X-Yao-Data", headerDataBase64)
|
req.Header.Set("X-Yao-Metadata", headerDataBase64)
|
||||||
w := httptest.NewRecorder()
|
w := httptest.NewRecorder()
|
||||||
c, _ := gin.CreateTestContext(w)
|
c, _ := gin.CreateTestContext(w)
|
||||||
c.Request = req
|
c.Request = req
|
||||||
|
|
@ -729,10 +729,10 @@ func TestGetData_Priority(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
completionReq := &CompletionRequest{
|
completionReq := &CompletionRequest{
|
||||||
Data: payloadData,
|
Metadata: payloadData,
|
||||||
}
|
}
|
||||||
|
|
||||||
result := GetData(c, completionReq)
|
result := GetMetadata(c, completionReq)
|
||||||
if result == nil {
|
if result == nil {
|
||||||
t.Fatal("Expected data to be returned")
|
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)
|
gin.SetMode(gin.TestMode)
|
||||||
|
|
||||||
req := httptest.NewRequest("GET", "/chat/completions", nil)
|
req := httptest.NewRequest("GET", "/chat/completions", nil)
|
||||||
|
|
@ -750,7 +750,7 @@ func TestGetData_EmptyData(t *testing.T) {
|
||||||
c, _ := gin.CreateTestContext(w)
|
c, _ := gin.CreateTestContext(w)
|
||||||
c.Request = req
|
c.Request = req
|
||||||
|
|
||||||
result := GetData(c, nil)
|
result := GetMetadata(c, nil)
|
||||||
if result != nil {
|
if result != nil {
|
||||||
t.Errorf("Expected nil data, got '%v'", result)
|
t.Errorf("Expected nil data, got '%v'", result)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -149,8 +149,8 @@ type Context struct {
|
||||||
Accept Accept `json:"accept,omitempty"` // Response format: standard, cui-web, cui-native, cui-desktop
|
Accept Accept `json:"accept,omitempty"` // Response format: standard, cui-web, cui-native, cui-desktop
|
||||||
|
|
||||||
// CUI Context information
|
// 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
|
Route string `json:"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
|
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)
|
Silent bool `json:"silent,omitempty"` // Silent mode (Deprecated, use Referer instead)
|
||||||
}
|
}
|
||||||
|
|
@ -204,9 +204,6 @@ type HookCreateResponse struct {
|
||||||
Temperature *float64 `json:"temperature,omitempty"`
|
Temperature *float64 `json:"temperature,omitempty"`
|
||||||
MaxTokens *int `json:"max_tokens,omitempty"`
|
MaxTokens *int `json:"max_tokens,omitempty"`
|
||||||
MaxCompletionTokens *int `json:"max_completion_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
|
// 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
|
Stream *bool `json:"stream,omitempty"` // Optional: if true, stream partial message deltas
|
||||||
StreamOptions *StreamOptions `json:"stream_options,omitempty"` // Optional: options for streaming response
|
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
|
// CUI Context information
|
||||||
Route string `json:"yao_route,omitempty"` // Optional: route of the request for CUI context
|
Route string `json:"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
|
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
|
// AudioConfig represents the audio output configuration for models that support audio
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue