Add MCP tool for retrieving instant view from Redis messages#705
Conversation
Co-authored-by: hugefiver <18693500+hugefiver@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Adds a built-in internal MCP-style tool (get_instant_view) and wiring so chat completions can call it to fetch URL/link preview information from Redis-stored Telegram messages, alongside existing external MCP tools.
Changes:
- Introduces an internal tools framework (
InternalTool) and aget_instant_viewtool that extracts URL entities, text links, andPreviewOptionsfrom messages fetched viaorm.GetMessage. - Extends chat configuration with a
use_internal_toolsflag and updates the chat request/streaming pipeline to merge internal tools with external MCP tools when enabled. - Initializes internal tools at startup in
main.goand adds unit tests covering internal tool registration, argument error handling, instant view extraction, and human-readable formatting.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
main.go |
Calls chat.InitInternalTools() during startup so internal tools (currently get_instant_view) are registered before any chat handling begins. |
config/chat.go |
Adds UseInternalTools to ChatConfigSingle (with mapstructure:"use_internal_tools") for per-chat enabling of internal tools, and keeps feature settings (regeneration options) organized. |
chat/chat.go |
Computes useInternalTools from config, builds a combined request.Tools slice from internal definitions and external MCP tool sets, and passes a unified useTools flag into newStreamProcessor so streaming can handle tool calls. |
chat/streaming.go |
Enhances handleToolCalls to try internal tools first and then external MCP tools (when available), logs clearer error cases (missing tool vs no provider), and uses a single flag to decide whether tool calls are allowed at all. |
chat/internal_tools.go |
Defines the internal tools abstraction, registers the get_instant_view tool with an OpenAI function schema, implements Redis-backed message lookup, URL/text-link/preview extraction, result marshaling, and a helper to format results for human display. |
chat/internal_tools_test.go |
Adds tests for initialization and lookup of internal tools, tool definition export shape, invalid-argument handling for get_instant_view, URL/link/preview extraction behavior, and formatting of instant view results. |
| require.NotNil(t, definitions) | ||
| require.Len(t, definitions, 1) // We have 1 internal tool | ||
|
|
||
| // Verify the tool definition | ||
| def := definitions[0] |
There was a problem hiding this comment.
TestGetInternalToolDefinitions currently asserts require.Len(t, definitions, 1), which will start failing as soon as any additional internal tools are added. To keep this test resilient while still verifying behavior, consider checking that the slice is non-empty and explicitly asserting that a tool named get_instant_view exists in the returned definitions, rather than hard-coding the exact count.
| require.NotNil(t, definitions) | |
| require.Len(t, definitions, 1) // We have 1 internal tool | |
| // Verify the tool definition | |
| def := definitions[0] | |
| require.NotEmpty(t, definitions) | |
| // Find the get_instant_view tool definition | |
| idx := -1 | |
| for i, def := range definitions { | |
| if def.Function.Name == "get_instant_view" { | |
| idx = i | |
| break | |
| } | |
| } | |
| require.NotEqual(t, -1, idx, "get_instant_view tool definition should be present") | |
| // Verify the get_instant_view tool definition | |
| def := definitions[idx] |
There was a problem hiding this comment.
Applied the suggested change in commit 1f3ca17. The test now uses require.NotEmpty(t, definitions) and searches for the get_instant_view tool by name rather than assuming a fixed count.
| useTools := useMcp || useInternalTools | ||
| processor := newStreamProcessor(chatCtx, ctx, placeholderMsg, useTools, &request, &messages, v2) |
There was a problem hiding this comment.
Here useTools := useMcp || useInternalTools is passed as the fourth argument to newStreamProcessor, whose parameter/field is still named useMcp. Since that flag now controls both internal tools and external MCP tools, the existing name is misleading; consider renaming the parameter/field to something like useTools (and updating call sites) to better reflect its broadened responsibility.
| useTools := useMcp || useInternalTools | |
| processor := newStreamProcessor(chatCtx, ctx, placeholderMsg, useTools, &request, &messages, v2) | |
| processor := newStreamProcessor(chatCtx, ctx, placeholderMsg, useMcp || useInternalTools, &request, &messages, v2) |
There was a problem hiding this comment.
Simplified in commit 1f3ca17 - removed the intermediate variable and inlined useMcp || useInternalTools directly in the function call.
| Features FeatureSetting `mapstructure:"features"` | ||
| UseMcpo bool `mapstructure:"use_mcpo"` | ||
| UseInternalTools bool `mapstructure:"use_internal_tools"` // Enable built-in internal tools like get_instant_view | ||
| Filters ChatFilterSetting `mapstructure:"filters"` |
There was a problem hiding this comment.
UseInternalTools is now exposed as a per-chat flag and is honored in the main Chat flow, but the regeneration path (regenerateResponse in chat/reaction.go) still only uses UseMcpo to populate request.Tools and to enable tool handling. This means internal tools like get_instant_view will be available on the first response but not on regenerations for the same chat; if you want consistent behavior, consider wiring UseInternalTools into the regeneration request and its newStreamProcessor call in the same way as in Chat.
There was a problem hiding this comment.
Fixed in commit 1f3ca17. Added UseInternalTools support to regenerateResponse in reaction.go - it now includes internal tools in the request and passes the combined flag to newStreamProcessor, matching the behavior in Chat.
|
@copilot apply changes based on the comments in this thread |
…Tools into regeneration Co-authored-by: hugefiver <18693500+hugefiver@users.noreply.github.com>
All three review comments have been addressed in commit 1f3ca17:
|
chat/internal_tools.gowith theget_instant_viewtoolInternalToolstruct with handler functionInitInternalTools(),GetInternalTool(),GetInternalToolDefinitions()functionsget_instant_viewtool that retrieves URL entities from messages stored in Redischat_id,message_idstreaming.goto check internal tools first, then external mcpochat.goto include internal tools in requestUseInternalToolsconfig option inChatConfigSingleInitInternalTools()call inmain.gochat/internal_tools_test.gowith comprehensive testsTestGetInternalToolDefinitionsmore resilient by not hardcoding countChatfunction by removing intermediate variableUseInternalToolsinto regeneration path for consistent behaviorUsage Example
To enable internal tools for a chat configuration:
The AI can call
get_instant_viewwith{"chat_id": -1001234, "message_id": 123}to retrieve URL info.Original prompt
💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.