resolve_reference_target tool #97

Open
opened 2026-04-20 04:40:28 +03:00 by skobkin · 0 comments
Owner

PRD: resolve_reference_target

Summary
Implement a deterministic tool that resolves ambiguous user references such as “this”, “that file”, “the last poll”, “the reminder”, “the image above”, or their equivalents in any language, without relying on language-specific hardcoded words. The tool must work primarily from message metadata, recent bot/user actions, object type hints, topic scope, reply chain, and recency scoring. LLM use is out of scope for this tool and should remain an optional higher-level fallback outside the tool.

Goal
Return the most likely referenced object(s) from the current conversational scope so the bot can safely continue a follow-up flow without guessing.

Non-goals

  • No direct LLM inference inside the tool.
  • No full-text semantic interpretation of arbitrary human language.
  • No destructive actions.
  • No global cross-chat retrieval.
  • No persistence requirements beyond existing in-memory state.

Why
The bot will increasingly support follow-up actions around links, media, polls, reminders, summaries, and other objects. Users will naturally refer to prior objects indirectly. The bot needs a fast, compact, deterministic resolver to avoid hallucinating which object is being discussed.

Supported object kinds

  • article
  • link
  • media.image
  • media.video
  • media.voice
  • media.document
  • media.pdf
  • poll
  • reminder
  • summary
  • bot_message
  • message

Scope rules
The resolver must search in this priority order:

  1. current reply target / reply chain
  2. current topic/thread
  3. current chat fallback

The resolver must never inspect other chats.

Inputs
The tool should accept a structured request like this conceptually:

  • chat_id
  • topic_id (optional)
  • current_message_id
  • reply_to_message_id (optional)
  • sender_user_id
  • raw_user_text
  • normalized_reference_hints (optional)
  • allowed_kinds (optional)
  • max_candidates (default 3)

Notes on multilingual support
Do not rely on fixed English or Russian tokens like “this” or “that”.
Instead, the caller may pass optional normalized_reference_hints extracted upstream from the user message, for example:

  • positional_hint: replied_message | latest | previous | above | current_topic_recent
  • ordinal_hint: first | second | last
  • target_kind_hint: poll | reminder | image | file | article | quote
  • ownership_hint: mine | bot_created | any
  • recency_hint: latest | recent | currently_active

If normalized_reference_hints are missing, the tool must still work using metadata and state only.

State sources
Read only from existing in-memory indexed state and lightweight metadata:

  • recent messages in current topic/chat
  • recent bot-created objects
  • recent media registry
  • recent polls
  • recent reminders
  • recent summaries / article cache
  • currently active objects if available
  • reply metadata

Output
Return either:

  1. resolved: one strong winner
  2. ambiguous: 2-3 plausible candidates
  3. not_found: nothing plausible enough

Suggested output shape

  • status: resolved | ambiguous | not_found
  • best_match: object descriptor or null
  • candidates: compact candidate list
  • confidence: float 0..1
  • reasons: compact machine-readable reason codes
  • scope_used: reply_chain | topic | chat
  • diagnostics: optional compact scoring info for logs only

Each object descriptor should include only compact safe fields:

  • object_id
  • kind
  • source_message_id
  • chat_id
  • topic_id
  • title_or_label (short, optional)
  • created_by_user_id (optional)
  • created_by_bot (bool)
  • created_at
  • last_touched_at

Resolution algorithm

  1. Build candidate pool from current scope.
  2. Filter by allowed_kinds if provided.
  3. Score candidates using deterministic weighted features.
  4. Sort by score descending.
  5. Apply confidence and ambiguity thresholds.
  6. Return resolved if top candidate clearly outranks the rest.
  7. Return ambiguous if 2-3 candidates are close.
  8. Return not_found if no candidate reaches minimum threshold.

Recommended scoring features

  • exact reply target match: very high weight
  • same topic: high weight
  • currently active object in same topic: high weight
  • kind match with target_kind_hint: high weight
  • recent bot-created object when request implies bot action: medium-high
  • recency decay: medium
  • same sender ownership when request implies “my reminder/poll”: medium
  • referenced object previously touched in same interaction: medium
  • chat-scope only fallback penalty: negative
  • stale object penalty: negative

Reason codes
Examples:

  • exact_reply_target
  • same_topic
  • kind_match
  • recent_object
  • bot_created
  • owned_by_sender
  • currently_active
  • stale_penalty
  • weak_scope_fallback

API behavior requirements

  • Must be fast and bounded.
  • Must return compact results suitable for a small context budget.
  • Must not dump raw message history.
  • Must be deterministic for the same indexed state and inputs.
  • Must be safe when state is sparse.

Edge cases

  • Multiple active discussions in one chat: prefer topic scope strongly.
  • Reply exists but referenced kind does not match: include reply candidate but allow higher-scoring typed candidate.
  • No topic support in chat: fall back to chat-only mode cleanly.
  • Two candidates with near-equal score: return ambiguous, do not guess.
  • User asks for “my reminder” but reminders belong to multiple users: prefer sender-owned reminders.
  • Object expired from TTL but source message still exists: allow message candidate, not typed object hallucination.
  • Empty hints and no reply target: rely on recency + activity + scope only.

Observability
Log compactly:

  • request id
  • chat_id
  • topic_id
  • current_message_id
  • candidate count
  • returned status
  • top candidate ids
  • top score gap

Do not log raw full user text by default if existing logging policy avoids prompt-sized blobs.

Tests
Must include focused tests for:

  • exact reply target resolution
  • same-topic vs other-topic conflict
  • kind filtering for poll/reminder/media
  • sender ownership preference
  • ambiguity return instead of bad guess
  • stale candidate deprioritization
  • missing hints fallback
  • multilingual caller path using normalized hints rather than literal tokens

Acceptance criteria

  • The tool can resolve obvious follow-up references without model guessing.
  • The tool behaves correctly in supergroups with topics.
  • The tool returns ambiguous instead of inventing certainty.
  • The tool output is compact enough for tool-loop use.
  • The implementation is fully deterministic and covered by focused tests.

Caused by #92 and #95, related to #98

PRD: resolve_reference_target Summary Implement a deterministic tool that resolves ambiguous user references such as “this”, “that file”, “the last poll”, “the reminder”, “the image above”, or their equivalents in any language, without relying on language-specific hardcoded words. The tool must work primarily from message metadata, recent bot/user actions, object type hints, topic scope, reply chain, and recency scoring. LLM use is out of scope for this tool and should remain an optional higher-level fallback outside the tool. Goal Return the most likely referenced object(s) from the current conversational scope so the bot can safely continue a follow-up flow without guessing. Non-goals - No direct LLM inference inside the tool. - No full-text semantic interpretation of arbitrary human language. - No destructive actions. - No global cross-chat retrieval. - No persistence requirements beyond existing in-memory state. Why The bot will increasingly support follow-up actions around links, media, polls, reminders, summaries, and other objects. Users will naturally refer to prior objects indirectly. The bot needs a fast, compact, deterministic resolver to avoid hallucinating which object is being discussed. Supported object kinds - article - link - media.image - media.video - media.voice - media.document - media.pdf - poll - reminder - summary - bot_message - message Scope rules The resolver must search in this priority order: 1. current reply target / reply chain 2. current topic/thread 3. current chat fallback The resolver must never inspect other chats. Inputs The tool should accept a structured request like this conceptually: - chat_id - topic_id (optional) - current_message_id - reply_to_message_id (optional) - sender_user_id - raw_user_text - normalized_reference_hints (optional) - allowed_kinds (optional) - max_candidates (default 3) Notes on multilingual support Do not rely on fixed English or Russian tokens like “this” or “that”. Instead, the caller may pass optional normalized_reference_hints extracted upstream from the user message, for example: - positional_hint: replied_message | latest | previous | above | current_topic_recent - ordinal_hint: first | second | last - target_kind_hint: poll | reminder | image | file | article | quote - ownership_hint: mine | bot_created | any - recency_hint: latest | recent | currently_active If normalized_reference_hints are missing, the tool must still work using metadata and state only. State sources Read only from existing in-memory indexed state and lightweight metadata: - recent messages in current topic/chat - recent bot-created objects - recent media registry - recent polls - recent reminders - recent summaries / article cache - currently active objects if available - reply metadata Output Return either: 1. resolved: one strong winner 2. ambiguous: 2-3 plausible candidates 3. not_found: nothing plausible enough Suggested output shape - status: resolved | ambiguous | not_found - best_match: object descriptor or null - candidates: compact candidate list - confidence: float 0..1 - reasons: compact machine-readable reason codes - scope_used: reply_chain | topic | chat - diagnostics: optional compact scoring info for logs only Each object descriptor should include only compact safe fields: - object_id - kind - source_message_id - chat_id - topic_id - title_or_label (short, optional) - created_by_user_id (optional) - created_by_bot (bool) - created_at - last_touched_at Resolution algorithm 1. Build candidate pool from current scope. 2. Filter by allowed_kinds if provided. 3. Score candidates using deterministic weighted features. 4. Sort by score descending. 5. Apply confidence and ambiguity thresholds. 6. Return resolved if top candidate clearly outranks the rest. 7. Return ambiguous if 2-3 candidates are close. 8. Return not_found if no candidate reaches minimum threshold. Recommended scoring features - exact reply target match: very high weight - same topic: high weight - currently active object in same topic: high weight - kind match with target_kind_hint: high weight - recent bot-created object when request implies bot action: medium-high - recency decay: medium - same sender ownership when request implies “my reminder/poll”: medium - referenced object previously touched in same interaction: medium - chat-scope only fallback penalty: negative - stale object penalty: negative Reason codes Examples: - exact_reply_target - same_topic - kind_match - recent_object - bot_created - owned_by_sender - currently_active - stale_penalty - weak_scope_fallback API behavior requirements - Must be fast and bounded. - Must return compact results suitable for a small context budget. - Must not dump raw message history. - Must be deterministic for the same indexed state and inputs. - Must be safe when state is sparse. Edge cases - Multiple active discussions in one chat: prefer topic scope strongly. - Reply exists but referenced kind does not match: include reply candidate but allow higher-scoring typed candidate. - No topic support in chat: fall back to chat-only mode cleanly. - Two candidates with near-equal score: return ambiguous, do not guess. - User asks for “my reminder” but reminders belong to multiple users: prefer sender-owned reminders. - Object expired from TTL but source message still exists: allow message candidate, not typed object hallucination. - Empty hints and no reply target: rely on recency + activity + scope only. Observability Log compactly: - request id - chat_id - topic_id - current_message_id - candidate count - returned status - top candidate ids - top score gap Do not log raw full user text by default if existing logging policy avoids prompt-sized blobs. Tests Must include focused tests for: - exact reply target resolution - same-topic vs other-topic conflict - kind filtering for poll/reminder/media - sender ownership preference - ambiguity return instead of bad guess - stale candidate deprioritization - missing hints fallback - multilingual caller path using normalized hints rather than literal tokens Acceptance criteria - The tool can resolve obvious follow-up references without model guessing. - The tool behaves correctly in supergroups with topics. - The tool returns ambiguous instead of inventing certainty. - The tool output is compact enough for tool-loop use. - The implementation is fully deterministic and covered by focused tests. --- Caused by #92 and #95, related to #98
skobkin self-assigned this 2026-04-20 04:40:28 +03:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
skobkin/telegram-ollama-reply-bot#97
No description provided.