mirror of
https://github.com/memohai/Memoh.git
synced 2026-04-25 07:00:48 +09:00
473d559042
Introduce a new `show_tool_calls_in_im` bot setting plus a full overhaul of how tool calls are surfaced in IM channels: - Add per-bot setting + migration (0072) and expose through settings API / handlers / frontend SDK. - Introduce a `toolCallDroppingStream` wrapper that filters tool_call_* events when the setting is off, keeping the rest of the stream intact. - Add a shared `ToolCallPresentation` model (Header / Body blocks / Footer) with plain and Markdown renderers, and a per-tool formatter registry that produces rich output (e.g. `web_search` link lists, `list` directory previews, `exec` stdout/stderr tails) instead of raw JSON dumps. - High-capability adapters (Telegram, Feishu, Matrix, Slack, Discord) now flush pre-text and then send ONE tool-call message per call, editing it in-place from `running` to `completed` / `failed`; mapping from callID to platform message ID is tracked per stream, with a fallback to a new message if the edit fails. Low-capability adapters (WeCom, QQ, DingTalk) keep posting a single final message, but now benefit from the same rich per-tool formatting. - Suppress the early duplicate `EventToolCallStart` (from `sdk.ToolInputStartPart`) so that the SDK's final `StreamToolCallPart` remains the single source of truth for tool call start, preventing duplicated "running" bubbles in IM. - Stop auto-populating `InputSummary` / `ResultSummary` after a per-tool formatter runs, which previously leaked the raw JSON result as a fallback footer underneath the formatted body. Add regression tests for the formatters, the Markdown renderer, the edit-in-place flow on Telegram/Matrix, and the JSON-leak guard on `list`.
314 lines
12 KiB
Go
314 lines
12 KiB
Go
// Code generated by sqlc. DO NOT EDIT.
|
|
// versions:
|
|
// sqlc v1.30.0
|
|
// source: settings.sql
|
|
|
|
package sqlc
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/jackc/pgx/v5/pgtype"
|
|
)
|
|
|
|
const deleteSettingsByBotID = `-- name: DeleteSettingsByBotID :exec
|
|
UPDATE bots
|
|
SET language = 'auto',
|
|
reasoning_enabled = false,
|
|
reasoning_effort = 'medium',
|
|
heartbeat_enabled = false,
|
|
heartbeat_interval = 30,
|
|
heartbeat_prompt = '',
|
|
compaction_enabled = false,
|
|
compaction_threshold = 100000,
|
|
compaction_ratio = 80,
|
|
chat_model_id = NULL,
|
|
heartbeat_model_id = NULL,
|
|
compaction_model_id = NULL,
|
|
title_model_id = NULL,
|
|
image_model_id = NULL,
|
|
search_provider_id = NULL,
|
|
memory_provider_id = NULL,
|
|
tts_model_id = NULL,
|
|
transcription_model_id = NULL,
|
|
browser_context_id = NULL,
|
|
persist_full_tool_results = false,
|
|
show_tool_calls_in_im = false,
|
|
updated_at = now()
|
|
WHERE id = $1
|
|
`
|
|
|
|
func (q *Queries) DeleteSettingsByBotID(ctx context.Context, id pgtype.UUID) error {
|
|
_, err := q.db.Exec(ctx, deleteSettingsByBotID, id)
|
|
return err
|
|
}
|
|
|
|
const getSettingsByBotID = `-- name: GetSettingsByBotID :one
|
|
SELECT
|
|
bots.id AS bot_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.timezone,
|
|
chat_models.id AS chat_model_id,
|
|
heartbeat_models.id AS heartbeat_model_id,
|
|
compaction_models.id AS compaction_model_id,
|
|
title_models.id AS title_model_id,
|
|
search_providers.id AS search_provider_id,
|
|
memory_providers.id AS memory_provider_id,
|
|
image_models.id AS image_model_id,
|
|
tts_models.id AS tts_model_id,
|
|
transcription_models.id AS transcription_model_id,
|
|
browser_contexts.id AS browser_context_id,
|
|
bots.persist_full_tool_results,
|
|
bots.show_tool_calls_in_im
|
|
FROM bots
|
|
LEFT JOIN models AS chat_models ON chat_models.id = bots.chat_model_id
|
|
LEFT JOIN models AS heartbeat_models ON heartbeat_models.id = bots.heartbeat_model_id
|
|
LEFT JOIN models AS compaction_models ON compaction_models.id = bots.compaction_model_id
|
|
LEFT JOIN models AS title_models ON title_models.id = bots.title_model_id
|
|
LEFT JOIN models AS image_models ON image_models.id = bots.image_model_id
|
|
LEFT JOIN search_providers ON search_providers.id = bots.search_provider_id
|
|
LEFT JOIN memory_providers ON memory_providers.id = bots.memory_provider_id
|
|
LEFT JOIN models AS tts_models ON tts_models.id = bots.tts_model_id
|
|
LEFT JOIN models AS transcription_models ON transcription_models.id = bots.transcription_model_id
|
|
LEFT JOIN browser_contexts ON browser_contexts.id = bots.browser_context_id
|
|
WHERE bots.id = $1
|
|
`
|
|
|
|
type GetSettingsByBotIDRow struct {
|
|
BotID pgtype.UUID `json:"bot_id"`
|
|
Language string `json:"language"`
|
|
ReasoningEnabled bool `json:"reasoning_enabled"`
|
|
ReasoningEffort string `json:"reasoning_effort"`
|
|
HeartbeatEnabled bool `json:"heartbeat_enabled"`
|
|
HeartbeatInterval int32 `json:"heartbeat_interval"`
|
|
HeartbeatPrompt string `json:"heartbeat_prompt"`
|
|
CompactionEnabled bool `json:"compaction_enabled"`
|
|
CompactionThreshold int32 `json:"compaction_threshold"`
|
|
CompactionRatio int32 `json:"compaction_ratio"`
|
|
Timezone pgtype.Text `json:"timezone"`
|
|
ChatModelID pgtype.UUID `json:"chat_model_id"`
|
|
HeartbeatModelID pgtype.UUID `json:"heartbeat_model_id"`
|
|
CompactionModelID pgtype.UUID `json:"compaction_model_id"`
|
|
TitleModelID pgtype.UUID `json:"title_model_id"`
|
|
SearchProviderID pgtype.UUID `json:"search_provider_id"`
|
|
MemoryProviderID pgtype.UUID `json:"memory_provider_id"`
|
|
ImageModelID pgtype.UUID `json:"image_model_id"`
|
|
TtsModelID pgtype.UUID `json:"tts_model_id"`
|
|
TranscriptionModelID pgtype.UUID `json:"transcription_model_id"`
|
|
BrowserContextID pgtype.UUID `json:"browser_context_id"`
|
|
PersistFullToolResults bool `json:"persist_full_tool_results"`
|
|
ShowToolCallsInIm bool `json:"show_tool_calls_in_im"`
|
|
}
|
|
|
|
func (q *Queries) GetSettingsByBotID(ctx context.Context, id pgtype.UUID) (GetSettingsByBotIDRow, error) {
|
|
row := q.db.QueryRow(ctx, getSettingsByBotID, id)
|
|
var i GetSettingsByBotIDRow
|
|
err := row.Scan(
|
|
&i.BotID,
|
|
&i.Language,
|
|
&i.ReasoningEnabled,
|
|
&i.ReasoningEffort,
|
|
&i.HeartbeatEnabled,
|
|
&i.HeartbeatInterval,
|
|
&i.HeartbeatPrompt,
|
|
&i.CompactionEnabled,
|
|
&i.CompactionThreshold,
|
|
&i.CompactionRatio,
|
|
&i.Timezone,
|
|
&i.ChatModelID,
|
|
&i.HeartbeatModelID,
|
|
&i.CompactionModelID,
|
|
&i.TitleModelID,
|
|
&i.SearchProviderID,
|
|
&i.MemoryProviderID,
|
|
&i.ImageModelID,
|
|
&i.TtsModelID,
|
|
&i.TranscriptionModelID,
|
|
&i.BrowserContextID,
|
|
&i.PersistFullToolResults,
|
|
&i.ShowToolCallsInIm,
|
|
)
|
|
return i, err
|
|
}
|
|
|
|
const upsertBotSettings = `-- name: UpsertBotSettings :one
|
|
WITH updated AS (
|
|
UPDATE bots
|
|
SET language = $1,
|
|
reasoning_enabled = $2,
|
|
reasoning_effort = $3,
|
|
heartbeat_enabled = $4,
|
|
heartbeat_interval = $5,
|
|
heartbeat_prompt = $6,
|
|
compaction_enabled = $7,
|
|
compaction_threshold = $8,
|
|
compaction_ratio = $9,
|
|
timezone = COALESCE($10::text, bots.timezone),
|
|
chat_model_id = COALESCE($11::uuid, bots.chat_model_id),
|
|
heartbeat_model_id = COALESCE($12::uuid, bots.heartbeat_model_id),
|
|
compaction_model_id = COALESCE($13::uuid, bots.compaction_model_id),
|
|
title_model_id = COALESCE($14::uuid, bots.title_model_id),
|
|
search_provider_id = COALESCE($15::uuid, bots.search_provider_id),
|
|
memory_provider_id = COALESCE($16::uuid, bots.memory_provider_id),
|
|
image_model_id = COALESCE($17::uuid, bots.image_model_id),
|
|
tts_model_id = COALESCE($18::uuid, bots.tts_model_id),
|
|
transcription_model_id = COALESCE($19::uuid, bots.transcription_model_id),
|
|
browser_context_id = COALESCE($20::uuid, bots.browser_context_id),
|
|
persist_full_tool_results = $21,
|
|
show_tool_calls_in_im = $22,
|
|
updated_at = now()
|
|
WHERE bots.id = $23
|
|
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.timezone, bots.chat_model_id, bots.heartbeat_model_id, bots.compaction_model_id, bots.title_model_id, bots.image_model_id, bots.search_provider_id, bots.memory_provider_id, bots.tts_model_id, bots.transcription_model_id, bots.browser_context_id, bots.persist_full_tool_results, bots.show_tool_calls_in_im
|
|
)
|
|
SELECT
|
|
updated.id AS bot_id,
|
|
updated.language,
|
|
updated.reasoning_enabled,
|
|
updated.reasoning_effort,
|
|
updated.heartbeat_enabled,
|
|
updated.heartbeat_interval,
|
|
updated.heartbeat_prompt,
|
|
updated.compaction_enabled,
|
|
updated.compaction_threshold,
|
|
updated.compaction_ratio,
|
|
updated.timezone,
|
|
chat_models.id AS chat_model_id,
|
|
heartbeat_models.id AS heartbeat_model_id,
|
|
compaction_models.id AS compaction_model_id,
|
|
title_models.id AS title_model_id,
|
|
search_providers.id AS search_provider_id,
|
|
memory_providers.id AS memory_provider_id,
|
|
image_models.id AS image_model_id,
|
|
tts_models.id AS tts_model_id,
|
|
transcription_models.id AS transcription_model_id,
|
|
browser_contexts.id AS browser_context_id,
|
|
updated.persist_full_tool_results,
|
|
updated.show_tool_calls_in_im
|
|
FROM updated
|
|
LEFT JOIN models AS chat_models ON chat_models.id = updated.chat_model_id
|
|
LEFT JOIN models AS heartbeat_models ON heartbeat_models.id = updated.heartbeat_model_id
|
|
LEFT JOIN models AS compaction_models ON compaction_models.id = updated.compaction_model_id
|
|
LEFT JOIN models AS title_models ON title_models.id = updated.title_model_id
|
|
LEFT JOIN models AS image_models ON image_models.id = updated.image_model_id
|
|
LEFT JOIN search_providers ON search_providers.id = updated.search_provider_id
|
|
LEFT JOIN memory_providers ON memory_providers.id = updated.memory_provider_id
|
|
LEFT JOIN models AS tts_models ON tts_models.id = updated.tts_model_id
|
|
LEFT JOIN models AS transcription_models ON transcription_models.id = updated.transcription_model_id
|
|
LEFT JOIN browser_contexts ON browser_contexts.id = updated.browser_context_id
|
|
`
|
|
|
|
type UpsertBotSettingsParams struct {
|
|
Language string `json:"language"`
|
|
ReasoningEnabled bool `json:"reasoning_enabled"`
|
|
ReasoningEffort string `json:"reasoning_effort"`
|
|
HeartbeatEnabled bool `json:"heartbeat_enabled"`
|
|
HeartbeatInterval int32 `json:"heartbeat_interval"`
|
|
HeartbeatPrompt string `json:"heartbeat_prompt"`
|
|
CompactionEnabled bool `json:"compaction_enabled"`
|
|
CompactionThreshold int32 `json:"compaction_threshold"`
|
|
CompactionRatio int32 `json:"compaction_ratio"`
|
|
Timezone pgtype.Text `json:"timezone"`
|
|
ChatModelID pgtype.UUID `json:"chat_model_id"`
|
|
HeartbeatModelID pgtype.UUID `json:"heartbeat_model_id"`
|
|
CompactionModelID pgtype.UUID `json:"compaction_model_id"`
|
|
TitleModelID pgtype.UUID `json:"title_model_id"`
|
|
SearchProviderID pgtype.UUID `json:"search_provider_id"`
|
|
MemoryProviderID pgtype.UUID `json:"memory_provider_id"`
|
|
ImageModelID pgtype.UUID `json:"image_model_id"`
|
|
TtsModelID pgtype.UUID `json:"tts_model_id"`
|
|
TranscriptionModelID pgtype.UUID `json:"transcription_model_id"`
|
|
BrowserContextID pgtype.UUID `json:"browser_context_id"`
|
|
PersistFullToolResults bool `json:"persist_full_tool_results"`
|
|
ShowToolCallsInIm bool `json:"show_tool_calls_in_im"`
|
|
ID pgtype.UUID `json:"id"`
|
|
}
|
|
|
|
type UpsertBotSettingsRow struct {
|
|
BotID pgtype.UUID `json:"bot_id"`
|
|
Language string `json:"language"`
|
|
ReasoningEnabled bool `json:"reasoning_enabled"`
|
|
ReasoningEffort string `json:"reasoning_effort"`
|
|
HeartbeatEnabled bool `json:"heartbeat_enabled"`
|
|
HeartbeatInterval int32 `json:"heartbeat_interval"`
|
|
HeartbeatPrompt string `json:"heartbeat_prompt"`
|
|
CompactionEnabled bool `json:"compaction_enabled"`
|
|
CompactionThreshold int32 `json:"compaction_threshold"`
|
|
CompactionRatio int32 `json:"compaction_ratio"`
|
|
Timezone pgtype.Text `json:"timezone"`
|
|
ChatModelID pgtype.UUID `json:"chat_model_id"`
|
|
HeartbeatModelID pgtype.UUID `json:"heartbeat_model_id"`
|
|
CompactionModelID pgtype.UUID `json:"compaction_model_id"`
|
|
TitleModelID pgtype.UUID `json:"title_model_id"`
|
|
SearchProviderID pgtype.UUID `json:"search_provider_id"`
|
|
MemoryProviderID pgtype.UUID `json:"memory_provider_id"`
|
|
ImageModelID pgtype.UUID `json:"image_model_id"`
|
|
TtsModelID pgtype.UUID `json:"tts_model_id"`
|
|
TranscriptionModelID pgtype.UUID `json:"transcription_model_id"`
|
|
BrowserContextID pgtype.UUID `json:"browser_context_id"`
|
|
PersistFullToolResults bool `json:"persist_full_tool_results"`
|
|
ShowToolCallsInIm bool `json:"show_tool_calls_in_im"`
|
|
}
|
|
|
|
func (q *Queries) UpsertBotSettings(ctx context.Context, arg UpsertBotSettingsParams) (UpsertBotSettingsRow, error) {
|
|
row := q.db.QueryRow(ctx, upsertBotSettings,
|
|
arg.Language,
|
|
arg.ReasoningEnabled,
|
|
arg.ReasoningEffort,
|
|
arg.HeartbeatEnabled,
|
|
arg.HeartbeatInterval,
|
|
arg.HeartbeatPrompt,
|
|
arg.CompactionEnabled,
|
|
arg.CompactionThreshold,
|
|
arg.CompactionRatio,
|
|
arg.Timezone,
|
|
arg.ChatModelID,
|
|
arg.HeartbeatModelID,
|
|
arg.CompactionModelID,
|
|
arg.TitleModelID,
|
|
arg.SearchProviderID,
|
|
arg.MemoryProviderID,
|
|
arg.ImageModelID,
|
|
arg.TtsModelID,
|
|
arg.TranscriptionModelID,
|
|
arg.BrowserContextID,
|
|
arg.PersistFullToolResults,
|
|
arg.ShowToolCallsInIm,
|
|
arg.ID,
|
|
)
|
|
var i UpsertBotSettingsRow
|
|
err := row.Scan(
|
|
&i.BotID,
|
|
&i.Language,
|
|
&i.ReasoningEnabled,
|
|
&i.ReasoningEffort,
|
|
&i.HeartbeatEnabled,
|
|
&i.HeartbeatInterval,
|
|
&i.HeartbeatPrompt,
|
|
&i.CompactionEnabled,
|
|
&i.CompactionThreshold,
|
|
&i.CompactionRatio,
|
|
&i.Timezone,
|
|
&i.ChatModelID,
|
|
&i.HeartbeatModelID,
|
|
&i.CompactionModelID,
|
|
&i.TitleModelID,
|
|
&i.SearchProviderID,
|
|
&i.MemoryProviderID,
|
|
&i.ImageModelID,
|
|
&i.TtsModelID,
|
|
&i.TranscriptionModelID,
|
|
&i.BrowserContextID,
|
|
&i.PersistFullToolResults,
|
|
&i.ShowToolCallsInIm,
|
|
)
|
|
return i, err
|
|
}
|