mirror of
https://github.com/memohai/Memoh.git
synced 2026-04-25 07:00:48 +09:00
feat: add compaction ratio setting to control partial context compaction
Allow users to configure what percentage of older messages to compact, keeping the most recent portion intact. Default ratio is 80%, meaning the oldest 80% of uncompacted messages are summarized while the newest 20% remain as-is for full-fidelity context.
This commit is contained in:
@@ -828,6 +828,8 @@
|
||||
"compactionEnabled": "Enable Context Compaction",
|
||||
"compactionDescription": "Automatically summarize older messages when context gets too large",
|
||||
"compactionThreshold": "Compaction Threshold (input tokens)",
|
||||
"compactionRatio": "Compaction Ratio (%)",
|
||||
"compactionRatioDescription": "Percentage of older messages to compact. The remaining recent messages are kept intact.",
|
||||
"compactionModel": "Compaction Model",
|
||||
"compactionModelDescription": "Select a model for summarization. Defaults to the bot's chat model if not set.",
|
||||
"compactionModelPlaceholder": "Use chat model (default)",
|
||||
|
||||
@@ -824,6 +824,8 @@
|
||||
"compactionEnabled": "启用上下文压缩",
|
||||
"compactionDescription": "上下文过大时自动摘要旧消息以节省 token",
|
||||
"compactionThreshold": "压缩阈值(输入 token 数)",
|
||||
"compactionRatio": "压缩比例(%)",
|
||||
"compactionRatioDescription": "压缩较旧消息的百分比,剩余的最近消息保持原始完整度。",
|
||||
"compactionModel": "压缩模型",
|
||||
"compactionModelDescription": "选择用于摘要的模型,未设置时默认使用聊天模型。",
|
||||
"compactionModelPlaceholder": "使用聊天模型(默认)",
|
||||
|
||||
@@ -28,6 +28,23 @@
|
||||
:aria-label="$t('bots.settings.compactionThreshold')"
|
||||
/>
|
||||
</div>
|
||||
<div class="space-y-2">
|
||||
<Label>{{ $t('bots.settings.compactionRatio') }}</Label>
|
||||
<p class="text-xs text-muted-foreground mt-0.5">
|
||||
{{ $t('bots.settings.compactionRatioDescription') }}
|
||||
</p>
|
||||
<div class="flex items-center gap-3">
|
||||
<Slider
|
||||
:model-value="[settingsForm.compaction_ratio]"
|
||||
:min="1"
|
||||
:max="100"
|
||||
:step="1"
|
||||
class="flex-1"
|
||||
@update:model-value="(val) => settingsForm.compaction_ratio = val[0]"
|
||||
/>
|
||||
<span class="text-sm text-muted-foreground w-10 text-right tabular-nums">{{ settingsForm.compaction_ratio }}%</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="space-y-2">
|
||||
<Label>{{ $t('bots.settings.compactionModel') }}</Label>
|
||||
<p class="text-xs text-muted-foreground mt-0.5">
|
||||
@@ -254,7 +271,7 @@ import { ref, reactive, computed, watch, onMounted } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { toast } from 'vue-sonner'
|
||||
import {
|
||||
Button, Badge, Spinner, NativeSelect, Label, Switch, Input, Separator,
|
||||
Button, Badge, Spinner, NativeSelect, Label, Switch, Input, Separator, Slider,
|
||||
Pagination, PaginationContent, PaginationEllipsis,
|
||||
PaginationFirst, PaginationItem, PaginationLast,
|
||||
PaginationNext, PaginationPrevious,
|
||||
@@ -313,6 +330,7 @@ const providers = computed(() => providerData.value ?? [])
|
||||
const settingsForm = reactive({
|
||||
compaction_enabled: false,
|
||||
compaction_threshold: 100000,
|
||||
compaction_ratio: 80,
|
||||
compaction_model_id: '',
|
||||
})
|
||||
|
||||
@@ -320,6 +338,7 @@ watch(settings, (val: SettingsSettings | undefined) => {
|
||||
if (val) {
|
||||
settingsForm.compaction_enabled = val.compaction_enabled ?? false
|
||||
settingsForm.compaction_threshold = val.compaction_threshold ?? 100000
|
||||
settingsForm.compaction_ratio = val.compaction_ratio ?? 80
|
||||
settingsForm.compaction_model_id = val.compaction_model_id ?? ''
|
||||
}
|
||||
}, { immediate: true })
|
||||
@@ -329,6 +348,7 @@ const settingsChanged = computed(() => {
|
||||
const s: SettingsSettings = settings.value
|
||||
return settingsForm.compaction_enabled !== (s.compaction_enabled ?? false)
|
||||
|| settingsForm.compaction_threshold !== (s.compaction_threshold ?? 100000)
|
||||
|| settingsForm.compaction_ratio !== (s.compaction_ratio ?? 80)
|
||||
|| settingsForm.compaction_model_id !== (s.compaction_model_id ?? '')
|
||||
})
|
||||
|
||||
|
||||
@@ -174,6 +174,7 @@ CREATE TABLE IF NOT EXISTS bots (
|
||||
heartbeat_model_id UUID REFERENCES models(id) ON DELETE SET NULL,
|
||||
compaction_enabled BOOLEAN NOT NULL DEFAULT false,
|
||||
compaction_threshold INTEGER NOT NULL DEFAULT 100000,
|
||||
compaction_ratio INTEGER NOT NULL DEFAULT 80,
|
||||
compaction_model_id UUID REFERENCES models(id) ON DELETE SET NULL,
|
||||
title_model_id UUID REFERENCES models(id) ON DELETE SET NULL,
|
||||
tts_model_id UUID REFERENCES tts_models(id) ON DELETE SET NULL,
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
-- 0052_compaction_ratio (rollback)
|
||||
-- Remove compaction_ratio column from bots table.
|
||||
|
||||
ALTER TABLE bots DROP COLUMN IF EXISTS compaction_ratio;
|
||||
@@ -0,0 +1,4 @@
|
||||
-- 0052_compaction_ratio
|
||||
-- Add compaction_ratio column to bots table for controlling what percentage of messages to compact.
|
||||
|
||||
ALTER TABLE bots ADD COLUMN IF NOT EXISTS compaction_ratio INTEGER NOT NULL DEFAULT 80;
|
||||
+1
-1
@@ -4,7 +4,7 @@ VALUES ($1, $2, $3, $4, $5, $6, $7)
|
||||
RETURNING id, owner_user_id, display_name, avatar_url, timezone, is_active, status, language, reasoning_enabled, reasoning_effort, chat_model_id, search_provider_id, memory_provider_id, heartbeat_enabled, heartbeat_interval, heartbeat_prompt, metadata, created_at, updated_at;
|
||||
|
||||
-- name: GetBotByID :one
|
||||
SELECT id, owner_user_id, display_name, avatar_url, timezone, is_active, status, language, reasoning_enabled, reasoning_effort, chat_model_id, search_provider_id, memory_provider_id, heartbeat_enabled, heartbeat_interval, heartbeat_prompt, compaction_enabled, compaction_threshold, compaction_model_id, metadata, created_at, updated_at
|
||||
SELECT id, owner_user_id, display_name, avatar_url, timezone, is_active, status, language, reasoning_enabled, reasoning_effort, chat_model_id, search_provider_id, memory_provider_id, heartbeat_enabled, heartbeat_interval, heartbeat_prompt, compaction_enabled, compaction_threshold, compaction_ratio, compaction_model_id, metadata, created_at, updated_at
|
||||
FROM bots
|
||||
WHERE id = $1;
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ SELECT
|
||||
bots.heartbeat_prompt,
|
||||
bots.compaction_enabled,
|
||||
bots.compaction_threshold,
|
||||
bots.compaction_ratio,
|
||||
chat_models.id AS chat_model_id,
|
||||
heartbeat_models.id AS heartbeat_model_id,
|
||||
compaction_models.id AS compaction_model_id,
|
||||
@@ -39,6 +40,7 @@ WITH updated AS (
|
||||
heartbeat_prompt = sqlc.arg(heartbeat_prompt),
|
||||
compaction_enabled = sqlc.arg(compaction_enabled),
|
||||
compaction_threshold = sqlc.arg(compaction_threshold),
|
||||
compaction_ratio = sqlc.arg(compaction_ratio),
|
||||
chat_model_id = COALESCE(sqlc.narg(chat_model_id)::uuid, bots.chat_model_id),
|
||||
heartbeat_model_id = COALESCE(sqlc.narg(heartbeat_model_id)::uuid, bots.heartbeat_model_id),
|
||||
compaction_model_id = COALESCE(sqlc.narg(compaction_model_id)::uuid, bots.compaction_model_id),
|
||||
@@ -49,7 +51,7 @@ WITH updated AS (
|
||||
browser_context_id = COALESCE(sqlc.narg(browser_context_id)::uuid, bots.browser_context_id),
|
||||
updated_at = now()
|
||||
WHERE bots.id = sqlc.arg(id)
|
||||
RETURNING bots.id, bots.language, bots.reasoning_enabled, bots.reasoning_effort, bots.heartbeat_enabled, bots.heartbeat_interval, bots.heartbeat_prompt, bots.compaction_enabled, bots.compaction_threshold, bots.chat_model_id, bots.heartbeat_model_id, bots.compaction_model_id, bots.title_model_id, bots.search_provider_id, bots.memory_provider_id, bots.tts_model_id, bots.browser_context_id
|
||||
RETURNING bots.id, bots.language, bots.reasoning_enabled, bots.reasoning_effort, bots.heartbeat_enabled, bots.heartbeat_interval, bots.heartbeat_prompt, bots.compaction_enabled, bots.compaction_threshold, bots.compaction_ratio, bots.chat_model_id, bots.heartbeat_model_id, bots.compaction_model_id, bots.title_model_id, bots.search_provider_id, bots.memory_provider_id, bots.tts_model_id, bots.browser_context_id
|
||||
)
|
||||
SELECT
|
||||
updated.id AS bot_id,
|
||||
@@ -61,6 +63,7 @@ SELECT
|
||||
updated.heartbeat_prompt,
|
||||
updated.compaction_enabled,
|
||||
updated.compaction_threshold,
|
||||
updated.compaction_ratio,
|
||||
chat_models.id AS chat_model_id,
|
||||
heartbeat_models.id AS heartbeat_model_id,
|
||||
compaction_models.id AS compaction_model_id,
|
||||
@@ -89,6 +92,7 @@ SET language = 'auto',
|
||||
heartbeat_prompt = '',
|
||||
compaction_enabled = false,
|
||||
compaction_threshold = 100000,
|
||||
compaction_ratio = 80,
|
||||
chat_model_id = NULL,
|
||||
heartbeat_model_id = NULL,
|
||||
compaction_model_id = NULL,
|
||||
|
||||
@@ -114,10 +114,11 @@ func makeBotRow(botID, ownerUserID pgtype.UUID) *fakeRow {
|
||||
*dest[15].(*string) = "" // HeartbeatPrompt
|
||||
*dest[16].(*bool) = false // CompactionEnabled
|
||||
*dest[17].(*int32) = 100000 // CompactionThreshold
|
||||
*dest[18].(*pgtype.UUID) = pgtype.UUID{} // CompactionModelID
|
||||
*dest[19].(*[]byte) = []byte(`{}`)
|
||||
*dest[20].(*pgtype.Timestamptz) = pgtype.Timestamptz{}
|
||||
*dest[18].(*int32) = 80 // CompactionRatio
|
||||
*dest[19].(*pgtype.UUID) = pgtype.UUID{} // CompactionModelID
|
||||
*dest[20].(*[]byte) = []byte(`{}`)
|
||||
*dest[21].(*pgtype.Timestamptz) = pgtype.Timestamptz{}
|
||||
*dest[22].(*pgtype.Timestamptz) = pgtype.Timestamptz{}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
@@ -71,10 +71,11 @@ func makeBotRow(botID, ownerUserID pgtype.UUID) *fakeRow {
|
||||
*dest[15].(*string) = "" // HeartbeatPrompt
|
||||
*dest[16].(*bool) = false // CompactionEnabled
|
||||
*dest[17].(*int32) = 100000 // CompactionThreshold
|
||||
*dest[18].(*pgtype.UUID) = pgtype.UUID{} // CompactionModelID
|
||||
*dest[19].(*[]byte) = []byte(`{}`)
|
||||
*dest[20].(*pgtype.Timestamptz) = pgtype.Timestamptz{}
|
||||
*dest[18].(*int32) = 80 // CompactionRatio
|
||||
*dest[19].(*pgtype.UUID) = pgtype.UUID{} // CompactionModelID
|
||||
*dest[20].(*[]byte) = []byte(`{}`)
|
||||
*dest[21].(*pgtype.Timestamptz) = pgtype.Timestamptz{}
|
||||
*dest[22].(*pgtype.Timestamptz) = pgtype.Timestamptz{}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
@@ -79,6 +79,12 @@ func (s *Service) doCompaction(ctx context.Context, logID pgtype.UUID, sessionUU
|
||||
return nil
|
||||
}
|
||||
|
||||
toCompact := splitByRatio(messages, cfg.TotalInputTokens, cfg.Ratio)
|
||||
if len(toCompact) == 0 {
|
||||
s.completeLog(ctx, logID, "ok", "", "", nil, pgtype.UUID{})
|
||||
return nil
|
||||
}
|
||||
|
||||
priorLogs, err := s.queries.ListCompactionLogsBySession(ctx, sessionUUID)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -90,9 +96,9 @@ func (s *Service) doCompaction(ctx context.Context, logID pgtype.UUID, sessionUU
|
||||
}
|
||||
}
|
||||
|
||||
entries := make([]messageEntry, 0, len(messages))
|
||||
messageIDs := make([]pgtype.UUID, 0, len(messages))
|
||||
for _, m := range messages {
|
||||
entries := make([]messageEntry, 0, len(toCompact))
|
||||
messageIDs := make([]pgtype.UUID, 0, len(toCompact))
|
||||
for _, m := range toCompact {
|
||||
entries = append(entries, messageEntry{
|
||||
Role: m.Role,
|
||||
Content: extractTextContent(m.Content),
|
||||
@@ -258,3 +264,49 @@ func extractTextContent(content []byte) string {
|
||||
func joinTexts(parts []string) string {
|
||||
return strings.Join(parts, " ")
|
||||
}
|
||||
|
||||
// splitByRatio splits messages so that roughly the first ratio% (by token weight)
|
||||
// are returned for compaction, and the rest are kept as-is.
|
||||
// When ratio >= 100 or totalInputTokens <= 0, all messages are returned.
|
||||
func splitByRatio(messages []sqlc.ListUncompactedMessagesBySessionRow, totalInputTokens, ratio int) []sqlc.ListUncompactedMessagesBySessionRow {
|
||||
if ratio >= 100 || ratio <= 0 || totalInputTokens <= 0 || len(messages) == 0 {
|
||||
return messages
|
||||
}
|
||||
|
||||
keepTokens := totalInputTokens * (100 - ratio) / 100
|
||||
if keepTokens <= 0 {
|
||||
return messages
|
||||
}
|
||||
|
||||
accumulated := 0
|
||||
cutoff := len(messages)
|
||||
for i := len(messages) - 1; i >= 0; i-- {
|
||||
accumulated += estimateRowTokens(messages[i])
|
||||
if accumulated >= keepTokens {
|
||||
cutoff = i + 1
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if cutoff <= 0 {
|
||||
return nil
|
||||
}
|
||||
if cutoff >= len(messages) {
|
||||
return messages
|
||||
}
|
||||
return messages[:cutoff]
|
||||
}
|
||||
|
||||
type usagePayload struct {
|
||||
OutputTokens *int `json:"output_tokens"`
|
||||
}
|
||||
|
||||
func estimateRowTokens(m sqlc.ListUncompactedMessagesBySessionRow) int {
|
||||
if len(m.Usage) > 0 {
|
||||
var u usagePayload
|
||||
if json.Unmarshal(m.Usage, &u) == nil && u.OutputTokens != nil && *u.OutputTokens > 0 {
|
||||
return *u.OutputTokens
|
||||
}
|
||||
}
|
||||
return len(m.Content) / 4
|
||||
}
|
||||
|
||||
@@ -28,12 +28,14 @@ type ListLogsResponse struct {
|
||||
|
||||
// TriggerConfig holds the parameters needed to trigger a compaction.
|
||||
type TriggerConfig struct {
|
||||
BotID string
|
||||
SessionID string
|
||||
ModelID string
|
||||
ClientType string
|
||||
APIKey string //nolint:gosec // runtime credential, not a hardcoded secret
|
||||
CodexAccountID string
|
||||
BaseURL string
|
||||
HTTPClient *http.Client
|
||||
BotID string
|
||||
SessionID string
|
||||
ModelID string
|
||||
ClientType string
|
||||
APIKey string //nolint:gosec // runtime credential, not a hardcoded secret
|
||||
CodexAccountID string
|
||||
BaseURL string
|
||||
HTTPClient *http.Client
|
||||
Ratio int
|
||||
TotalInputTokens int
|
||||
}
|
||||
|
||||
@@ -31,9 +31,16 @@ func (r *Resolver) maybeCompact(ctx context.Context, req conversation.ChatReques
|
||||
modelID = rc.model.ID
|
||||
}
|
||||
|
||||
ratio := settings.CompactionRatio
|
||||
if ratio <= 0 || ratio > 100 {
|
||||
ratio = 80
|
||||
}
|
||||
|
||||
cfg := compaction.TriggerConfig{
|
||||
BotID: req.BotID,
|
||||
SessionID: req.SessionID,
|
||||
BotID: req.BotID,
|
||||
SessionID: req.SessionID,
|
||||
Ratio: ratio,
|
||||
TotalInputTokens: inputTokens,
|
||||
}
|
||||
|
||||
model, err := r.modelsService.GetByID(ctx, modelID)
|
||||
|
||||
@@ -94,7 +94,7 @@ func (q *Queries) DeleteBotByID(ctx context.Context, id pgtype.UUID) error {
|
||||
}
|
||||
|
||||
const getBotByID = `-- name: GetBotByID :one
|
||||
SELECT id, owner_user_id, display_name, avatar_url, timezone, is_active, status, language, reasoning_enabled, reasoning_effort, chat_model_id, search_provider_id, memory_provider_id, heartbeat_enabled, heartbeat_interval, heartbeat_prompt, compaction_enabled, compaction_threshold, compaction_model_id, metadata, created_at, updated_at
|
||||
SELECT id, owner_user_id, display_name, avatar_url, timezone, is_active, status, language, reasoning_enabled, reasoning_effort, chat_model_id, search_provider_id, memory_provider_id, heartbeat_enabled, heartbeat_interval, heartbeat_prompt, compaction_enabled, compaction_threshold, compaction_ratio, compaction_model_id, metadata, created_at, updated_at
|
||||
FROM bots
|
||||
WHERE id = $1
|
||||
`
|
||||
@@ -118,6 +118,7 @@ type GetBotByIDRow struct {
|
||||
HeartbeatPrompt string `json:"heartbeat_prompt"`
|
||||
CompactionEnabled bool `json:"compaction_enabled"`
|
||||
CompactionThreshold int32 `json:"compaction_threshold"`
|
||||
CompactionRatio int32 `json:"compaction_ratio"`
|
||||
CompactionModelID pgtype.UUID `json:"compaction_model_id"`
|
||||
Metadata []byte `json:"metadata"`
|
||||
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||
@@ -146,6 +147,7 @@ func (q *Queries) GetBotByID(ctx context.Context, id pgtype.UUID) (GetBotByIDRow
|
||||
&i.HeartbeatPrompt,
|
||||
&i.CompactionEnabled,
|
||||
&i.CompactionThreshold,
|
||||
&i.CompactionRatio,
|
||||
&i.CompactionModelID,
|
||||
&i.Metadata,
|
||||
&i.CreatedAt,
|
||||
|
||||
@@ -511,7 +511,7 @@ WITH updated AS (
|
||||
SET display_name = $1,
|
||||
updated_at = now()
|
||||
WHERE bots.id = $2
|
||||
RETURNING id, owner_user_id, display_name, avatar_url, timezone, is_active, status, language, reasoning_enabled, reasoning_effort, chat_model_id, search_provider_id, memory_provider_id, heartbeat_enabled, heartbeat_interval, heartbeat_prompt, heartbeat_model_id, compaction_enabled, compaction_threshold, compaction_model_id, title_model_id, tts_model_id, browser_context_id, metadata, created_at, updated_at, acl_default_effect
|
||||
RETURNING id, owner_user_id, display_name, avatar_url, timezone, is_active, status, language, reasoning_enabled, reasoning_effort, chat_model_id, search_provider_id, memory_provider_id, heartbeat_enabled, heartbeat_interval, heartbeat_prompt, heartbeat_model_id, compaction_enabled, compaction_threshold, compaction_ratio, compaction_model_id, title_model_id, tts_model_id, browser_context_id, metadata, created_at, updated_at, acl_default_effect
|
||||
)
|
||||
SELECT
|
||||
updated.id AS id,
|
||||
|
||||
@@ -28,6 +28,7 @@ type Bot struct {
|
||||
HeartbeatModelID pgtype.UUID `json:"heartbeat_model_id"`
|
||||
CompactionEnabled bool `json:"compaction_enabled"`
|
||||
CompactionThreshold int32 `json:"compaction_threshold"`
|
||||
CompactionRatio int32 `json:"compaction_ratio"`
|
||||
CompactionModelID pgtype.UUID `json:"compaction_model_id"`
|
||||
TitleModelID pgtype.UUID `json:"title_model_id"`
|
||||
TtsModelID pgtype.UUID `json:"tts_model_id"`
|
||||
|
||||
@@ -21,6 +21,7 @@ SET language = 'auto',
|
||||
heartbeat_prompt = '',
|
||||
compaction_enabled = false,
|
||||
compaction_threshold = 100000,
|
||||
compaction_ratio = 80,
|
||||
chat_model_id = NULL,
|
||||
heartbeat_model_id = NULL,
|
||||
compaction_model_id = NULL,
|
||||
@@ -49,6 +50,7 @@ SELECT
|
||||
bots.heartbeat_prompt,
|
||||
bots.compaction_enabled,
|
||||
bots.compaction_threshold,
|
||||
bots.compaction_ratio,
|
||||
chat_models.id AS chat_model_id,
|
||||
heartbeat_models.id AS heartbeat_model_id,
|
||||
compaction_models.id AS compaction_model_id,
|
||||
@@ -79,6 +81,7 @@ type GetSettingsByBotIDRow struct {
|
||||
HeartbeatPrompt string `json:"heartbeat_prompt"`
|
||||
CompactionEnabled bool `json:"compaction_enabled"`
|
||||
CompactionThreshold int32 `json:"compaction_threshold"`
|
||||
CompactionRatio int32 `json:"compaction_ratio"`
|
||||
ChatModelID pgtype.UUID `json:"chat_model_id"`
|
||||
HeartbeatModelID pgtype.UUID `json:"heartbeat_model_id"`
|
||||
CompactionModelID pgtype.UUID `json:"compaction_model_id"`
|
||||
@@ -102,6 +105,7 @@ func (q *Queries) GetSettingsByBotID(ctx context.Context, id pgtype.UUID) (GetSe
|
||||
&i.HeartbeatPrompt,
|
||||
&i.CompactionEnabled,
|
||||
&i.CompactionThreshold,
|
||||
&i.CompactionRatio,
|
||||
&i.ChatModelID,
|
||||
&i.HeartbeatModelID,
|
||||
&i.CompactionModelID,
|
||||
@@ -125,17 +129,18 @@ WITH updated AS (
|
||||
heartbeat_prompt = $6,
|
||||
compaction_enabled = $7,
|
||||
compaction_threshold = $8,
|
||||
chat_model_id = COALESCE($9::uuid, bots.chat_model_id),
|
||||
heartbeat_model_id = COALESCE($10::uuid, bots.heartbeat_model_id),
|
||||
compaction_model_id = COALESCE($11::uuid, bots.compaction_model_id),
|
||||
title_model_id = COALESCE($12::uuid, bots.title_model_id),
|
||||
search_provider_id = COALESCE($13::uuid, bots.search_provider_id),
|
||||
memory_provider_id = COALESCE($14::uuid, bots.memory_provider_id),
|
||||
tts_model_id = COALESCE($15::uuid, bots.tts_model_id),
|
||||
browser_context_id = COALESCE($16::uuid, bots.browser_context_id),
|
||||
compaction_ratio = $9,
|
||||
chat_model_id = COALESCE($10::uuid, bots.chat_model_id),
|
||||
heartbeat_model_id = COALESCE($11::uuid, bots.heartbeat_model_id),
|
||||
compaction_model_id = COALESCE($12::uuid, bots.compaction_model_id),
|
||||
title_model_id = COALESCE($13::uuid, bots.title_model_id),
|
||||
search_provider_id = COALESCE($14::uuid, bots.search_provider_id),
|
||||
memory_provider_id = COALESCE($15::uuid, bots.memory_provider_id),
|
||||
tts_model_id = COALESCE($16::uuid, bots.tts_model_id),
|
||||
browser_context_id = COALESCE($17::uuid, bots.browser_context_id),
|
||||
updated_at = now()
|
||||
WHERE bots.id = $17
|
||||
RETURNING bots.id, bots.language, bots.reasoning_enabled, bots.reasoning_effort, bots.heartbeat_enabled, bots.heartbeat_interval, bots.heartbeat_prompt, bots.compaction_enabled, bots.compaction_threshold, bots.chat_model_id, bots.heartbeat_model_id, bots.compaction_model_id, bots.title_model_id, bots.search_provider_id, bots.memory_provider_id, bots.tts_model_id, bots.browser_context_id
|
||||
WHERE bots.id = $18
|
||||
RETURNING bots.id, bots.language, bots.reasoning_enabled, bots.reasoning_effort, bots.heartbeat_enabled, bots.heartbeat_interval, bots.heartbeat_prompt, bots.compaction_enabled, bots.compaction_threshold, bots.compaction_ratio, bots.chat_model_id, bots.heartbeat_model_id, bots.compaction_model_id, bots.title_model_id, bots.search_provider_id, bots.memory_provider_id, bots.tts_model_id, bots.browser_context_id
|
||||
)
|
||||
SELECT
|
||||
updated.id AS bot_id,
|
||||
@@ -147,6 +152,7 @@ SELECT
|
||||
updated.heartbeat_prompt,
|
||||
updated.compaction_enabled,
|
||||
updated.compaction_threshold,
|
||||
updated.compaction_ratio,
|
||||
chat_models.id AS chat_model_id,
|
||||
heartbeat_models.id AS heartbeat_model_id,
|
||||
compaction_models.id AS compaction_model_id,
|
||||
@@ -175,6 +181,7 @@ type UpsertBotSettingsParams struct {
|
||||
HeartbeatPrompt string `json:"heartbeat_prompt"`
|
||||
CompactionEnabled bool `json:"compaction_enabled"`
|
||||
CompactionThreshold int32 `json:"compaction_threshold"`
|
||||
CompactionRatio int32 `json:"compaction_ratio"`
|
||||
ChatModelID pgtype.UUID `json:"chat_model_id"`
|
||||
HeartbeatModelID pgtype.UUID `json:"heartbeat_model_id"`
|
||||
CompactionModelID pgtype.UUID `json:"compaction_model_id"`
|
||||
@@ -196,6 +203,7 @@ type UpsertBotSettingsRow struct {
|
||||
HeartbeatPrompt string `json:"heartbeat_prompt"`
|
||||
CompactionEnabled bool `json:"compaction_enabled"`
|
||||
CompactionThreshold int32 `json:"compaction_threshold"`
|
||||
CompactionRatio int32 `json:"compaction_ratio"`
|
||||
ChatModelID pgtype.UUID `json:"chat_model_id"`
|
||||
HeartbeatModelID pgtype.UUID `json:"heartbeat_model_id"`
|
||||
CompactionModelID pgtype.UUID `json:"compaction_model_id"`
|
||||
@@ -216,6 +224,7 @@ func (q *Queries) UpsertBotSettings(ctx context.Context, arg UpsertBotSettingsPa
|
||||
arg.HeartbeatPrompt,
|
||||
arg.CompactionEnabled,
|
||||
arg.CompactionThreshold,
|
||||
arg.CompactionRatio,
|
||||
arg.ChatModelID,
|
||||
arg.HeartbeatModelID,
|
||||
arg.CompactionModelID,
|
||||
@@ -237,6 +246,7 @@ func (q *Queries) UpsertBotSettings(ctx context.Context, arg UpsertBotSettingsPa
|
||||
&i.HeartbeatPrompt,
|
||||
&i.CompactionEnabled,
|
||||
&i.CompactionThreshold,
|
||||
&i.CompactionRatio,
|
||||
&i.ChatModelID,
|
||||
&i.HeartbeatModelID,
|
||||
&i.CompactionModelID,
|
||||
|
||||
@@ -69,7 +69,7 @@ func (s *Service) UpsertBot(ctx context.Context, botID string, req UpsertRequest
|
||||
if err != nil {
|
||||
return Settings{}, err
|
||||
}
|
||||
current := normalizeBotSetting(botRow.Language, aclDefaultEffect, botRow.ReasoningEnabled, botRow.ReasoningEffort, botRow.HeartbeatEnabled, botRow.HeartbeatInterval, botRow.CompactionEnabled, botRow.CompactionThreshold)
|
||||
current := normalizeBotSetting(botRow.Language, aclDefaultEffect, botRow.ReasoningEnabled, botRow.ReasoningEffort, botRow.HeartbeatEnabled, botRow.HeartbeatInterval, botRow.CompactionEnabled, botRow.CompactionThreshold, botRow.CompactionRatio)
|
||||
if strings.TrimSpace(req.Language) != "" {
|
||||
current.Language = strings.TrimSpace(req.Language)
|
||||
}
|
||||
@@ -94,6 +94,9 @@ func (s *Service) UpsertBot(ctx context.Context, botID string, req UpsertRequest
|
||||
if req.CompactionThreshold != nil && *req.CompactionThreshold >= 0 {
|
||||
current.CompactionThreshold = *req.CompactionThreshold
|
||||
}
|
||||
if req.CompactionRatio != nil && *req.CompactionRatio >= 1 && *req.CompactionRatio <= 100 {
|
||||
current.CompactionRatio = *req.CompactionRatio
|
||||
}
|
||||
chatModelUUID := pgtype.UUID{}
|
||||
if value := strings.TrimSpace(req.ChatModelID); value != "" {
|
||||
modelID, err := s.resolveModelUUID(ctx, value)
|
||||
@@ -170,6 +173,7 @@ func (s *Service) UpsertBot(ctx context.Context, botID string, req UpsertRequest
|
||||
HeartbeatPrompt: "",
|
||||
CompactionEnabled: current.CompactionEnabled,
|
||||
CompactionThreshold: int32(current.CompactionThreshold), //nolint:gosec // bounded by non-negative setter above
|
||||
CompactionRatio: int32(current.CompactionRatio), //nolint:gosec // bounded 1-100 above
|
||||
ChatModelID: chatModelUUID,
|
||||
HeartbeatModelID: heartbeatModelUUID,
|
||||
CompactionModelID: compactionModelUUID,
|
||||
@@ -209,7 +213,7 @@ func (s *Service) Delete(ctx context.Context, botID string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func normalizeBotSetting(language string, aclDefaultEffect string, reasoningEnabled bool, reasoningEffort string, heartbeatEnabled bool, heartbeatInterval int32, compactionEnabled bool, compactionThreshold int32) Settings {
|
||||
func normalizeBotSetting(language string, aclDefaultEffect string, reasoningEnabled bool, reasoningEffort string, heartbeatEnabled bool, heartbeatInterval int32, compactionEnabled bool, compactionThreshold int32, compactionRatio int32) Settings {
|
||||
settings := Settings{
|
||||
Language: strings.TrimSpace(language),
|
||||
AclDefaultEffect: strings.TrimSpace(aclDefaultEffect),
|
||||
@@ -219,6 +223,7 @@ func normalizeBotSetting(language string, aclDefaultEffect string, reasoningEnab
|
||||
HeartbeatInterval: int(heartbeatInterval),
|
||||
CompactionEnabled: compactionEnabled,
|
||||
CompactionThreshold: int(compactionThreshold),
|
||||
CompactionRatio: int(compactionRatio),
|
||||
}
|
||||
if settings.Language == "" {
|
||||
settings.Language = DefaultLanguage
|
||||
@@ -235,6 +240,9 @@ func normalizeBotSetting(language string, aclDefaultEffect string, reasoningEnab
|
||||
if settings.CompactionThreshold < 0 {
|
||||
settings.CompactionThreshold = 0
|
||||
}
|
||||
if settings.CompactionRatio < 1 || settings.CompactionRatio > 100 {
|
||||
settings.CompactionRatio = 80
|
||||
}
|
||||
return settings
|
||||
}
|
||||
|
||||
@@ -256,6 +264,7 @@ func normalizeBotSettingsReadRow(row sqlc.GetSettingsByBotIDRow) Settings {
|
||||
row.HeartbeatInterval,
|
||||
row.CompactionEnabled,
|
||||
row.CompactionThreshold,
|
||||
row.CompactionRatio,
|
||||
row.ChatModelID,
|
||||
row.HeartbeatModelID,
|
||||
row.CompactionModelID,
|
||||
@@ -276,6 +285,7 @@ func normalizeBotSettingsWriteRow(row sqlc.UpsertBotSettingsRow) Settings {
|
||||
row.HeartbeatInterval,
|
||||
row.CompactionEnabled,
|
||||
row.CompactionThreshold,
|
||||
row.CompactionRatio,
|
||||
row.ChatModelID,
|
||||
row.HeartbeatModelID,
|
||||
row.CompactionModelID,
|
||||
@@ -295,6 +305,7 @@ func normalizeBotSettingsFields(
|
||||
heartbeatInterval int32,
|
||||
compactionEnabled bool,
|
||||
compactionThreshold int32,
|
||||
compactionRatio int32,
|
||||
chatModelID pgtype.UUID,
|
||||
heartbeatModelID pgtype.UUID,
|
||||
compactionModelID pgtype.UUID,
|
||||
@@ -304,7 +315,7 @@ func normalizeBotSettingsFields(
|
||||
ttsModelID pgtype.UUID,
|
||||
browserContextID pgtype.UUID,
|
||||
) Settings {
|
||||
settings := normalizeBotSetting(language, "", reasoningEnabled, reasoningEffort, heartbeatEnabled, heartbeatInterval, compactionEnabled, compactionThreshold)
|
||||
settings := normalizeBotSetting(language, "", reasoningEnabled, reasoningEffort, heartbeatEnabled, heartbeatInterval, compactionEnabled, compactionThreshold, compactionRatio)
|
||||
if chatModelID.Valid {
|
||||
settings.ChatModelID = uuid.UUID(chatModelID.Bytes).String()
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ type Settings struct {
|
||||
TitleModelID string `json:"title_model_id"`
|
||||
CompactionEnabled bool `json:"compaction_enabled"`
|
||||
CompactionThreshold int `json:"compaction_threshold"`
|
||||
CompactionRatio int `json:"compaction_ratio"`
|
||||
CompactionModelID string `json:"compaction_model_id,omitempty"`
|
||||
}
|
||||
|
||||
@@ -41,5 +42,6 @@ type UpsertRequest struct {
|
||||
TitleModelID string `json:"title_model_id,omitempty"`
|
||||
CompactionEnabled *bool `json:"compaction_enabled,omitempty"`
|
||||
CompactionThreshold *int `json:"compaction_threshold,omitempty"`
|
||||
CompactionRatio *int `json:"compaction_ratio,omitempty"`
|
||||
CompactionModelID *string `json:"compaction_model_id,omitempty"`
|
||||
}
|
||||
|
||||
@@ -1447,6 +1447,7 @@ export type SettingsSettings = {
|
||||
chat_model_id?: string;
|
||||
compaction_enabled?: boolean;
|
||||
compaction_model_id?: string;
|
||||
compaction_ratio?: number;
|
||||
compaction_threshold?: number;
|
||||
heartbeat_enabled?: boolean;
|
||||
heartbeat_interval?: number;
|
||||
@@ -1466,6 +1467,7 @@ export type SettingsUpsertRequest = {
|
||||
chat_model_id?: string;
|
||||
compaction_enabled?: boolean;
|
||||
compaction_model_id?: string;
|
||||
compaction_ratio?: number;
|
||||
compaction_threshold?: number;
|
||||
heartbeat_enabled?: boolean;
|
||||
heartbeat_interval?: number;
|
||||
|
||||
@@ -12401,6 +12401,9 @@ const docTemplate = `{
|
||||
"compaction_model_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"compaction_ratio": {
|
||||
"type": "integer"
|
||||
},
|
||||
"compaction_threshold": {
|
||||
"type": "integer"
|
||||
},
|
||||
@@ -12454,6 +12457,9 @@ const docTemplate = `{
|
||||
"compaction_model_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"compaction_ratio": {
|
||||
"type": "integer"
|
||||
},
|
||||
"compaction_threshold": {
|
||||
"type": "integer"
|
||||
},
|
||||
|
||||
@@ -12392,6 +12392,9 @@
|
||||
"compaction_model_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"compaction_ratio": {
|
||||
"type": "integer"
|
||||
},
|
||||
"compaction_threshold": {
|
||||
"type": "integer"
|
||||
},
|
||||
@@ -12445,6 +12448,9 @@
|
||||
"compaction_model_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"compaction_ratio": {
|
||||
"type": "integer"
|
||||
},
|
||||
"compaction_threshold": {
|
||||
"type": "integer"
|
||||
},
|
||||
|
||||
@@ -2398,6 +2398,8 @@ definitions:
|
||||
type: boolean
|
||||
compaction_model_id:
|
||||
type: string
|
||||
compaction_ratio:
|
||||
type: integer
|
||||
compaction_threshold:
|
||||
type: integer
|
||||
heartbeat_enabled:
|
||||
@@ -2433,6 +2435,8 @@ definitions:
|
||||
type: boolean
|
||||
compaction_model_id:
|
||||
type: string
|
||||
compaction_ratio:
|
||||
type: integer
|
||||
compaction_threshold:
|
||||
type: integer
|
||||
heartbeat_enabled:
|
||||
|
||||
Reference in New Issue
Block a user