django-unicom 25.2.27.dev0__tar.gz → 25.2.27.dev2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/PKG-INFO +1 -1
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/django_unicom.egg-info/PKG-INFO +1 -1
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/_version.py +2 -2
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/models/message.py +53 -2
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/models/message_template.py +4 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/services/email/IMAP_thread_manager.py +2 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/services/email/listen_to_IMAP.py +8 -2
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/services/email/send_email_message.py +4 -1
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/services/html_inline_images.py +4 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/services/telegram/send_telegram_message.py +4 -1
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/.cursor/rules/match_codebase_style.mdc +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/.cursor/rules/preserve_comments_and_irrelevant_code.mdc +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/.cursor/rules/require_context_before_changes.mdc +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/Dockerfile +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/MANIFEST.in +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/Makefile +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/README.md +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/conftest.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/django_unicom.egg-info/SOURCES.txt +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/django_unicom.egg-info/dependency_links.txt +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/django_unicom.egg-info/requires.txt +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/django_unicom.egg-info/top_level.txt +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/docker-compose.yaml +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/entrypoint.sh +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/manage.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/pyproject.toml +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/pytest.ini +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/requirements.txt +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/setup.cfg +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/setup.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/test_dkim_security.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/tests/__init__.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/tests/test_email_authentication.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/tests/test_email_live.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/tests/test_email_request_processing.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/tests/test_telegram_live.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/tests/utils.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/__init__.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/admin/__init__.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/admin/account_admin.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/admin/channel_admin.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/admin/chat_admin.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/admin/draft_message_admin.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/admin/email_inline_image_admin.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/admin/filters.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/admin/member_admin.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/admin/message_admin.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/admin/message_template_admin.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/admin/request_admin.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/apps.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/management/__init__.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/management/commands/__init__.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/management/commands/mail_inbox_listen.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/management/commands/run_as_llm_chat.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/management/commands/send_scheduled_messages.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/management/commands/start_imap_listeners.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/migrations/0001_initial.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/migrations/0002_emailinlineimage.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/migrations/0003_alter_emailinlineimage_email_message.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/migrations/0004_messagetemplateinlineimage.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/migrations/0005_emailinlineimage_hash_and_more.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/migrations/0006_channel_created_at_channel_created_by_and_more.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/migrations/0007_message_imap_uid.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/migrations/0008_add_all_members_group.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/migrations/0009_add_tool_call_types.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/migrations/0010_request_initial_request_request_llm_calls_count_and_more.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/migrations/0011_toolcall_add_message_reference.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/migrations/__init__.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/models/__init__.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/models/account.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/models/account_chat.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/models/channel.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/models/chat.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/models/constants.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/models/draft_message.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/models/fields.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/models/member.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/models/member_group.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/models/request.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/models/request_category.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/models/tool_call.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/models/update.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/services/__init__.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/services/chat_summary.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/services/crossplatform/__init__.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/services/crossplatform/reply_to_message.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/services/crossplatform/scheduler.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/services/crossplatform/send_message.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/services/decode_base64_image.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/services/email/__init__.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/services/email/email_tracking.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/services/email/quote_filter.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/services/email/replace_cid_images_with_base64.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/services/email/save_email_message.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/services/email/validate_email_config.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/services/get_public_origin.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/services/internal/__init__.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/services/internal/generate_text_message_data.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/services/internal/save_internal_message.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/services/internal/send_internal_message.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/services/llm/README.md +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/services/llm/__init__.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/services/llm/tool_calls.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/services/telegram/__init__.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/services/telegram/download_file.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/services/telegram/escape_markdown.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/services/telegram/get_file_path.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/services/telegram/save_telegram_message.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/services/telegram/set_telegram_webhook.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/services/telegram/start_typing_in_telegram.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/services/telegram/stop_typing_in_telegram.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/services/whatsapp/__init__.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/services/whatsapp/get_template.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/services/whatsapp/save_whatsapp_message.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/services/whatsapp/save_whatsapp_message_status.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/services/whatsapp/send_whatsapp_message.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/signals.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/static/unicom/css/bootstrap_scoped.css +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/static/unicom/css/draft_message_mobile.css +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/static/unicom/js/channel_config.js +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/static/unicom/js/tinymce_ai_template.js +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/static/unicom/js/tinymce_init.js +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/templates/admin/unicom/chat/change_list.html +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/templates/admin/unicom/chat/compose.html +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/templates/admin/unicom/chat_history.html +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/templates/admin/unicom/forms/email_message_form.html +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/templates/admin/unicom/forms/text_message_form.html +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/templates/admin/unicom/includes/ai_template_modal.html +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/templates/admin/unicom/includes/loading_indicators.html +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/templates/admin/unicom/includes/message_actions_menu.html +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/templates/admin/unicom/messagetemplate/change_form.html +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/templates/code_templates/category_processor.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/urls.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/views/__init__.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/views/chat_history_view.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/views/compose_view.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/views/email_tracking.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/views/inline_image.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/views/message_template.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/views/telegram_webhook.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/views/whatsapp_webhook.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom_project/__init__.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom_project/asgi.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom_project/settings.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom_project/urls.py +0 -0
- {django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom_project/wsgi.py +0 -0
|
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
|
|
|
28
28
|
commit_id: COMMIT_ID
|
|
29
29
|
__commit_id__: COMMIT_ID
|
|
30
30
|
|
|
31
|
-
__version__ = version = '25.2.27.
|
|
32
|
-
__version_tuple__ = version_tuple = (25, 2, 27, '
|
|
31
|
+
__version__ = version = '25.2.27.dev2'
|
|
32
|
+
__version_tuple__ = version_tuple = (25, 2, 27, 'dev2')
|
|
33
33
|
|
|
34
34
|
__commit_id__ = commit_id = None
|
|
@@ -284,8 +284,8 @@ class Message(models.Model):
|
|
|
284
284
|
import json
|
|
285
285
|
arguments = json.dumps(arguments)
|
|
286
286
|
d = {
|
|
287
|
-
"role":
|
|
288
|
-
"content":
|
|
287
|
+
"role": "assistant", # Tool calls are always from assistant
|
|
288
|
+
"content": None, # Tool calls should have null content
|
|
289
289
|
"tool_calls": [{
|
|
290
290
|
"id": tool_call_data.get('id', f"call_{msg.id}"),
|
|
291
291
|
"type": "function",
|
|
@@ -316,6 +316,28 @@ class Message(models.Model):
|
|
|
316
316
|
idx = list(qs.values_list("id", flat=True)).index(self.id)
|
|
317
317
|
start = max(0, idx - depth + 1)
|
|
318
318
|
selected = list(qs[start:idx+1])
|
|
319
|
+
|
|
320
|
+
# Handle user interruption for tool response messages in chat mode
|
|
321
|
+
if self.media_type == "tool_response":
|
|
322
|
+
# Find any user message that came chronologically after any tool call in our range
|
|
323
|
+
tool_call_timestamps = [m.timestamp for m in selected if m.media_type == "tool_call"]
|
|
324
|
+
if tool_call_timestamps:
|
|
325
|
+
latest_tool_call_time = max(tool_call_timestamps)
|
|
326
|
+
# Look for user messages after the latest tool call but before this tool response
|
|
327
|
+
user_interrupt = self.chat.messages.filter(
|
|
328
|
+
is_outgoing=False,
|
|
329
|
+
timestamp__gt=latest_tool_call_time,
|
|
330
|
+
timestamp__lt=self.timestamp
|
|
331
|
+
).exclude(
|
|
332
|
+
media_type__in=['tool_call', 'tool_response']
|
|
333
|
+
).order_by('-timestamp').first()
|
|
334
|
+
|
|
335
|
+
if user_interrupt:
|
|
336
|
+
# Found user interrupt - get conversation from that user message
|
|
337
|
+
return user_interrupt.as_llm_chat(depth=depth, mode=mode,
|
|
338
|
+
system_instruction=system_instruction,
|
|
339
|
+
multimodal=multimodal)
|
|
340
|
+
|
|
319
341
|
for m in selected:
|
|
320
342
|
messages.append(msg_to_dict(m))
|
|
321
343
|
elif mode == "thread":
|
|
@@ -326,6 +348,33 @@ class Message(models.Model):
|
|
|
326
348
|
break
|
|
327
349
|
chain.append(cur)
|
|
328
350
|
cur = cur.reply_to_message
|
|
351
|
+
|
|
352
|
+
# Handle user interruption for tool response messages in thread mode
|
|
353
|
+
if self.media_type == "tool_response":
|
|
354
|
+
# Find any user message that came chronologically after any tool call in our chain
|
|
355
|
+
# AND that replies to one of the messages in our chain
|
|
356
|
+
tool_call_timestamps = [m.timestamp for m in chain if m.media_type == "tool_call"]
|
|
357
|
+
if tool_call_timestamps:
|
|
358
|
+
latest_tool_call_time = max(tool_call_timestamps)
|
|
359
|
+
chain_message_ids = [m.id for m in chain]
|
|
360
|
+
|
|
361
|
+
# Look for user messages after the latest tool call, before this tool response,
|
|
362
|
+
# that reply to any message in our chain
|
|
363
|
+
user_interrupt = self.chat.messages.filter(
|
|
364
|
+
is_outgoing=False,
|
|
365
|
+
timestamp__gt=latest_tool_call_time,
|
|
366
|
+
timestamp__lt=self.timestamp,
|
|
367
|
+
reply_to_message_id__in=chain_message_ids
|
|
368
|
+
).exclude(
|
|
369
|
+
media_type__in=['tool_call', 'tool_response']
|
|
370
|
+
).order_by('-timestamp').first()
|
|
371
|
+
|
|
372
|
+
if user_interrupt:
|
|
373
|
+
# Found user interrupt - get conversation from that user message
|
|
374
|
+
return user_interrupt.as_llm_chat(depth=depth, mode=mode,
|
|
375
|
+
system_instruction=system_instruction,
|
|
376
|
+
multimodal=multimodal)
|
|
377
|
+
|
|
329
378
|
for m in reversed(chain):
|
|
330
379
|
messages.append(msg_to_dict(m))
|
|
331
380
|
else:
|
|
@@ -449,6 +498,8 @@ class Message(models.Model):
|
|
|
449
498
|
m = re.match(r"data:(.*?);base64,(.*)", url)
|
|
450
499
|
if m:
|
|
451
500
|
mime, b64data = m.groups()
|
|
501
|
+
if not isinstance(mime, str):
|
|
502
|
+
raise ValueError(f"Expected mime to be string, got {type(mime)}: {mime}")
|
|
452
503
|
ext = mime.split("/")[-1]
|
|
453
504
|
image_file_name = f"media/{uuid.uuid4()}.{ext}"
|
|
454
505
|
with open(image_file_name, "wb") as f:
|
|
@@ -108,7 +108,11 @@ class MessageTemplate(models.Model):
|
|
|
108
108
|
for img in soup.find_all('img'):
|
|
109
109
|
src = img.get('src', '')
|
|
110
110
|
if src.startswith('data:image/') and ';base64,' in src:
|
|
111
|
+
if not isinstance(src, str):
|
|
112
|
+
raise ValueError(f"Expected src to be string, got {type(src)}: {src}")
|
|
111
113
|
header, b64data = src.split(';base64,', 1)
|
|
114
|
+
if not isinstance(header, str):
|
|
115
|
+
raise ValueError(f"Expected header to be string, got {type(header)}: {header}")
|
|
112
116
|
mime = header.split(':')[1]
|
|
113
117
|
ext = mimetypes.guess_extension(mime) or '.png'
|
|
114
118
|
data = base64.b64decode(b64data)
|
|
@@ -66,6 +66,8 @@ class IMAPThreadManager:
|
|
|
66
66
|
channel.listen_to_IMAP()
|
|
67
67
|
except Exception as e:
|
|
68
68
|
logger.exception(f"Listener for Channel {channel.pk} crashed: {e}")
|
|
69
|
+
import traceback
|
|
70
|
+
logger.error(f"Full traceback: {traceback.format_exc()}")
|
|
69
71
|
time.sleep(10)
|
|
70
72
|
finally:
|
|
71
73
|
# ensure no DB connections are leaked by this thread
|
{django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/services/email/listen_to_IMAP.py
RENAMED
|
@@ -41,6 +41,8 @@ def listen_to_IMAP(channel):
|
|
|
41
41
|
# logger.info(f"Channel {channel.pk}: Found email {msg.id} (uid={uid})")
|
|
42
42
|
except Exception as e:
|
|
43
43
|
logger.error(f"Channel {channel.pk}: Failed to process UID {uid}: {e}")
|
|
44
|
+
import traceback
|
|
45
|
+
logger.error(f"Full traceback: {traceback.format_exc()}")
|
|
44
46
|
|
|
45
47
|
if mark_seen_on == 'on_save':
|
|
46
48
|
if uids:
|
|
@@ -85,13 +87,17 @@ def listen_to_IMAP(channel):
|
|
|
85
87
|
server.add_flags(uid, [SEEN])
|
|
86
88
|
logger.debug(f"Incoming email - Message-ID: {msg.id}, In-Reply-To: {msg.raw.get('In-Reply-To') if msg.raw else 'None'}")
|
|
87
89
|
logger.debug(f"Associated with chat: {msg.chat_id}")
|
|
88
|
-
except Exception:
|
|
89
|
-
logger.error(f"Channel {channel.pk}: Failed to process UID {uid}")
|
|
90
|
+
except Exception as e:
|
|
91
|
+
logger.error(f"Channel {channel.pk}: Failed to process UID {uid}: {e}")
|
|
92
|
+
import traceback
|
|
93
|
+
logger.error(f"Full traceback: {traceback.format_exc()}")
|
|
90
94
|
finally:
|
|
91
95
|
connections.close_all()
|
|
92
96
|
|
|
93
97
|
except Exception as e:
|
|
94
98
|
logger.error(f"Channel {channel.pk}: Fatal IMAP error: {e}, reconnecting in 30s…")
|
|
99
|
+
import traceback
|
|
100
|
+
logger.error(f"Full traceback: {traceback.format_exc()}")
|
|
95
101
|
time.sleep(3)
|
|
96
102
|
finally:
|
|
97
103
|
# Ensure we close all connections to avoid leaks
|
|
@@ -223,7 +223,10 @@ def send_email_message(channel: Channel, params: dict, user: User=None):
|
|
|
223
223
|
if parent:
|
|
224
224
|
# First add any existing References from parent
|
|
225
225
|
if parent.raw and 'References' in parent.raw:
|
|
226
|
-
|
|
226
|
+
references_header = parent.raw['References']
|
|
227
|
+
if not isinstance(references_header, str):
|
|
228
|
+
raise ValueError(f"Expected References header to be string, got {type(references_header)}: {references_header}")
|
|
229
|
+
references.extend((references_header or '').split())
|
|
227
230
|
# Then add the parent's Message-ID
|
|
228
231
|
references.append(params['reply_to_message_id'])
|
|
229
232
|
else:
|
{django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/services/html_inline_images.py
RENAMED
|
@@ -41,7 +41,11 @@ def html_base64_images_to_shortlinks(html: str) -> tuple[str, list[int]]:
|
|
|
41
41
|
for img in soup.find_all('img'):
|
|
42
42
|
src = img.get('src', '')
|
|
43
43
|
if src.startswith('data:image/') and ';base64,' in src:
|
|
44
|
+
if not isinstance(src, str):
|
|
45
|
+
raise ValueError(f"Expected src to be string, got {type(src)}: {src}")
|
|
44
46
|
header, b64data = src.split(';base64,', 1)
|
|
47
|
+
if not isinstance(header, str):
|
|
48
|
+
raise ValueError(f"Expected header to be string, got {type(header)}: {header}")
|
|
45
49
|
mime = header.split(':')[1]
|
|
46
50
|
ext = mimetypes.guess_extension(mime) or '.png'
|
|
47
51
|
data = base64.b64decode(b64data)
|
|
@@ -125,7 +125,10 @@ def send_telegram_message(channel: Channel, params: dict, user: User=None, retry
|
|
|
125
125
|
params[text_field_key] = params[text_field_key][:4095 - len(cropping_footer)] + cropping_footer
|
|
126
126
|
elif "Can't find end of the entity starting at byte offset" in ret.get('description', ''):
|
|
127
127
|
# Extract mentioned byte offset from error message
|
|
128
|
-
|
|
128
|
+
description = ret['description']
|
|
129
|
+
if not isinstance(description, str):
|
|
130
|
+
raise ValueError(f"Expected description to be string, got {type(description)}: {description}")
|
|
131
|
+
byte_offset = int(description.split("byte offset")[1].split()[0])
|
|
129
132
|
print(f"Byte offset: {byte_offset}")
|
|
130
133
|
mentioned_char = params[text_field_key][byte_offset]
|
|
131
134
|
print(f"Mentioned char that's causing the error: \"{mentioned_char}\"")
|
{django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/.cursor/rules/match_codebase_style.mdc
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/django_unicom.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
{django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/django_unicom.egg-info/requires.txt
RENAMED
|
File without changes
|
{django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/django_unicom.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/tests/test_email_authentication.py
RENAMED
|
File without changes
|
|
File without changes
|
{django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/tests/test_email_request_processing.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/admin/draft_message_admin.py
RENAMED
|
File without changes
|
{django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/admin/email_inline_image_admin.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/admin/message_template_admin.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/management/commands/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/migrations/0002_emailinlineimage.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/migrations/0007_message_imap_uid.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/services/crossplatform/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/services/crossplatform/scheduler.py
RENAMED
|
File without changes
|
|
File without changes
|
{django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/services/decode_base64_image.py
RENAMED
|
File without changes
|
|
File without changes
|
{django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/services/email/email_tracking.py
RENAMED
|
File without changes
|
{django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/services/email/quote_filter.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/services/get_public_origin.py
RENAMED
|
File without changes
|
{django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/services/internal/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/services/telegram/__init__.py
RENAMED
|
File without changes
|
{django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/services/telegram/download_file.py
RENAMED
|
File without changes
|
|
File without changes
|
{django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/services/telegram/get_file_path.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/services/whatsapp/__init__.py
RENAMED
|
File without changes
|
{django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/services/whatsapp/get_template.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/static/unicom/js/channel_config.js
RENAMED
|
File without changes
|
|
File without changes
|
{django_unicom-25.2.27.dev0 → django_unicom-25.2.27.dev2}/unicom/static/unicom/js/tinymce_init.js
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|