mirror of
https://github.com/memohai/Memoh.git
synced 2026-04-25 07:00:48 +09:00
feat(channel): structured tool-call IM display with edit-in-place
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`.
This commit is contained in:
@@ -179,6 +179,7 @@ CREATE TABLE IF NOT EXISTS bots (
|
||||
transcription_model_id UUID REFERENCES models(id) ON DELETE SET NULL,
|
||||
browser_context_id UUID REFERENCES browser_contexts(id) ON DELETE SET NULL,
|
||||
persist_full_tool_results BOOLEAN NOT NULL DEFAULT false,
|
||||
show_tool_calls_in_im BOOLEAN NOT NULL DEFAULT false,
|
||||
metadata JSONB NOT NULL DEFAULT '{}'::jsonb,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
-- 0072_add_show_tool_calls_in_im (down)
|
||||
-- NOTE: After rolling back this migration, re-run `sqlc generate` to update the
|
||||
-- generated Go code in internal/db/sqlc/.
|
||||
|
||||
ALTER TABLE bots DROP COLUMN IF EXISTS show_tool_calls_in_im;
|
||||
@@ -0,0 +1,5 @@
|
||||
-- 0072_add_show_tool_calls_in_im
|
||||
-- Add show_tool_calls_in_im column to bots table to control whether tool call
|
||||
-- status messages are surfaced in IM channels.
|
||||
|
||||
ALTER TABLE bots ADD COLUMN IF NOT EXISTS show_tool_calls_in_im BOOLEAN NOT NULL DEFAULT false;
|
||||
@@ -21,7 +21,8 @@ SELECT
|
||||
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.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
|
||||
@@ -59,9 +60,10 @@ WITH updated AS (
|
||||
transcription_model_id = COALESCE(sqlc.narg(transcription_model_id)::uuid, bots.transcription_model_id),
|
||||
browser_context_id = COALESCE(sqlc.narg(browser_context_id)::uuid, bots.browser_context_id),
|
||||
persist_full_tool_results = sqlc.arg(persist_full_tool_results),
|
||||
show_tool_calls_in_im = sqlc.arg(show_tool_calls_in_im),
|
||||
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.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
|
||||
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,
|
||||
@@ -85,7 +87,8 @@ SELECT
|
||||
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.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
|
||||
@@ -120,5 +123,6 @@ SET language = 'auto',
|
||||
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;
|
||||
|
||||
Reference in New Issue
Block a user