Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/telegram_codex_bot/transcript_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ class TranscriptParser:
# Magic string constants
_NO_CONTENT_PLACEHOLDER = "(no content)"
_INTERRUPTED_TEXT = "[Request interrupted by user for tool use]"
_INTERNAL_TOOL_NAMES = {"update_plan"}
_INTERNAL_TOOL_NAMES = {"update_plan", "view_image", "viewimage"}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Hide orphaned view_image outputs

When the bot starts or restarts after the view_image function_call has already been consumed but before its function_call_output is read, the in-memory pending-tool map in session_monitor is empty, and the output entry only carries a call_id with no tool name. In that case _is_internal_tool_name(tool_name) sees None, so the parser emits the JSON output containing data:image/png;base64,... as a persistent Telegram tool-result bubble instead of hiding it. Adding view_image to the internal-name set only hides outputs while the matching call is still pending; the output shape should also be detected or the hidden call IDs persisted/reconstructed.

Useful? React with 👍 / 👎.

_MAX_SUMMARY_LENGTH = 200
_AUTH_ERROR_HINT_MARKERS = (
"could not be refreshed",
Expand Down
42 changes: 42 additions & 0 deletions tests/telegram_codex_bot/test_transcript_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,48 @@ def test_private_connector_tool_calls_are_hidden_but_thinking_stays(
assert "checking repos" in result[0].text
assert pending == {}

def test_view_image_tool_calls_are_hidden_from_messages(self):
use_item = {
"type": "response_item",
"timestamp": "2026-06-08T09:40:05Z",
"payload": {
"type": "function_call",
"call_id": "call_view_image",
"name": "view_image",
"arguments": json.dumps(
{
"path": "/tmp/ibkr-gateway-screen.png",
"detail": "high",
}
),
},
}
result_item = {
"type": "response_item",
"timestamp": "2026-06-08T09:40:06Z",
"payload": {
"type": "function_call_output",
"call_id": "call_view_image",
"output": json.dumps(
[
{
"type": "input_image",
"image_url": "data:image/png;base64,abc123",
}
]
),
},
}

entries = [
TranscriptParser.parse_line(json.dumps(use_item)),
TranscriptParser.parse_line(json.dumps(result_item)),
]
result, pending = TranscriptParser.parse_entries([e for e in entries if e])

assert result == []
assert pending == {}

def test_response_item_function_call_output_is_normalized_as_tool_result(self):
item = {
"type": "response_item",
Expand Down
Loading