Skip to content

Feature/social media integration testing#233

Open
pulinduvidmal wants to merge 105 commits intodevelopfrom
feature/social_media_integration_testing
Open

Feature/social media integration testing#233
pulinduvidmal wants to merge 105 commits intodevelopfrom
feature/social_media_integration_testing

Conversation

@pulinduvidmal
Copy link
Contributor

@pulinduvidmal pulinduvidmal commented Feb 16, 2026

Description

Add real Slack/Telegram integration test

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update
  • Refactoring (no functional changes)
  • Performance improvement
  • Test update
  • CI/CD update
  • Other (please describe):

Related Issues

Fixes #
Relates to #

Changes Made

Testing

  • Unit tests pass locally
  • Integration tests pass locally
  • Manual testing completed
  • New tests added for changes

Checklist

  • My code follows the project's style guidelines
  • I have performed a self-review of my code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published

Screenshots (if applicable)

Additional Notes

pulinduvidmal and others added 30 commits December 23, 2025 21:13
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings March 2, 2026 11:02
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 41 out of 47 changed files in this pull request and generated 8 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +152 to +161
max_attachments: int = Field(default=20, description="Maximum number of attachments to keep per session")
description_max_length: int = Field(default=200, description="Maximum length of attachment description text")
description_model: str = Field(
default="gpt-4o",
description="LiteLLM model used to generate brief descriptions when an attachment is first received (called by the pre-hook)",
)
analysis_model: str = Field(
default="gpt-4o",
description="LiteLLM model used by the analyze_attachments tool when the agent requests a full analysis of an attachment",
)
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

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

description_max_length is introduced in _MultimodalConfig, but it isn’t referenced anywhere else in the codebase. Either enforce this limit when generating/storing descriptions (e.g., in describe_attachment_briefly or the multimodal pre-hook) or remove the config option to avoid dead/unused configuration knobs.

Copilot uses AI. Check for mistakes.
Comment on lines 1 to 3
import asyncio
import json
import os
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

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

json is imported but never used in this test module. Remove it to keep the test file clean (and to avoid unused-import lint failures if enabled).

Copilot uses AI. Check for mistakes.
Comment on lines +43 to +45
3. Click **Apply**.
4. Go to **Channels** and add **Microsoft Teams**. accepting the terms.

Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

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

Minor grammar: sentence is split oddly here ("Go to Channels and add Microsoft Teams. accepting the terms."). Consider changing to a single sentence like "...add Microsoft Teams, accepting the terms." or "...add Microsoft Teams and accept the terms.".

Copilot uses AI. Check for mistakes.
self._log = logging.getLogger("ak.api.slack")
self._slack_agent = Config.get().slack.agent if Config.get().slack.agent != "" else None
self._slack_agent_acknowledgement = Config.get().slack.agent_acknowledgement if Config.get().slack.agent_acknowledgement != "" else None
self._slack_test_mode = Config.get().slack.test_mode
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

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

Config.get().slack.test_mode is accessed here, but _SlackConfig in ak-py/src/agentkernel/core/config.py does not define a test_mode field. With extra="ignore", test_mode in YAML/env will be discarded and this will raise AttributeError at runtime during handler initialization. Add test_mode: bool = Field(default=False, ...) to _SlackConfig (and document it), or use getattr(Config.get().slack, "test_mode", False) as a backwards-compatible default.

Suggested change
self._slack_test_mode = Config.get().slack.test_mode
self._slack_test_mode = getattr(Config.get().slack, "test_mode", False)

Copilot uses AI. Check for mistakes.
Comment on lines 24 to 30
self._telegram_agent = Config.get().telegram.agent if Config.get().telegram.agent != "" else None
self._bot_token = Config.get().telegram.bot_token
self._webhook_secret = Config.get().telegram.webhook_secret
self._api_version = Config.get().telegram.api_version or "bot"
self._base_url = f"https://api.telegram.org/{self._api_version}{self._bot_token}"
self._api_base_url = Config.get().telegram.api_base_url
self._base_url = f"{self._api_base_url}/{self._api_version}{self._bot_token}"

Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

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

Config.get().telegram.api_base_url is used to build _base_url, but _TelegramConfig in ak-py/src/agentkernel/core/config.py does not define api_base_url. This will raise AttributeError at startup, and env vars like AK_TELEGRAM__API_BASE_URL will be ignored due to extra="ignore". Add api_base_url to _TelegramConfig with a default like https://api.telegram.org (and consider normalizing trailing / to avoid double slashes).

Copilot uses AI. Check for mistakes.
Comment on lines +92 to +100
# Bot Framework expects a dict with 'body' as parsed JSON
req_dict = {"body": json.loads(body_text), "headers": {"Authorization": auth_header}} # Parse JSON

# Process the activity using Bot Framework adapter
async def bot_logic(turn_context: TurnContext):
await self._handle_teams_message(turn_context)

# Process the request - Bot Framework validates auth internally
await self._adapter.process_activity(req_dict, auth_header, bot_logic)
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

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

BotFrameworkAdapter.process_activity(...) expects an Activity (deserialized from the request JSON), not a custom {"body": ..., "headers": ...} dict. As written, this is very likely to fail inside the adapter (and you’re also discarding any InvokeResponse that should be returned for certain activity types). Deserialize with Activity().deserialize(json.loads(body_text)), call process_activity(activity, auth_header, bot_logic), and if an invoke response is returned, convert it into the FastAPI Response (status/body/headers).

Suggested change
# Bot Framework expects a dict with 'body' as parsed JSON
req_dict = {"body": json.loads(body_text), "headers": {"Authorization": auth_header}} # Parse JSON
# Process the activity using Bot Framework adapter
async def bot_logic(turn_context: TurnContext):
await self._handle_teams_message(turn_context)
# Process the request - Bot Framework validates auth internally
await self._adapter.process_activity(req_dict, auth_header, bot_logic)
# Deserialize the incoming request body into a Bot Framework Activity
activity = Activity().deserialize(json.loads(body_text))
# Process the activity using Bot Framework adapter
async def bot_logic(turn_context: TurnContext):
await self._handle_teams_message(turn_context)
# Process the request - Bot Framework validates auth internally
invoke_response = await self._adapter.process_activity(activity, auth_header, bot_logic)
# If an InvokeResponse is returned, convert it into a FastAPI Response
if invoke_response:
body = invoke_response.body if hasattr(invoke_response, "body") else None
content = json.dumps(body) if body is not None else None
headers = getattr(invoke_response, "headers", None)
if headers is not None and not isinstance(headers, dict):
headers = None
return Response(
status_code=invoke_response.status,
content=content,
media_type="application/json" if content is not None else None,
headers=headers,
)
# For non-invoke activities, return a simple 200 OK

Copilot uses AI. Check for mistakes.
Comment on lines +17 to +20
Usage:
cd examples/api/slack && ./build.sh local
uv run pytest server_integration_test.py -s --junitxml=pytest-report.xml
"""
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

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

The usage string references server_integration_test.py, but this file is server_test.py (and there’s no server_integration_test.py in the repo). Update the docstring so the command matches the actual filename to avoid confusing users/CI scripts.

Copilot uses AI. Check for mistakes.
Comment on lines +151 to +174
async def _read_channel_messages() -> list[dict]:
"""Read the most recent message from the dedicated test channel."""
async with httpx.AsyncClient(timeout=10.0) as client:
resp = await client.get(
"https://slack.com/api/conversations.history",
params={
"channel": CHANNEL_ID,
"limit": 1,
},
headers={"Authorization": f"Bearer {BOT_TOKEN}"},
)
resp.raise_for_status()
data = resp.json()

print(
f"conversations.history response: ok={data.get('ok')}, "
f"messages={len(data.get('messages', []))}, "
f"error={data.get('error', 'none')}"
)

if not data.get("ok"):
raise RuntimeError(f"Slack API error: {data.get('error', 'unknown')}")

return data.get("messages", [])
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

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

conversations.history is queried with limit: 1, and the test assumes the most recent channel message is the acknowledgment from this run. If any other message is posted to the channel (human, another test, Slack system message), the test can read/update/delete the wrong message and become flaky. Consider fetching a larger window (e.g., 10–50 messages) and selecting the message by a unique marker (uuid/run id) included in the webhook/ack text, or by timestamp >= test start time.

Copilot uses AI. Check for mistakes.
Copilot AI review requested due to automatic review settings March 2, 2026 17:50
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 43 out of 49 changed files in this pull request and generated 12 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

failed_files = await self._process_attachments(activity.attachments, requests)
if failed_files:
await turn_context.send_activity(
f"Sorry {user_name}, I could not download the following files: {', '.join(failed_files)}. Please try again."
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

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

The block returns failed_files + rejected_files + oversized_files, but the user-facing message in _handle_teams_message says they "could not download" all of them. Rejected (audio/video) and oversized files aren’t download failures, so the error text should distinguish these cases (or return structured categories instead of a single list).

Suggested change
f"Sorry {user_name}, I could not download the following files: {', '.join(failed_files)}. Please try again."
f"Sorry {user_name}, I could not use the following files (they may be unsupported types, too large, or failed to download): {', '.join(failed_files)}. Please try again."

Copilot uses AI. Check for mistakes.
@@ -0,0 +1,301 @@
import base64
import io
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

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

io is imported but never used in this module.

Suggested change
import io

Copilot uses AI. Check for mistakes.
Comment on lines +17 to +20
Usage:
cd examples/api/slack && ./build.sh local
uv run pytest server_integration_test.py -s --junitxml=pytest-report.xml
"""
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

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

The usage instructions reference server_integration_test.py, but this repository only contains server_test.py. This makes the copy/paste instructions incorrect.

Copilot uses AI. Check for mistakes.
Comment on lines 1 to 3
import asyncio
import json
import os
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

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

json is imported but never used (the code calls request.json(), which doesn’t require the stdlib json module). Please remove the unused import to avoid lint/test failures in stricter environments.

Copilot uses AI. Check for mistakes.
Comment on lines 1 to 3
import asyncio
import json
import os
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

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

json is imported but never used (the code calls request.json(), which doesn’t require the stdlib json module). Please remove the unused import to avoid lint/test failures in stricter environments.

Copilot uses AI. Check for mistakes.
Comment on lines +316 to +321
import os

base_url_env = os.environ.get("AK_WHATSAPP__API_BASE_URL", "").strip()
if not base_url_env:
base_url_env = Config.get().whatsapp.api_base_url
base_url = f"{base_url_env}/{self._api_version}"
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

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

self._base_url is computed in __init__ from AK_WHATSAPP__API_BASE_URL but _send_message() recomputes a separate base_url (and strips whitespace) instead of using self._base_url. This can lead to inconsistent behavior where media downloads / mark-as-read use self._base_url while sending messages uses the recomputed URL (especially if the env var has whitespace or a trailing slash). Consider normalizing the base URL once in __init__ (strip + rstrip('/')) and reusing it everywhere.

Suggested change
import os
base_url_env = os.environ.get("AK_WHATSAPP__API_BASE_URL", "").strip()
if not base_url_env:
base_url_env = Config.get().whatsapp.api_base_url
base_url = f"{base_url_env}/{self._api_version}"
# Use the base URL configured on initialization to ensure consistency
base_url = f"{self._base_url.strip().rstrip('/')}/{self._api_version}"

Copilot uses AI. Check for mistakes.
Comment on lines +52 to +56
```bash
export AK_MULTIMODAL__ENABLED=true # Enable multimodal support (default: false)
export AK_MULTIMODAL__MAX_ATTACHMENTS=5 # Keep last N files in session (default: 5)
export AK_MULTIMODAL__ATTACHMENT_TTL=604800 # File lifetime in seconds (default: 604800 = 1 week)
```
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

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

The docs list AK_MULTIMODAL__ATTACHMENT_TTL and state defaults for AK_MULTIMODAL__MAX_ATTACHMENTS, but the current config model only defines multimodal.max_attachments (default 20) and there is no TTL setting/implementation in the code. Either implement TTL + align defaults, or update this block to reflect the actual supported configuration.

Copilot uses AI. Check for mistakes.
Comment on lines +40 to +44
```bash
export AK_MULTIMODAL__ENABLED=true # Enable multimodal support (default: false)
export AK_MULTIMODAL__MAX_ATTACHMENTS=5 # Keep last N files in session (default: 5)
export AK_MULTIMODAL__ATTACHMENT_TTL=604800 # File lifetime in seconds (default: 604800 = 1 week)
```
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

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

This README documents AK_MULTIMODAL__ATTACHMENT_TTL and claims AK_MULTIMODAL__MAX_ATTACHMENTS defaults to 5, but the current Agent Kernel config only supports multimodal.max_attachments (default 20) and has no TTL setting. Please update the README to match the implemented config, or add the missing config fields + TTL behavior.

Copilot uses AI. Check for mistakes.
2. **Messaging endpoint**: Enter your server's public URL + `/teams/messages`.
* Example: `https://your-server.com/teams/messages`
3. Click **Apply**.
4. Go to **Channels** and add **Microsoft Teams**. accepting the terms.
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

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

Grammar: "Go to Channels and add Microsoft Teams. accepting the terms." should be a complete sentence (e.g., "..., accepting the terms" or "... and add ..., accepting the terms").

Copilot uses AI. Check for mistakes.
Comment on lines 60 to +99
class _APIConfig(BaseModel):
host: str = Field(default="0.0.0.0", description="API host")
port: int = Field(default=8000, description="API port")
enabled_routes: _RoutesConfig = Field(description="API route flags", default_factory=_RoutesConfig)
custom_router_prefix: str = Field(default="/custom", description="Custom router prefix")
max_file_size: int = Field(default=2097152, description="Maximum file size in bytes (default: 2 MB)")
max_file_size: int = Field(default=20971520, description="Maximum file size in bytes (default: 20 MB)")


class _A2AConfig(BaseModel):
enabled: bool = Field(default=False, description="Enable A2A")
agents: List[str] = Field(default=["*"], description="List of agent names to enable A2A")
url: str = Field(default="http://localhost:8000/a2a", description="A2A URL")
task_store_type: str = Field(default="in_memory", pattern="^(in_memory|redis)$")


class _MCPConfig(BaseModel):
enabled: bool = Field(default=False, description="Enable MCP")
expose_agents: bool = Field(default=False, description="Expose agents as MCP tools")
agents: List[str] = Field(default=["*"], description="List of agent names to expose as MCP tool")
url: str = Field(default="http://localhost:8000/mcp", description="MCP URL")


class _SlackConfig(BaseModel):
agent: str = Field(default="", description="Default agent to use for Slack interactions")
agent_acknowledgement: str = Field(
default="",
description="The message to send as an acknowledgement when a Slack message is received",
)
test_mode: bool = Field(default=False, description="Enable test mode for Slack integration")


class _TeamsConfig(BaseModel):
agent: str = Field(default="", description="Default agent to use for Microsoft Teams interactions")
agent_acknowledgement: str = Field(
default="",
description="The message to send as an acknowledgement when a Teams message is received",
)
app_id: str = Field(default="", description="Microsoft App ID (Application/Client ID) from Azure AD App Registration")
app_password: str = Field(default="", description="Microsoft App Password (Client Secret) from Azure AD App Registration")
tenant_id: str = Field(default="", description="Optional Tenant ID for Single Tenant App registration")
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

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

PR description frames this as a Slack/Telegram integration test/refactor, but this change set also introduces new public config surface (teams, multimodal, slack.test_mode) and changes defaults like api.max_file_size (2MB -> 20MB). Please update the PR description/type-of-change checklist to reflect these functional additions, since they impact library behavior beyond tests.

Copilot uses AI. Check for mistakes.
Copilot AI review requested due to automatic review settings March 2, 2026 19:03
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 47 out of 54 changed files in this pull request and generated 3 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +39 to +42
import os

base_url_env = os.getenv("AK_WHATSAPP__API_BASE_URL")
self._base_url = f"{base_url_env or Config.get().whatsapp.api_base_url}/{self._api_version}"
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

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

AK_WHATSAPP__API_BASE_URL is being read directly via os.getenv() inside __init__, even though api_base_url is now a first-class config field (Config.get().whatsapp.api_base_url) and will already be populated from the same env var by the settings layer. This duplication also makes precedence/whitespace handling inconsistent (here the env var isn’t .strip()ed). Consider relying on Config.get().whatsapp.api_base_url only (and normalizing it once) and removing the inline import os.

Copilot uses AI. Check for mistakes.
Comment on lines +316 to 323
import os

base_url_env = os.environ.get("AK_WHATSAPP__API_BASE_URL", "").strip()
if not base_url_env:
base_url_env = Config.get().whatsapp.api_base_url
base_url = f"{base_url_env}/{self._api_version}"
url = f"{base_url}/{self._phone_number_id}/messages"

Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

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

_send_message() re-reads AK_WHATSAPP__API_BASE_URL and recomputes the base URL even though self._base_url was already constructed in __init__. This duplication makes it easy for the handler to use different base URLs in different code paths (and it adds another inline import os). Consider computing/normalizing the base URL once (in config or __init__) and reusing that value here.

Suggested change
import os
base_url_env = os.environ.get("AK_WHATSAPP__API_BASE_URL", "").strip()
if not base_url_env:
base_url_env = Config.get().whatsapp.api_base_url
base_url = f"{base_url_env}/{self._api_version}"
url = f"{base_url}/{self._phone_number_id}/messages"
url = f"{self._base_url}/{self._phone_number_id}/messages"

Copilot uses AI. Check for mistakes.
Comment on lines +37 to 38
_system_pre_hooks: list = [MultimodalPreHookFactory.get(), InputGuardrailFactory.get()]
_system_post_hooks: list = [OutputGuardrailFactory.get()]
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

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

_system_pre_hooks is initialized at import/class-definition time via MultimodalPreHookFactory.get(). If multimodal is enabled/disabled via env/config after import (or in tests that monkeypatch config), this list will keep the originally-created hook (often the NoOp hook), so multimodal pre-processing may never run. Consider instantiating the multimodal hook inside Runtime.__init__ (or always registering MultimodalPreHook and letting it check config in on_run) instead of freezing it as a class-level value.

Copilot uses AI. Check for mistakes.
Copilot AI review requested due to automatic review settings March 3, 2026 11:14
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 49 out of 56 changed files in this pull request and generated 5 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +153 to +156
service = get_gmail_service()
if not service:
pytest.skip(f"Valid token.pickle not found at {TOKEN_FILE}. Cannot run real Gmail test.")

Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

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

get_gmail_service() can return None for reasons other than a missing token.pickle (e.g., missing AK_GMAIL__CLIENT_ID/AK_GMAIL__CLIENT_SECRET), but the skip reason here always claims the token file is missing. Consider returning a more specific error/enum from get_gmail_service() or updating the skip message to cover all None cases.

Copilot uses AI. Check for mistakes.
@@ -0,0 +1,301 @@
import base64
import io
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

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

io is imported but never used in this module. Please remove the unused import to avoid lint/test failures in stricter environments.

Suggested change
import io

Copilot uses AI. Check for mistakes.
2. **Messaging endpoint**: Enter your server's public URL + `/teams/messages`.
* Example: `https://your-server.com/teams/messages`
3. Click **Apply**.
4. Go to **Channels** and add **Microsoft Teams**. accepting the terms.
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

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

Grammar: "add Microsoft Teams. accepting the terms." should be a complete sentence (e.g., "...and add Microsoft Teams, accepting the terms.").

Copilot uses AI. Check for mistakes.
Comment on lines 1 to 3
import asyncio
import json
import os
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

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

json is imported but not used in this test module. Please remove the unused import to keep the integration test tidy.

Copilot uses AI. Check for mistakes.
Comment on lines +425 to +426
if config and config.enabled:
self.override_system_prompt(session=None, prompt=self.get_system_prompt_suffix())
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

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

override_system_prompt is declared to require a Session, but _setup_system_prompt() calls it with session=None. This is inconsistent with the abstract method contract and may break implementations that assume a real session. Consider typing the parameter as Session | None (and updating implementations) or refactor init-time prompt injection to not require a session object.

Suggested change
if config and config.enabled:
self.override_system_prompt(session=None, prompt=self.get_system_prompt_suffix())
session = getattr(self, "session", None)
if config and config.enabled and session is not None:
self.override_system_prompt(session=session, prompt=self.get_system_prompt_suffix())

Copilot uses AI. Check for mistakes.
Copilot AI review requested due to automatic review settings March 3, 2026 12:43
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 50 out of 57 changed files in this pull request and generated 1 comment.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +155 to +158
await turn_context.send_activity(
f"Sorry {user_name}, I could not download the following files: {', '.join(failed_files)}. Please try again."
)
return
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

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

_process_attachments() returns a combined list of (download failures + rejected audio/video + oversized files), but the caller treats this purely as “could not download” and aborts the whole request. Consider returning a structured result (e.g., separate lists for failed/rejected/oversized) so you can send an accurate user message (and potentially still proceed when only some attachments are rejected).

Suggested change
await turn_context.send_activity(
f"Sorry {user_name}, I could not download the following files: {', '.join(failed_files)}. Please try again."
)
return
# Some attachments could not be used (e.g., failed download, rejected type, or oversized),
# but we can still proceed with the rest of the request.
await turn_context.send_activity(
f"Sorry {user_name}, I could not process the following files and will continue without them: {', '.join(failed_files)}."
)

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Write proper e2e test for the slack example code

4 participants