mirror of
https://github.com/memohai/Memoh.git
synced 2026-04-25 07:00:48 +09:00
feat: max context tokens
This commit is contained in:
Executable
BIN
Binary file not shown.
@@ -117,6 +117,7 @@ CREATE TABLE IF NOT EXISTS bots (
|
||||
is_active BOOLEAN NOT NULL DEFAULT true,
|
||||
status TEXT NOT NULL DEFAULT 'ready',
|
||||
max_context_load_time INTEGER NOT NULL DEFAULT 1440,
|
||||
max_context_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
language TEXT NOT NULL DEFAULT 'auto',
|
||||
allow_guest BOOLEAN NOT NULL DEFAULT false,
|
||||
chat_model_id UUID REFERENCES models(id) ON DELETE SET NULL,
|
||||
@@ -242,6 +243,7 @@ CREATE TABLE IF NOT EXISTS bot_history_messages (
|
||||
role TEXT NOT NULL CHECK (role IN ('user', 'assistant', 'system', 'tool')),
|
||||
content JSONB NOT NULL,
|
||||
metadata JSONB NOT NULL DEFAULT '{}'::jsonb,
|
||||
usage JSONB,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||||
);
|
||||
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
-- 0008_max_context_tokens
|
||||
-- Remove max_context_tokens column from bots table
|
||||
|
||||
ALTER TABLE bots DROP COLUMN IF EXISTS max_context_tokens;
|
||||
@@ -0,0 +1,4 @@
|
||||
-- 0008_max_context_tokens
|
||||
-- Add max_context_tokens column to bots table for token-based context trimming
|
||||
|
||||
ALTER TABLE bots ADD COLUMN IF NOT EXISTS max_context_tokens INTEGER NOT NULL DEFAULT 0;
|
||||
@@ -0,0 +1,4 @@
|
||||
-- 0009_message_usage
|
||||
-- Remove usage JSONB column from bot_history_messages
|
||||
|
||||
ALTER TABLE bot_history_messages DROP COLUMN IF EXISTS usage;
|
||||
@@ -0,0 +1,4 @@
|
||||
-- 0009_message_usage
|
||||
-- Add usage JSONB column to bot_history_messages for storing LLM token usage
|
||||
|
||||
ALTER TABLE bot_history_messages ADD COLUMN IF NOT EXISTS usage JSONB;
|
||||
+6
-6
@@ -1,21 +1,21 @@
|
||||
-- name: CreateBot :one
|
||||
INSERT INTO bots (owner_user_id, type, display_name, avatar_url, is_active, metadata, status)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7)
|
||||
RETURNING id, owner_user_id, type, display_name, avatar_url, is_active, status, max_context_load_time, language, allow_guest, chat_model_id, memory_model_id, embedding_model_id, search_provider_id, metadata, created_at, updated_at;
|
||||
RETURNING id, owner_user_id, type, display_name, avatar_url, is_active, status, max_context_load_time, max_context_tokens, language, allow_guest, chat_model_id, memory_model_id, embedding_model_id, search_provider_id, metadata, created_at, updated_at;
|
||||
|
||||
-- name: GetBotByID :one
|
||||
SELECT id, owner_user_id, type, display_name, avatar_url, is_active, status, max_context_load_time, language, allow_guest, chat_model_id, memory_model_id, embedding_model_id, search_provider_id, metadata, created_at, updated_at
|
||||
SELECT id, owner_user_id, type, display_name, avatar_url, is_active, status, max_context_load_time, max_context_tokens, language, allow_guest, chat_model_id, memory_model_id, embedding_model_id, search_provider_id, metadata, created_at, updated_at
|
||||
FROM bots
|
||||
WHERE id = $1;
|
||||
|
||||
-- name: ListBotsByOwner :many
|
||||
SELECT id, owner_user_id, type, display_name, avatar_url, is_active, status, max_context_load_time, language, allow_guest, chat_model_id, memory_model_id, embedding_model_id, search_provider_id, metadata, created_at, updated_at
|
||||
SELECT id, owner_user_id, type, display_name, avatar_url, is_active, status, max_context_load_time, max_context_tokens, language, allow_guest, chat_model_id, memory_model_id, embedding_model_id, search_provider_id, metadata, created_at, updated_at
|
||||
FROM bots
|
||||
WHERE owner_user_id = $1
|
||||
ORDER BY created_at DESC;
|
||||
|
||||
-- name: ListBotsByMember :many
|
||||
SELECT b.id, b.owner_user_id, b.type, b.display_name, b.avatar_url, b.is_active, b.status, b.max_context_load_time, b.language, b.allow_guest, b.chat_model_id, b.memory_model_id, b.embedding_model_id, b.search_provider_id, b.metadata, b.created_at, b.updated_at
|
||||
SELECT b.id, b.owner_user_id, b.type, b.display_name, b.avatar_url, b.is_active, b.status, b.max_context_load_time, b.max_context_tokens, b.language, b.allow_guest, b.chat_model_id, b.memory_model_id, b.embedding_model_id, b.search_provider_id, b.metadata, b.created_at, b.updated_at
|
||||
FROM bots b
|
||||
JOIN bot_members m ON m.bot_id = b.id
|
||||
WHERE m.user_id = $1
|
||||
@@ -29,14 +29,14 @@ SET display_name = $2,
|
||||
metadata = $5,
|
||||
updated_at = now()
|
||||
WHERE id = $1
|
||||
RETURNING id, owner_user_id, type, display_name, avatar_url, is_active, status, max_context_load_time, language, allow_guest, chat_model_id, memory_model_id, embedding_model_id, search_provider_id, metadata, created_at, updated_at;
|
||||
RETURNING id, owner_user_id, type, display_name, avatar_url, is_active, status, max_context_load_time, max_context_tokens, language, allow_guest, chat_model_id, memory_model_id, embedding_model_id, search_provider_id, metadata, created_at, updated_at;
|
||||
|
||||
-- name: UpdateBotOwner :one
|
||||
UPDATE bots
|
||||
SET owner_user_id = $2,
|
||||
updated_at = now()
|
||||
WHERE id = $1
|
||||
RETURNING id, owner_user_id, type, display_name, avatar_url, is_active, status, max_context_load_time, language, allow_guest, chat_model_id, memory_model_id, embedding_model_id, search_provider_id, metadata, created_at, updated_at;
|
||||
RETURNING id, owner_user_id, type, display_name, avatar_url, is_active, status, max_context_load_time, max_context_tokens, language, allow_guest, chat_model_id, memory_model_id, embedding_model_id, search_provider_id, metadata, created_at, updated_at;
|
||||
|
||||
-- name: UpdateBotStatus :exec
|
||||
UPDATE bots
|
||||
|
||||
@@ -9,7 +9,8 @@ INSERT INTO bot_history_messages (
|
||||
source_reply_to_message_id,
|
||||
role,
|
||||
content,
|
||||
metadata
|
||||
metadata,
|
||||
usage
|
||||
)
|
||||
VALUES (
|
||||
sqlc.arg(bot_id),
|
||||
@@ -21,7 +22,8 @@ VALUES (
|
||||
sqlc.narg(source_reply_to_message_id)::text,
|
||||
sqlc.arg(role),
|
||||
sqlc.arg(content),
|
||||
sqlc.arg(metadata)
|
||||
sqlc.arg(metadata),
|
||||
sqlc.arg(usage)
|
||||
)
|
||||
RETURNING
|
||||
id,
|
||||
@@ -35,6 +37,7 @@ RETURNING
|
||||
role,
|
||||
content,
|
||||
metadata,
|
||||
usage,
|
||||
created_at;
|
||||
|
||||
-- name: ListMessages :many
|
||||
@@ -50,6 +53,7 @@ SELECT
|
||||
m.role,
|
||||
m.content,
|
||||
m.metadata,
|
||||
m.usage,
|
||||
m.created_at,
|
||||
ci.display_name AS sender_display_name,
|
||||
ci.avatar_url AS sender_avatar_url
|
||||
@@ -72,6 +76,7 @@ SELECT
|
||||
m.role,
|
||||
m.content,
|
||||
m.metadata,
|
||||
m.usage,
|
||||
m.created_at,
|
||||
ci.display_name AS sender_display_name,
|
||||
ci.avatar_url AS sender_avatar_url
|
||||
@@ -94,6 +99,7 @@ SELECT
|
||||
m.role,
|
||||
m.content,
|
||||
m.metadata,
|
||||
m.usage,
|
||||
m.created_at,
|
||||
ci.display_name AS sender_display_name,
|
||||
ci.avatar_url AS sender_avatar_url
|
||||
@@ -117,6 +123,7 @@ SELECT
|
||||
m.role,
|
||||
m.content,
|
||||
m.metadata,
|
||||
m.usage,
|
||||
m.created_at,
|
||||
ci.display_name AS sender_display_name,
|
||||
ci.avatar_url AS sender_avatar_url
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
SELECT
|
||||
bots.id AS bot_id,
|
||||
bots.max_context_load_time,
|
||||
bots.max_context_tokens,
|
||||
bots.language,
|
||||
bots.allow_guest,
|
||||
chat_models.model_id AS chat_model_id,
|
||||
@@ -19,6 +20,7 @@ WHERE bots.id = $1;
|
||||
WITH updated AS (
|
||||
UPDATE bots
|
||||
SET max_context_load_time = sqlc.arg(max_context_load_time),
|
||||
max_context_tokens = sqlc.arg(max_context_tokens),
|
||||
language = sqlc.arg(language),
|
||||
allow_guest = sqlc.arg(allow_guest),
|
||||
chat_model_id = COALESCE(sqlc.narg(chat_model_id)::uuid, bots.chat_model_id),
|
||||
@@ -27,11 +29,12 @@ WITH updated AS (
|
||||
search_provider_id = COALESCE(sqlc.narg(search_provider_id)::uuid, bots.search_provider_id),
|
||||
updated_at = now()
|
||||
WHERE bots.id = sqlc.arg(id)
|
||||
RETURNING bots.id, bots.max_context_load_time, bots.language, bots.allow_guest, bots.chat_model_id, bots.memory_model_id, bots.embedding_model_id, bots.search_provider_id
|
||||
RETURNING bots.id, bots.max_context_load_time, bots.max_context_tokens, bots.language, bots.allow_guest, bots.chat_model_id, bots.memory_model_id, bots.embedding_model_id, bots.search_provider_id
|
||||
)
|
||||
SELECT
|
||||
updated.id AS bot_id,
|
||||
updated.max_context_load_time,
|
||||
updated.max_context_tokens,
|
||||
updated.language,
|
||||
updated.allow_guest,
|
||||
chat_models.model_id AS chat_model_id,
|
||||
@@ -47,6 +50,7 @@ LEFT JOIN search_providers ON search_providers.id = updated.search_provider_id;
|
||||
-- name: DeleteSettingsByBotID :exec
|
||||
UPDATE bots
|
||||
SET max_context_load_time = 1440,
|
||||
max_context_tokens = 0,
|
||||
language = 'auto',
|
||||
allow_guest = false,
|
||||
chat_model_id = NULL,
|
||||
|
||||
@@ -150,6 +150,12 @@ type gatewayRequest struct {
|
||||
type gatewayResponse struct {
|
||||
Messages []conversation.ModelMessage `json:"messages"`
|
||||
Skills []string `json:"skills"`
|
||||
Usage json.RawMessage `json:"usage,omitempty"`
|
||||
}
|
||||
|
||||
type gatewayUsage struct {
|
||||
InputTokens *int `json:"inputTokens"`
|
||||
OutputTokens *int `json:"outputTokens"`
|
||||
}
|
||||
|
||||
// gatewaySchedule matches the agent gateway ScheduleModel for /chat/trigger-schedule.
|
||||
@@ -212,13 +218,15 @@ func (r *Resolver) resolve(ctx context.Context, req conversation.ChatRequest) (r
|
||||
return resolvedContext{}, err
|
||||
}
|
||||
maxCtx := coalescePositiveInt(req.MaxContextLoadTime, botSettings.MaxContextLoadTime, defaultMaxContextMinutes)
|
||||
maxTokens := botSettings.MaxContextTokens
|
||||
|
||||
var messages []conversation.ModelMessage
|
||||
if !skipHistory && r.conversationSvc != nil {
|
||||
messages, err = r.loadMessages(ctx, req.ChatID, maxCtx)
|
||||
if err != nil {
|
||||
return resolvedContext{}, err
|
||||
loaded, loadErr := r.loadMessages(ctx, req.ChatID, maxCtx)
|
||||
if loadErr != nil {
|
||||
return resolvedContext{}, loadErr
|
||||
}
|
||||
messages = trimMessagesByTokens(loaded, maxTokens)
|
||||
}
|
||||
if memoryMsg := r.loadMemoryContextMessage(ctx, req); memoryMsg != nil {
|
||||
messages = append(messages, *memoryMsg)
|
||||
@@ -291,7 +299,7 @@ func (r *Resolver) Chat(ctx context.Context, req conversation.ChatRequest) (conv
|
||||
if err != nil {
|
||||
return conversation.ChatResponse{}, err
|
||||
}
|
||||
if err := r.storeRound(ctx, req, resp.Messages); err != nil {
|
||||
if err := r.storeRound(ctx, req, resp.Messages, resp.Usage); err != nil {
|
||||
return conversation.ChatResponse{}, err
|
||||
}
|
||||
return conversation.ChatResponse{
|
||||
@@ -345,7 +353,7 @@ func (r *Resolver) TriggerSchedule(ctx context.Context, botID string, payload sc
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return r.storeRound(ctx, req, resp.Messages)
|
||||
return r.storeRound(ctx, req, resp.Messages, resp.Usage)
|
||||
}
|
||||
|
||||
// --- StreamChat ---
|
||||
@@ -552,7 +560,7 @@ func (r *Resolver) tryStoreStream(ctx context.Context, req conversation.ChatRequ
|
||||
if eventType == "done" {
|
||||
var resp gatewayResponse
|
||||
if err := json.Unmarshal([]byte(data), &resp); err == nil && len(resp.Messages) > 0 {
|
||||
return true, r.storeRound(ctx, req, resp.Messages)
|
||||
return true, r.storeRound(ctx, req, resp.Messages, resp.Usage)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -562,15 +570,16 @@ func (r *Resolver) tryStoreStream(ctx context.Context, req conversation.ChatRequ
|
||||
Data json.RawMessage `json:"data"`
|
||||
Messages []conversation.ModelMessage `json:"messages"`
|
||||
Skills []string `json:"skills"`
|
||||
Usage json.RawMessage `json:"usage,omitempty"`
|
||||
}
|
||||
if err := json.Unmarshal([]byte(data), &envelope); err == nil {
|
||||
if (envelope.Type == "agent_end" || envelope.Type == "done") && len(envelope.Messages) > 0 {
|
||||
return true, r.storeRound(ctx, req, envelope.Messages)
|
||||
return true, r.storeRound(ctx, req, envelope.Messages, envelope.Usage)
|
||||
}
|
||||
if envelope.Type == "done" && len(envelope.Data) > 0 {
|
||||
var resp gatewayResponse
|
||||
if err := json.Unmarshal(envelope.Data, &resp); err == nil && len(resp.Messages) > 0 {
|
||||
return true, r.storeRound(ctx, req, resp.Messages)
|
||||
return true, r.storeRound(ctx, req, resp.Messages, resp.Usage)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -578,7 +587,7 @@ func (r *Resolver) tryStoreStream(ctx context.Context, req conversation.ChatRequ
|
||||
// fallback: data: {messages: [...]}
|
||||
var resp gatewayResponse
|
||||
if err := json.Unmarshal([]byte(data), &resp); err == nil && len(resp.Messages) > 0 {
|
||||
return true, r.storeRound(ctx, req, resp.Messages)
|
||||
return true, r.storeRound(ctx, req, resp.Messages, resp.Usage)
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
@@ -648,7 +657,12 @@ func (r *Resolver) resolveContainerID(ctx context.Context, botID, explicit strin
|
||||
|
||||
// --- message loading ---
|
||||
|
||||
func (r *Resolver) loadMessages(ctx context.Context, chatID string, maxContextMinutes int) ([]conversation.ModelMessage, error) {
|
||||
type messageWithUsage struct {
|
||||
Message conversation.ModelMessage
|
||||
UsageInputTokens *int
|
||||
}
|
||||
|
||||
func (r *Resolver) loadMessages(ctx context.Context, chatID string, maxContextMinutes int) ([]messageWithUsage, error) {
|
||||
if r.messageService == nil {
|
||||
return nil, nil
|
||||
}
|
||||
@@ -657,7 +671,7 @@ func (r *Resolver) loadMessages(ctx context.Context, chatID string, maxContextMi
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var result []conversation.ModelMessage
|
||||
var result []messageWithUsage
|
||||
for _, m := range msgs {
|
||||
var mm conversation.ModelMessage
|
||||
if err := json.Unmarshal(m.Content, &mm); err != nil {
|
||||
@@ -667,11 +681,84 @@ func (r *Resolver) loadMessages(ctx context.Context, chatID string, maxContextMi
|
||||
} else {
|
||||
mm.Role = m.Role
|
||||
}
|
||||
result = append(result, mm)
|
||||
var inputTokens *int
|
||||
if len(m.Usage) > 0 {
|
||||
var u gatewayUsage
|
||||
if json.Unmarshal(m.Usage, &u) == nil {
|
||||
inputTokens = u.InputTokens
|
||||
}
|
||||
}
|
||||
result = append(result, messageWithUsage{Message: mm, UsageInputTokens: inputTokens})
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func estimateMessageTokens(msg conversation.ModelMessage) int {
|
||||
text := msg.TextContent()
|
||||
if len(text) == 0 {
|
||||
data, _ := json.Marshal(msg.Content)
|
||||
return len(data) / 4
|
||||
}
|
||||
return len(text) / 4
|
||||
}
|
||||
|
||||
func trimMessagesByTokens(messages []messageWithUsage, maxTokens int) []conversation.ModelMessage {
|
||||
if maxTokens <= 0 || len(messages) == 0 {
|
||||
result := make([]conversation.ModelMessage, len(messages))
|
||||
for i, m := range messages {
|
||||
result[i] = m.Message
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Scan backwards. When a message with UsageInputTokens is found, that value
|
||||
// represents the cumulative input tokens for all messages up to and including
|
||||
// that message. Messages after it are estimated with chars/4.
|
||||
totalTokens := 0
|
||||
anchorFound := false
|
||||
cutoff := 0
|
||||
|
||||
tailEstimate := 0
|
||||
for i := len(messages) - 1; i >= 0; i-- {
|
||||
if !anchorFound && messages[i].UsageInputTokens != nil {
|
||||
anchorFound = true
|
||||
totalTokens = *messages[i].UsageInputTokens + tailEstimate
|
||||
if totalTokens > maxTokens {
|
||||
cutoff = i + 1
|
||||
break
|
||||
}
|
||||
continue
|
||||
}
|
||||
est := estimateMessageTokens(messages[i].Message)
|
||||
if anchorFound {
|
||||
totalTokens += est
|
||||
if totalTokens > maxTokens {
|
||||
cutoff = i + 1
|
||||
break
|
||||
}
|
||||
} else {
|
||||
tailEstimate += est
|
||||
}
|
||||
}
|
||||
|
||||
if !anchorFound {
|
||||
totalTokens = 0
|
||||
for i := len(messages) - 1; i >= 0; i-- {
|
||||
totalTokens += estimateMessageTokens(messages[i].Message)
|
||||
if totalTokens > maxTokens {
|
||||
cutoff = i + 1
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result := make([]conversation.ModelMessage, 0, len(messages)-cutoff)
|
||||
for _, m := range messages[cutoff:] {
|
||||
result = append(result, m.Message)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
type memoryContextItem struct {
|
||||
Namespace string
|
||||
Item memory.MemoryItem
|
||||
@@ -792,9 +879,7 @@ func (r *Resolver) persistUserMessage(ctx context.Context, req conversation.Chat
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *Resolver) storeRound(ctx context.Context, req conversation.ChatRequest, messages []conversation.ModelMessage) error {
|
||||
// Add user query as the first message if not already present in the round.
|
||||
// This ensures the user's prompt is persisted alongside the assistant's response.
|
||||
func (r *Resolver) storeRound(ctx context.Context, req conversation.ChatRequest, messages []conversation.ModelMessage, usage json.RawMessage) error {
|
||||
fullRound := make([]conversation.ModelMessage, 0, len(messages)+1)
|
||||
hasUserQuery := false
|
||||
for _, m := range messages {
|
||||
@@ -813,7 +898,6 @@ func (r *Resolver) storeRound(ctx context.Context, req conversation.ChatRequest,
|
||||
}
|
||||
for _, m := range messages {
|
||||
if req.UserMessagePersisted && m.Role == "user" && strings.TrimSpace(m.TextContent()) == strings.TrimSpace(req.Query) {
|
||||
// User message was already persisted before streaming; skip duplicate copy in round payload.
|
||||
continue
|
||||
}
|
||||
fullRound = append(fullRound, m)
|
||||
@@ -822,14 +906,12 @@ func (r *Resolver) storeRound(ctx context.Context, req conversation.ChatRequest,
|
||||
return nil
|
||||
}
|
||||
|
||||
r.storeMessages(ctx, req, fullRound)
|
||||
// Run memory extraction in the background so that the SSE stream can
|
||||
// finish immediately after messages are persisted.
|
||||
r.storeMessages(ctx, req, fullRound, usage)
|
||||
go r.storeMemory(context.WithoutCancel(ctx), req.BotID, fullRound)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Resolver) storeMessages(ctx context.Context, req conversation.ChatRequest, messages []conversation.ModelMessage) {
|
||||
func (r *Resolver) storeMessages(ctx context.Context, req conversation.ChatRequest, messages []conversation.ModelMessage, usage json.RawMessage) {
|
||||
if r.messageService == nil {
|
||||
return
|
||||
}
|
||||
@@ -838,7 +920,7 @@ func (r *Resolver) storeMessages(ctx context.Context, req conversation.ChatReque
|
||||
}
|
||||
meta := buildRouteMetadata(req)
|
||||
senderChannelIdentityID, senderUserID := r.resolvePersistSenderIDs(ctx, req)
|
||||
for _, msg := range messages {
|
||||
for i, msg := range messages {
|
||||
content, err := json.Marshal(msg)
|
||||
if err != nil {
|
||||
r.logger.Warn("storeMessages: marshal failed", slog.Any("error", err))
|
||||
@@ -857,9 +939,12 @@ func (r *Resolver) storeMessages(ctx context.Context, req conversation.ChatReque
|
||||
assets = chatAttachmentsToAssetRefs(req.Attachments)
|
||||
}
|
||||
} else if strings.TrimSpace(req.ExternalMessageID) != "" {
|
||||
// Assistant/tool/system outputs are linked to the inbound source message for cross-channel reply threading.
|
||||
sourceReplyToMessageID = req.ExternalMessageID
|
||||
}
|
||||
var msgUsage json.RawMessage
|
||||
if i == len(messages)-1 && len(usage) > 0 {
|
||||
msgUsage = usage
|
||||
}
|
||||
if _, err := r.messageService.Persist(ctx, messagepkg.PersistInput{
|
||||
BotID: req.BotID,
|
||||
RouteID: req.RouteID,
|
||||
@@ -871,6 +956,7 @@ func (r *Resolver) storeMessages(ctx context.Context, req conversation.ChatReque
|
||||
Role: msg.Role,
|
||||
Content: content,
|
||||
Metadata: meta,
|
||||
Usage: msgUsage,
|
||||
Assets: assets,
|
||||
}); err != nil {
|
||||
r.logger.Warn("persist message failed", slog.Any("error", err))
|
||||
|
||||
@@ -14,7 +14,7 @@ import (
|
||||
const createBot = `-- name: CreateBot :one
|
||||
INSERT INTO bots (owner_user_id, type, display_name, avatar_url, is_active, metadata, status)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7)
|
||||
RETURNING id, owner_user_id, type, display_name, avatar_url, is_active, status, max_context_load_time, language, allow_guest, chat_model_id, memory_model_id, embedding_model_id, search_provider_id, metadata, created_at, updated_at
|
||||
RETURNING id, owner_user_id, type, display_name, avatar_url, is_active, status, max_context_load_time, max_context_tokens, language, allow_guest, chat_model_id, memory_model_id, embedding_model_id, search_provider_id, metadata, created_at, updated_at
|
||||
`
|
||||
|
||||
type CreateBotParams struct {
|
||||
@@ -47,6 +47,7 @@ func (q *Queries) CreateBot(ctx context.Context, arg CreateBotParams) (Bot, erro
|
||||
&i.IsActive,
|
||||
&i.Status,
|
||||
&i.MaxContextLoadTime,
|
||||
&i.MaxContextTokens,
|
||||
&i.Language,
|
||||
&i.AllowGuest,
|
||||
&i.ChatModelID,
|
||||
@@ -84,7 +85,7 @@ func (q *Queries) DeleteBotMember(ctx context.Context, arg DeleteBotMemberParams
|
||||
}
|
||||
|
||||
const getBotByID = `-- name: GetBotByID :one
|
||||
SELECT id, owner_user_id, type, display_name, avatar_url, is_active, status, max_context_load_time, language, allow_guest, chat_model_id, memory_model_id, embedding_model_id, search_provider_id, metadata, created_at, updated_at
|
||||
SELECT id, owner_user_id, type, display_name, avatar_url, is_active, status, max_context_load_time, max_context_tokens, language, allow_guest, chat_model_id, memory_model_id, embedding_model_id, search_provider_id, metadata, created_at, updated_at
|
||||
FROM bots
|
||||
WHERE id = $1
|
||||
`
|
||||
@@ -101,6 +102,7 @@ func (q *Queries) GetBotByID(ctx context.Context, id pgtype.UUID) (Bot, error) {
|
||||
&i.IsActive,
|
||||
&i.Status,
|
||||
&i.MaxContextLoadTime,
|
||||
&i.MaxContextTokens,
|
||||
&i.Language,
|
||||
&i.AllowGuest,
|
||||
&i.ChatModelID,
|
||||
@@ -171,7 +173,7 @@ func (q *Queries) ListBotMembers(ctx context.Context, botID pgtype.UUID) ([]BotM
|
||||
}
|
||||
|
||||
const listBotsByMember = `-- name: ListBotsByMember :many
|
||||
SELECT b.id, b.owner_user_id, b.type, b.display_name, b.avatar_url, b.is_active, b.status, b.max_context_load_time, b.language, b.allow_guest, b.chat_model_id, b.memory_model_id, b.embedding_model_id, b.search_provider_id, b.metadata, b.created_at, b.updated_at
|
||||
SELECT b.id, b.owner_user_id, b.type, b.display_name, b.avatar_url, b.is_active, b.status, b.max_context_load_time, b.max_context_tokens, b.language, b.allow_guest, b.chat_model_id, b.memory_model_id, b.embedding_model_id, b.search_provider_id, b.metadata, b.created_at, b.updated_at
|
||||
FROM bots b
|
||||
JOIN bot_members m ON m.bot_id = b.id
|
||||
WHERE m.user_id = $1
|
||||
@@ -196,6 +198,7 @@ func (q *Queries) ListBotsByMember(ctx context.Context, userID pgtype.UUID) ([]B
|
||||
&i.IsActive,
|
||||
&i.Status,
|
||||
&i.MaxContextLoadTime,
|
||||
&i.MaxContextTokens,
|
||||
&i.Language,
|
||||
&i.AllowGuest,
|
||||
&i.ChatModelID,
|
||||
@@ -217,7 +220,7 @@ func (q *Queries) ListBotsByMember(ctx context.Context, userID pgtype.UUID) ([]B
|
||||
}
|
||||
|
||||
const listBotsByOwner = `-- name: ListBotsByOwner :many
|
||||
SELECT id, owner_user_id, type, display_name, avatar_url, is_active, status, max_context_load_time, language, allow_guest, chat_model_id, memory_model_id, embedding_model_id, search_provider_id, metadata, created_at, updated_at
|
||||
SELECT id, owner_user_id, type, display_name, avatar_url, is_active, status, max_context_load_time, max_context_tokens, language, allow_guest, chat_model_id, memory_model_id, embedding_model_id, search_provider_id, metadata, created_at, updated_at
|
||||
FROM bots
|
||||
WHERE owner_user_id = $1
|
||||
ORDER BY created_at DESC
|
||||
@@ -241,6 +244,7 @@ func (q *Queries) ListBotsByOwner(ctx context.Context, ownerUserID pgtype.UUID)
|
||||
&i.IsActive,
|
||||
&i.Status,
|
||||
&i.MaxContextLoadTime,
|
||||
&i.MaxContextTokens,
|
||||
&i.Language,
|
||||
&i.AllowGuest,
|
||||
&i.ChatModelID,
|
||||
@@ -266,7 +270,7 @@ UPDATE bots
|
||||
SET owner_user_id = $2,
|
||||
updated_at = now()
|
||||
WHERE id = $1
|
||||
RETURNING id, owner_user_id, type, display_name, avatar_url, is_active, status, max_context_load_time, language, allow_guest, chat_model_id, memory_model_id, embedding_model_id, search_provider_id, metadata, created_at, updated_at
|
||||
RETURNING id, owner_user_id, type, display_name, avatar_url, is_active, status, max_context_load_time, max_context_tokens, language, allow_guest, chat_model_id, memory_model_id, embedding_model_id, search_provider_id, metadata, created_at, updated_at
|
||||
`
|
||||
|
||||
type UpdateBotOwnerParams struct {
|
||||
@@ -286,6 +290,7 @@ func (q *Queries) UpdateBotOwner(ctx context.Context, arg UpdateBotOwnerParams)
|
||||
&i.IsActive,
|
||||
&i.Status,
|
||||
&i.MaxContextLoadTime,
|
||||
&i.MaxContextTokens,
|
||||
&i.Language,
|
||||
&i.AllowGuest,
|
||||
&i.ChatModelID,
|
||||
@@ -307,7 +312,7 @@ SET display_name = $2,
|
||||
metadata = $5,
|
||||
updated_at = now()
|
||||
WHERE id = $1
|
||||
RETURNING id, owner_user_id, type, display_name, avatar_url, is_active, status, max_context_load_time, language, allow_guest, chat_model_id, memory_model_id, embedding_model_id, search_provider_id, metadata, created_at, updated_at
|
||||
RETURNING id, owner_user_id, type, display_name, avatar_url, is_active, status, max_context_load_time, max_context_tokens, language, allow_guest, chat_model_id, memory_model_id, embedding_model_id, search_provider_id, metadata, created_at, updated_at
|
||||
`
|
||||
|
||||
type UpdateBotProfileParams struct {
|
||||
@@ -336,6 +341,7 @@ func (q *Queries) UpdateBotProfile(ctx context.Context, arg UpdateBotProfilePara
|
||||
&i.IsActive,
|
||||
&i.Status,
|
||||
&i.MaxContextLoadTime,
|
||||
&i.MaxContextTokens,
|
||||
&i.Language,
|
||||
&i.AllowGuest,
|
||||
&i.ChatModelID,
|
||||
|
||||
@@ -590,7 +590,7 @@ WITH updated AS (
|
||||
SET display_name = $1,
|
||||
updated_at = now()
|
||||
WHERE bots.id = $2
|
||||
RETURNING id, owner_user_id, type, display_name, avatar_url, is_active, status, max_context_load_time, language, allow_guest, chat_model_id, memory_model_id, embedding_model_id, search_provider_id, metadata, created_at, updated_at
|
||||
RETURNING id, owner_user_id, type, display_name, avatar_url, is_active, status, max_context_load_time, max_context_tokens, language, allow_guest, chat_model_id, memory_model_id, embedding_model_id, search_provider_id, metadata, created_at, updated_at
|
||||
)
|
||||
SELECT
|
||||
updated.id AS id,
|
||||
|
||||
@@ -22,7 +22,8 @@ INSERT INTO bot_history_messages (
|
||||
source_reply_to_message_id,
|
||||
role,
|
||||
content,
|
||||
metadata
|
||||
metadata,
|
||||
usage
|
||||
)
|
||||
VALUES (
|
||||
$1,
|
||||
@@ -34,7 +35,8 @@ VALUES (
|
||||
$7::text,
|
||||
$8,
|
||||
$9,
|
||||
$10
|
||||
$10,
|
||||
$11
|
||||
)
|
||||
RETURNING
|
||||
id,
|
||||
@@ -48,6 +50,7 @@ RETURNING
|
||||
role,
|
||||
content,
|
||||
metadata,
|
||||
usage,
|
||||
created_at
|
||||
`
|
||||
|
||||
@@ -62,6 +65,7 @@ type CreateMessageParams struct {
|
||||
Role string `json:"role"`
|
||||
Content []byte `json:"content"`
|
||||
Metadata []byte `json:"metadata"`
|
||||
Usage []byte `json:"usage"`
|
||||
}
|
||||
|
||||
type CreateMessageRow struct {
|
||||
@@ -76,6 +80,7 @@ type CreateMessageRow struct {
|
||||
Role string `json:"role"`
|
||||
Content []byte `json:"content"`
|
||||
Metadata []byte `json:"metadata"`
|
||||
Usage []byte `json:"usage"`
|
||||
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||
}
|
||||
|
||||
@@ -91,6 +96,7 @@ func (q *Queries) CreateMessage(ctx context.Context, arg CreateMessageParams) (C
|
||||
arg.Role,
|
||||
arg.Content,
|
||||
arg.Metadata,
|
||||
arg.Usage,
|
||||
)
|
||||
var i CreateMessageRow
|
||||
err := row.Scan(
|
||||
@@ -105,6 +111,7 @@ func (q *Queries) CreateMessage(ctx context.Context, arg CreateMessageParams) (C
|
||||
&i.Role,
|
||||
&i.Content,
|
||||
&i.Metadata,
|
||||
&i.Usage,
|
||||
&i.CreatedAt,
|
||||
)
|
||||
return i, err
|
||||
@@ -133,6 +140,7 @@ SELECT
|
||||
m.role,
|
||||
m.content,
|
||||
m.metadata,
|
||||
m.usage,
|
||||
m.created_at,
|
||||
ci.display_name AS sender_display_name,
|
||||
ci.avatar_url AS sender_avatar_url
|
||||
@@ -155,6 +163,7 @@ type ListMessagesRow struct {
|
||||
Role string `json:"role"`
|
||||
Content []byte `json:"content"`
|
||||
Metadata []byte `json:"metadata"`
|
||||
Usage []byte `json:"usage"`
|
||||
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||
SenderDisplayName pgtype.Text `json:"sender_display_name"`
|
||||
SenderAvatarUrl pgtype.Text `json:"sender_avatar_url"`
|
||||
@@ -181,6 +190,7 @@ func (q *Queries) ListMessages(ctx context.Context, botID pgtype.UUID) ([]ListMe
|
||||
&i.Role,
|
||||
&i.Content,
|
||||
&i.Metadata,
|
||||
&i.Usage,
|
||||
&i.CreatedAt,
|
||||
&i.SenderDisplayName,
|
||||
&i.SenderAvatarUrl,
|
||||
@@ -208,6 +218,7 @@ SELECT
|
||||
m.role,
|
||||
m.content,
|
||||
m.metadata,
|
||||
m.usage,
|
||||
m.created_at,
|
||||
ci.display_name AS sender_display_name,
|
||||
ci.avatar_url AS sender_avatar_url
|
||||
@@ -237,6 +248,7 @@ type ListMessagesBeforeRow struct {
|
||||
Role string `json:"role"`
|
||||
Content []byte `json:"content"`
|
||||
Metadata []byte `json:"metadata"`
|
||||
Usage []byte `json:"usage"`
|
||||
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||
SenderDisplayName pgtype.Text `json:"sender_display_name"`
|
||||
SenderAvatarUrl pgtype.Text `json:"sender_avatar_url"`
|
||||
@@ -263,6 +275,7 @@ func (q *Queries) ListMessagesBefore(ctx context.Context, arg ListMessagesBefore
|
||||
&i.Role,
|
||||
&i.Content,
|
||||
&i.Metadata,
|
||||
&i.Usage,
|
||||
&i.CreatedAt,
|
||||
&i.SenderDisplayName,
|
||||
&i.SenderAvatarUrl,
|
||||
@@ -290,6 +303,7 @@ SELECT
|
||||
m.role,
|
||||
m.content,
|
||||
m.metadata,
|
||||
m.usage,
|
||||
m.created_at,
|
||||
ci.display_name AS sender_display_name,
|
||||
ci.avatar_url AS sender_avatar_url
|
||||
@@ -317,6 +331,7 @@ type ListMessagesLatestRow struct {
|
||||
Role string `json:"role"`
|
||||
Content []byte `json:"content"`
|
||||
Metadata []byte `json:"metadata"`
|
||||
Usage []byte `json:"usage"`
|
||||
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||
SenderDisplayName pgtype.Text `json:"sender_display_name"`
|
||||
SenderAvatarUrl pgtype.Text `json:"sender_avatar_url"`
|
||||
@@ -343,6 +358,7 @@ func (q *Queries) ListMessagesLatest(ctx context.Context, arg ListMessagesLatest
|
||||
&i.Role,
|
||||
&i.Content,
|
||||
&i.Metadata,
|
||||
&i.Usage,
|
||||
&i.CreatedAt,
|
||||
&i.SenderDisplayName,
|
||||
&i.SenderAvatarUrl,
|
||||
@@ -370,6 +386,7 @@ SELECT
|
||||
m.role,
|
||||
m.content,
|
||||
m.metadata,
|
||||
m.usage,
|
||||
m.created_at,
|
||||
ci.display_name AS sender_display_name,
|
||||
ci.avatar_url AS sender_avatar_url
|
||||
@@ -397,6 +414,7 @@ type ListMessagesSinceRow struct {
|
||||
Role string `json:"role"`
|
||||
Content []byte `json:"content"`
|
||||
Metadata []byte `json:"metadata"`
|
||||
Usage []byte `json:"usage"`
|
||||
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||
SenderDisplayName pgtype.Text `json:"sender_display_name"`
|
||||
SenderAvatarUrl pgtype.Text `json:"sender_avatar_url"`
|
||||
@@ -423,6 +441,7 @@ func (q *Queries) ListMessagesSince(ctx context.Context, arg ListMessagesSincePa
|
||||
&i.Role,
|
||||
&i.Content,
|
||||
&i.Metadata,
|
||||
&i.Usage,
|
||||
&i.CreatedAt,
|
||||
&i.SenderDisplayName,
|
||||
&i.SenderAvatarUrl,
|
||||
|
||||
@@ -17,6 +17,7 @@ type Bot struct {
|
||||
IsActive bool `json:"is_active"`
|
||||
Status string `json:"status"`
|
||||
MaxContextLoadTime int32 `json:"max_context_load_time"`
|
||||
MaxContextTokens int32 `json:"max_context_tokens"`
|
||||
Language string `json:"language"`
|
||||
AllowGuest bool `json:"allow_guest"`
|
||||
ChatModelID pgtype.UUID `json:"chat_model_id"`
|
||||
@@ -69,6 +70,7 @@ type BotHistoryMessage struct {
|
||||
Role string `json:"role"`
|
||||
Content []byte `json:"content"`
|
||||
Metadata []byte `json:"metadata"`
|
||||
Usage []byte `json:"usage"`
|
||||
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
const deleteSettingsByBotID = `-- name: DeleteSettingsByBotID :exec
|
||||
UPDATE bots
|
||||
SET max_context_load_time = 1440,
|
||||
max_context_tokens = 0,
|
||||
language = 'auto',
|
||||
allow_guest = false,
|
||||
chat_model_id = NULL,
|
||||
@@ -33,6 +34,7 @@ const getSettingsByBotID = `-- name: GetSettingsByBotID :one
|
||||
SELECT
|
||||
bots.id AS bot_id,
|
||||
bots.max_context_load_time,
|
||||
bots.max_context_tokens,
|
||||
bots.language,
|
||||
bots.allow_guest,
|
||||
chat_models.model_id AS chat_model_id,
|
||||
@@ -50,6 +52,7 @@ WHERE bots.id = $1
|
||||
type GetSettingsByBotIDRow struct {
|
||||
BotID pgtype.UUID `json:"bot_id"`
|
||||
MaxContextLoadTime int32 `json:"max_context_load_time"`
|
||||
MaxContextTokens int32 `json:"max_context_tokens"`
|
||||
Language string `json:"language"`
|
||||
AllowGuest bool `json:"allow_guest"`
|
||||
ChatModelID pgtype.Text `json:"chat_model_id"`
|
||||
@@ -64,6 +67,7 @@ func (q *Queries) GetSettingsByBotID(ctx context.Context, id pgtype.UUID) (GetSe
|
||||
err := row.Scan(
|
||||
&i.BotID,
|
||||
&i.MaxContextLoadTime,
|
||||
&i.MaxContextTokens,
|
||||
&i.Language,
|
||||
&i.AllowGuest,
|
||||
&i.ChatModelID,
|
||||
@@ -78,19 +82,21 @@ const upsertBotSettings = `-- name: UpsertBotSettings :one
|
||||
WITH updated AS (
|
||||
UPDATE bots
|
||||
SET max_context_load_time = $1,
|
||||
language = $2,
|
||||
allow_guest = $3,
|
||||
chat_model_id = COALESCE($4::uuid, bots.chat_model_id),
|
||||
memory_model_id = COALESCE($5::uuid, bots.memory_model_id),
|
||||
embedding_model_id = COALESCE($6::uuid, bots.embedding_model_id),
|
||||
search_provider_id = COALESCE($7::uuid, bots.search_provider_id),
|
||||
max_context_tokens = $2,
|
||||
language = $3,
|
||||
allow_guest = $4,
|
||||
chat_model_id = COALESCE($5::uuid, bots.chat_model_id),
|
||||
memory_model_id = COALESCE($6::uuid, bots.memory_model_id),
|
||||
embedding_model_id = COALESCE($7::uuid, bots.embedding_model_id),
|
||||
search_provider_id = COALESCE($8::uuid, bots.search_provider_id),
|
||||
updated_at = now()
|
||||
WHERE bots.id = $8
|
||||
RETURNING bots.id, bots.max_context_load_time, bots.language, bots.allow_guest, bots.chat_model_id, bots.memory_model_id, bots.embedding_model_id, bots.search_provider_id
|
||||
WHERE bots.id = $9
|
||||
RETURNING bots.id, bots.max_context_load_time, bots.max_context_tokens, bots.language, bots.allow_guest, bots.chat_model_id, bots.memory_model_id, bots.embedding_model_id, bots.search_provider_id
|
||||
)
|
||||
SELECT
|
||||
updated.id AS bot_id,
|
||||
updated.max_context_load_time,
|
||||
updated.max_context_tokens,
|
||||
updated.language,
|
||||
updated.allow_guest,
|
||||
chat_models.model_id AS chat_model_id,
|
||||
@@ -106,6 +112,7 @@ LEFT JOIN search_providers ON search_providers.id = updated.search_provider_id
|
||||
|
||||
type UpsertBotSettingsParams struct {
|
||||
MaxContextLoadTime int32 `json:"max_context_load_time"`
|
||||
MaxContextTokens int32 `json:"max_context_tokens"`
|
||||
Language string `json:"language"`
|
||||
AllowGuest bool `json:"allow_guest"`
|
||||
ChatModelID pgtype.UUID `json:"chat_model_id"`
|
||||
@@ -118,6 +125,7 @@ type UpsertBotSettingsParams struct {
|
||||
type UpsertBotSettingsRow struct {
|
||||
BotID pgtype.UUID `json:"bot_id"`
|
||||
MaxContextLoadTime int32 `json:"max_context_load_time"`
|
||||
MaxContextTokens int32 `json:"max_context_tokens"`
|
||||
Language string `json:"language"`
|
||||
AllowGuest bool `json:"allow_guest"`
|
||||
ChatModelID pgtype.Text `json:"chat_model_id"`
|
||||
@@ -129,6 +137,7 @@ type UpsertBotSettingsRow struct {
|
||||
func (q *Queries) UpsertBotSettings(ctx context.Context, arg UpsertBotSettingsParams) (UpsertBotSettingsRow, error) {
|
||||
row := q.db.QueryRow(ctx, upsertBotSettings,
|
||||
arg.MaxContextLoadTime,
|
||||
arg.MaxContextTokens,
|
||||
arg.Language,
|
||||
arg.AllowGuest,
|
||||
arg.ChatModelID,
|
||||
@@ -141,6 +150,7 @@ func (q *Queries) UpsertBotSettings(ctx context.Context, arg UpsertBotSettingsPa
|
||||
err := row.Scan(
|
||||
&i.BotID,
|
||||
&i.MaxContextLoadTime,
|
||||
&i.MaxContextTokens,
|
||||
&i.Language,
|
||||
&i.AllowGuest,
|
||||
&i.ChatModelID,
|
||||
|
||||
@@ -79,6 +79,7 @@ func (s *DBService) Persist(ctx context.Context, input PersistInput) (Message, e
|
||||
Role: input.Role,
|
||||
Content: content,
|
||||
Metadata: metaBytes,
|
||||
Usage: input.Usage,
|
||||
})
|
||||
if err != nil {
|
||||
return Message{}, err
|
||||
@@ -213,6 +214,7 @@ func toMessageFromCreate(row sqlc.CreateMessageRow) Message {
|
||||
row.Role,
|
||||
row.Content,
|
||||
row.Metadata,
|
||||
row.Usage,
|
||||
row.CreatedAt,
|
||||
)
|
||||
}
|
||||
@@ -232,6 +234,7 @@ func toMessageFromListRow(row sqlc.ListMessagesRow) Message {
|
||||
row.Role,
|
||||
row.Content,
|
||||
row.Metadata,
|
||||
row.Usage,
|
||||
row.CreatedAt,
|
||||
)
|
||||
}
|
||||
@@ -251,6 +254,7 @@ func toMessageFromSinceRow(row sqlc.ListMessagesSinceRow) Message {
|
||||
row.Role,
|
||||
row.Content,
|
||||
row.Metadata,
|
||||
row.Usage,
|
||||
row.CreatedAt,
|
||||
)
|
||||
}
|
||||
@@ -270,6 +274,7 @@ func toMessageFromLatestRow(row sqlc.ListMessagesLatestRow) Message {
|
||||
row.Role,
|
||||
row.Content,
|
||||
row.Metadata,
|
||||
row.Usage,
|
||||
row.CreatedAt,
|
||||
)
|
||||
}
|
||||
@@ -288,6 +293,7 @@ func toMessageFields(
|
||||
role string,
|
||||
content []byte,
|
||||
metadata []byte,
|
||||
usage []byte,
|
||||
createdAt pgtype.Timestamptz,
|
||||
) Message {
|
||||
return Message{
|
||||
@@ -304,6 +310,7 @@ func toMessageFields(
|
||||
Role: role,
|
||||
Content: json.RawMessage(content),
|
||||
Metadata: parseJSONMap(metadata),
|
||||
Usage: json.RawMessage(usage),
|
||||
CreatedAt: createdAt.Time,
|
||||
}
|
||||
}
|
||||
@@ -347,6 +354,7 @@ func toMessageFromBeforeRow(row sqlc.ListMessagesBeforeRow) Message {
|
||||
row.Role,
|
||||
row.Content,
|
||||
row.Metadata,
|
||||
row.Usage,
|
||||
row.CreatedAt,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ type Message struct {
|
||||
Role string `json:"role"`
|
||||
Content json.RawMessage `json:"content"`
|
||||
Metadata map[string]any `json:"metadata,omitempty"`
|
||||
Usage json.RawMessage `json:"usage,omitempty"`
|
||||
Assets []MessageAsset `json:"assets,omitempty"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
}
|
||||
@@ -59,6 +60,7 @@ type PersistInput struct {
|
||||
Role string
|
||||
Content json.RawMessage
|
||||
Metadata map[string]any
|
||||
Usage json.RawMessage
|
||||
Assets []AssetRef
|
||||
}
|
||||
|
||||
|
||||
@@ -54,10 +54,13 @@ func (s *Service) UpsertBot(ctx context.Context, botID string, req UpsertRequest
|
||||
}
|
||||
isPersonalBot := strings.EqualFold(strings.TrimSpace(botRow.Type), "personal")
|
||||
|
||||
current := normalizeBotSetting(botRow.MaxContextLoadTime, botRow.Language, botRow.AllowGuest)
|
||||
current := normalizeBotSetting(botRow.MaxContextLoadTime, botRow.MaxContextTokens, botRow.Language, botRow.AllowGuest)
|
||||
if req.MaxContextLoadTime != nil && *req.MaxContextLoadTime > 0 {
|
||||
current.MaxContextLoadTime = *req.MaxContextLoadTime
|
||||
}
|
||||
if req.MaxContextTokens != nil && *req.MaxContextTokens >= 0 {
|
||||
current.MaxContextTokens = *req.MaxContextTokens
|
||||
}
|
||||
if strings.TrimSpace(req.Language) != "" {
|
||||
current.Language = strings.TrimSpace(req.Language)
|
||||
}
|
||||
@@ -106,6 +109,7 @@ func (s *Service) UpsertBot(ctx context.Context, botID string, req UpsertRequest
|
||||
updated, err := s.queries.UpsertBotSettings(ctx, sqlc.UpsertBotSettingsParams{
|
||||
ID: pgID,
|
||||
MaxContextLoadTime: int32(current.MaxContextLoadTime),
|
||||
MaxContextTokens: int32(current.MaxContextTokens),
|
||||
Language: current.Language,
|
||||
AllowGuest: current.AllowGuest,
|
||||
ChatModelID: chatModelUUID,
|
||||
@@ -130,15 +134,19 @@ func (s *Service) Delete(ctx context.Context, botID string) error {
|
||||
return s.queries.DeleteSettingsByBotID(ctx, pgID)
|
||||
}
|
||||
|
||||
func normalizeBotSetting(maxContextLoadTime int32, language string, allowGuest bool) Settings {
|
||||
func normalizeBotSetting(maxContextLoadTime int32, maxContextTokens int32, language string, allowGuest bool) Settings {
|
||||
settings := Settings{
|
||||
MaxContextLoadTime: int(maxContextLoadTime),
|
||||
MaxContextTokens: int(maxContextTokens),
|
||||
Language: strings.TrimSpace(language),
|
||||
AllowGuest: allowGuest,
|
||||
}
|
||||
if settings.MaxContextLoadTime <= 0 {
|
||||
settings.MaxContextLoadTime = DefaultMaxContextLoadTime
|
||||
}
|
||||
if settings.MaxContextTokens < 0 {
|
||||
settings.MaxContextTokens = 0
|
||||
}
|
||||
if settings.Language == "" {
|
||||
settings.Language = DefaultLanguage
|
||||
}
|
||||
@@ -148,6 +156,7 @@ func normalizeBotSetting(maxContextLoadTime int32, language string, allowGuest b
|
||||
func normalizeBotSettingsReadRow(row sqlc.GetSettingsByBotIDRow) Settings {
|
||||
return normalizeBotSettingsFields(
|
||||
row.MaxContextLoadTime,
|
||||
row.MaxContextTokens,
|
||||
row.Language,
|
||||
row.AllowGuest,
|
||||
row.ChatModelID,
|
||||
@@ -160,6 +169,7 @@ func normalizeBotSettingsReadRow(row sqlc.GetSettingsByBotIDRow) Settings {
|
||||
func normalizeBotSettingsWriteRow(row sqlc.UpsertBotSettingsRow) Settings {
|
||||
return normalizeBotSettingsFields(
|
||||
row.MaxContextLoadTime,
|
||||
row.MaxContextTokens,
|
||||
row.Language,
|
||||
row.AllowGuest,
|
||||
row.ChatModelID,
|
||||
@@ -171,6 +181,7 @@ func normalizeBotSettingsWriteRow(row sqlc.UpsertBotSettingsRow) Settings {
|
||||
|
||||
func normalizeBotSettingsFields(
|
||||
maxContextLoadTime int32,
|
||||
maxContextTokens int32,
|
||||
language string,
|
||||
allowGuest bool,
|
||||
chatModelID pgtype.Text,
|
||||
@@ -178,7 +189,7 @@ func normalizeBotSettingsFields(
|
||||
embeddingModelID pgtype.Text,
|
||||
searchProviderID pgtype.UUID,
|
||||
) Settings {
|
||||
settings := normalizeBotSetting(maxContextLoadTime, language, allowGuest)
|
||||
settings := normalizeBotSetting(maxContextLoadTime, maxContextTokens, language, allowGuest)
|
||||
settings.ChatModelID = strings.TrimSpace(chatModelID.String)
|
||||
settings.MemoryModelID = strings.TrimSpace(memoryModelID.String)
|
||||
settings.EmbeddingModelID = strings.TrimSpace(embeddingModelID.String)
|
||||
|
||||
@@ -11,6 +11,7 @@ type Settings struct {
|
||||
EmbeddingModelID string `json:"embedding_model_id"`
|
||||
SearchProviderID string `json:"search_provider_id"`
|
||||
MaxContextLoadTime int `json:"max_context_load_time"`
|
||||
MaxContextTokens int `json:"max_context_tokens"`
|
||||
Language string `json:"language"`
|
||||
AllowGuest bool `json:"allow_guest"`
|
||||
}
|
||||
@@ -21,6 +22,7 @@ type UpsertRequest struct {
|
||||
EmbeddingModelID string `json:"embedding_model_id,omitempty"`
|
||||
SearchProviderID string `json:"search_provider_id,omitempty"`
|
||||
MaxContextLoadTime *int `json:"max_context_load_time,omitempty"`
|
||||
MaxContextTokens *int `json:"max_context_tokens,omitempty"`
|
||||
Language string `json:"language,omitempty"`
|
||||
AllowGuest *bool `json:"allow_guest,omitempty"`
|
||||
}
|
||||
|
||||
@@ -673,6 +673,7 @@ export type MessageMessage = {
|
||||
sender_display_name?: string;
|
||||
sender_user_id?: string;
|
||||
source_reply_to_message_id?: string;
|
||||
usage?: Array<number>;
|
||||
};
|
||||
|
||||
export type MessageMessageAsset = {
|
||||
@@ -866,6 +867,7 @@ export type SettingsSettings = {
|
||||
embedding_model_id?: string;
|
||||
language?: string;
|
||||
max_context_load_time?: number;
|
||||
max_context_tokens?: number;
|
||||
memory_model_id?: string;
|
||||
search_provider_id?: string;
|
||||
};
|
||||
@@ -876,6 +878,7 @@ export type SettingsUpsertRequest = {
|
||||
embedding_model_id?: string;
|
||||
language?: string;
|
||||
max_context_load_time?: number;
|
||||
max_context_tokens?: number;
|
||||
memory_model_id?: string;
|
||||
search_provider_id?: string;
|
||||
};
|
||||
|
||||
@@ -354,6 +354,7 @@
|
||||
"searchProvider": "Search Provider",
|
||||
"searchProviderPlaceholder": "Select search provider",
|
||||
"maxContextLoadTime": "Max Context Load Time",
|
||||
"maxContextTokens": "Max Context Tokens",
|
||||
"language": "Language",
|
||||
"allowGuest": "Allow Guest Access",
|
||||
"allowGuestPersonalHint": "Personal bots do not support guest access. Use a public bot instead.",
|
||||
|
||||
@@ -350,6 +350,7 @@
|
||||
"searchProvider": "搜索提供方",
|
||||
"searchProviderPlaceholder": "选择搜索提供方",
|
||||
"maxContextLoadTime": "最大上下文加载时间",
|
||||
"maxContextTokens": "最大上下文Token数",
|
||||
"language": "语言",
|
||||
"allowGuest": "允许游客访问",
|
||||
"allowGuestPersonalHint": "个人 Bot 不支持游客访问,请使用公开 Bot。",
|
||||
|
||||
@@ -58,6 +58,17 @@
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Max Context Tokens -->
|
||||
<div class="space-y-2">
|
||||
<Label>{{ $t('bots.settings.maxContextTokens') }}</Label>
|
||||
<Input
|
||||
v-model.number="form.max_context_tokens"
|
||||
type="number"
|
||||
:min="0"
|
||||
placeholder="0"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Language -->
|
||||
<div class="space-y-2">
|
||||
<Label>{{ $t('bots.settings.language') }}</Label>
|
||||
@@ -226,6 +237,7 @@ const form = reactive<SettingsSettings>({
|
||||
embedding_model_id: '',
|
||||
search_provider_id: '',
|
||||
max_context_load_time: 0,
|
||||
max_context_tokens: 0,
|
||||
language: '',
|
||||
allow_guest: false,
|
||||
})
|
||||
@@ -238,6 +250,7 @@ watch(settings, (val) => {
|
||||
form.embedding_model_id = val.embedding_model_id ?? ''
|
||||
form.search_provider_id = val.search_provider_id ?? ''
|
||||
form.max_context_load_time = val.max_context_load_time ?? 0
|
||||
form.max_context_tokens = val.max_context_tokens ?? 0
|
||||
form.language = val.language ?? ''
|
||||
form.allow_guest = val.allow_guest ?? false
|
||||
}
|
||||
@@ -252,6 +265,7 @@ const hasChanges = computed(() => {
|
||||
|| form.embedding_model_id !== (s.embedding_model_id ?? '')
|
||||
|| form.search_provider_id !== (s.search_provider_id ?? '')
|
||||
|| form.max_context_load_time !== (s.max_context_load_time ?? 0)
|
||||
|| form.max_context_tokens !== (s.max_context_tokens ?? 0)
|
||||
|| form.language !== (s.language ?? '')
|
||||
if (isPublicBot.value) {
|
||||
changed = changed || form.allow_guest !== (s.allow_guest ?? false)
|
||||
|
||||
@@ -6451,6 +6451,12 @@ const docTemplate = `{
|
||||
},
|
||||
"source_reply_to_message_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"usage": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -6949,6 +6955,9 @@ const docTemplate = `{
|
||||
"max_context_load_time": {
|
||||
"type": "integer"
|
||||
},
|
||||
"max_context_tokens": {
|
||||
"type": "integer"
|
||||
},
|
||||
"memory_model_id": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -6975,6 +6984,9 @@ const docTemplate = `{
|
||||
"max_context_load_time": {
|
||||
"type": "integer"
|
||||
},
|
||||
"max_context_tokens": {
|
||||
"type": "integer"
|
||||
},
|
||||
"memory_model_id": {
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
@@ -6442,6 +6442,12 @@
|
||||
},
|
||||
"source_reply_to_message_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"usage": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -6940,6 +6946,9 @@
|
||||
"max_context_load_time": {
|
||||
"type": "integer"
|
||||
},
|
||||
"max_context_tokens": {
|
||||
"type": "integer"
|
||||
},
|
||||
"memory_model_id": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -6966,6 +6975,9 @@
|
||||
"max_context_load_time": {
|
||||
"type": "integer"
|
||||
},
|
||||
"max_context_tokens": {
|
||||
"type": "integer"
|
||||
},
|
||||
"memory_model_id": {
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
@@ -1101,6 +1101,10 @@ definitions:
|
||||
type: string
|
||||
source_reply_to_message_id:
|
||||
type: string
|
||||
usage:
|
||||
items:
|
||||
type: integer
|
||||
type: array
|
||||
type: object
|
||||
message.MessageAsset:
|
||||
properties:
|
||||
@@ -1435,6 +1439,8 @@ definitions:
|
||||
type: string
|
||||
max_context_load_time:
|
||||
type: integer
|
||||
max_context_tokens:
|
||||
type: integer
|
||||
memory_model_id:
|
||||
type: string
|
||||
search_provider_id:
|
||||
@@ -1452,6 +1458,8 @@ definitions:
|
||||
type: string
|
||||
max_context_load_time:
|
||||
type: integer
|
||||
max_context_tokens:
|
||||
type: integer
|
||||
memory_model_id:
|
||||
type: string
|
||||
search_provider_id:
|
||||
|
||||
Reference in New Issue
Block a user