{"id":47594481,"url":"https://github.com/legionio/lex-microsoft_teams","last_synced_at":"2026-05-30T06:03:27.869Z","repository":{"id":344339220,"uuid":"1181435803","full_name":"LegionIO/lex-microsoft_teams","owner":"LegionIO","description":"Connects LegionIO to Microsoft Teams via Graph API and Bot Framework","archived":false,"fork":false,"pushed_at":"2026-04-09T19:20:46.000Z","size":490,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-09T21:26:02.286Z","etag":null,"topics":["bot-framework","graph-api","legionio","lex","microsoft-teams","ruby"],"latest_commit_sha":null,"homepage":null,"language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/LegionIO.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-14T06:08:42.000Z","updated_at":"2026-04-09T19:20:09.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/LegionIO/lex-microsoft_teams","commit_stats":null,"previous_names":["legionio/lex-microsoft_teams"],"tags_count":36,"template":false,"template_full_name":null,"purl":"pkg:github/LegionIO/lex-microsoft_teams","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LegionIO%2Flex-microsoft_teams","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LegionIO%2Flex-microsoft_teams/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LegionIO%2Flex-microsoft_teams/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LegionIO%2Flex-microsoft_teams/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/LegionIO","download_url":"https://codeload.github.com/LegionIO/lex-microsoft_teams/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LegionIO%2Flex-microsoft_teams/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32148180,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-22T17:06:48.269Z","status":"ssl_error","status_checked_at":"2026-04-22T17:06:19.037Z","response_time":58,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bot-framework","graph-api","legionio","lex","microsoft-teams","ruby"],"created_at":"2026-04-01T17:56:33.268Z","updated_at":"2026-04-22T18:01:17.074Z","avatar_url":"https://github.com/LegionIO.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"# lex-microsoft_teams\n\nMicrosoft Teams integration for [LegionIO](https://github.com/LegionIO/LegionIO). Connects to Microsoft Teams via Graph API and Bot Framework for chat, channel, and bot communication.\n\n## Installation\n\n```bash\ngem install lex-microsoft_teams\n```\n\n## Functions\n\n### Auth\n- `acquire_token` — OAuth2 client credentials token for Graph API\n- `acquire_bot_token` — OAuth2 token for Bot Framework\n- `authorize_url` — Build Authorization Code + PKCE authorize URL for delegated consent\n- `exchange_code` — Exchange authorization code for delegated access/refresh tokens\n- `refresh_delegated_token` — Refresh a delegated token using a refresh token\n- `request_device_code` — Start Device Code flow (headless fallback)\n- `poll_device_code` — Poll for Device Code completion (RFC 8628 compliant)\n\n### Teams\n- `list_joined_teams` — List teams the user has joined\n- `get_team` — Get team details\n- `list_team_members` — List members of a team\n\n### Chats\n- `list_chats` — List 1:1 and group chats\n- `get_chat` — Get chat details\n- `create_chat` — Create a new chat\n- `list_chat_members` — List chat participants\n- `add_chat_member` — Add a member to a chat\n\n### Messages\n- `list_chat_messages` — List messages in a chat\n- `get_chat_message` — Get a specific message\n- `send_chat_message` — Send a message to a chat\n- `reply_to_chat_message` — Reply to a message\n- `list_message_replies` — List replies to a message\n\n### Channels\n- `list_channels` — List channels in a team\n- `get_channel` — Get channel details\n- `create_channel` — Create a new channel\n- `update_channel` — Update channel properties\n- `delete_channel` — Delete a channel\n- `list_channel_members` — List channel members\n\n### Channel Messages\n- `list_channel_messages` — List messages in a channel\n- `get_channel_message` — Get a specific channel message\n- `send_channel_message` — Send a message to a channel\n- `reply_to_channel_message` — Reply to a channel message\n- `list_channel_message_replies` — List replies to a channel message\n\n### Meetings\n- `list_meetings` — List online meetings for a user\n- `get_meeting` — Get meeting details\n- `create_meeting` — Create an online meeting\n- `update_meeting` — Update meeting properties\n- `delete_meeting` — Delete a meeting\n- `get_meeting_by_join_url` — Find a meeting by its join URL\n- `list_attendance_reports` — List attendance reports for a meeting\n- `get_attendance_report` — Get a specific attendance report with attendee records\n\n### Transcripts\n- `list_transcripts` — List available transcripts for a meeting\n- `get_transcript` — Get transcript metadata\n- `get_transcript_content` — Get transcript content (VTT default, DOCX optional via `format:` param)\n\n### Presence\n- `get_presence` — Get the availability and activity status for a user\n\n### Subscriptions (Change Notifications)\n- `list_subscriptions` — List active subscriptions\n- `get_subscription` — Get subscription details\n- `create_subscription` — Create a change notification subscription\n- `renew_subscription` — Extend subscription expiration\n- `delete_subscription` — Delete a subscription\n- `subscribe_to_chat_messages` — Subscribe to chat message events\n- `subscribe_to_channel_messages` — Subscribe to channel message events\n\n### Local Cache (Offline)\n- `extract_local_messages` — Extract messages from the Teams 2.x LevelDB local storage without Graph API credentials\n- `local_cache_available?` — Check whether the local Teams cache exists on disk\n- `local_cache_stats` — Get message count and date range stats from the local cache without extracting\n\n### Cache Ingest\n- `ingest_cache` — Ingest messages from the local Teams cache into lex-memory as episodic traces; returns `{ stored:, skipped:, latest_time: }`\n\n### People\n- `get_profile` — Get Graph API profile for a user (default: `/me`)\n- `list_people` — List relevant people for a user via `/me/people`\n\n### AI Insights\n- `list_meeting_ai_insights` — List AI-generated insights for an online meeting\n- `get_meeting_ai_insight` — Get a specific AI insight\n- `list_meeting_recordings` — List recordings for an online meeting\n- `get_meeting_recording` — Get a specific meeting recording\n- `list_call_records` — List call records from Graph API\n- `get_call_record` — Get a specific call record\n\n### Ownership\n- `sync_owners` — Sync team ownership data from Graph API (single team or all teams)\n- `detect_orphans` — Detect teams with no current owners\n- `get_team_owners` — Get owners for a specific team\n\n### Adaptive Cards\n- `build_card` — Build an Adaptive Card payload\n- `text_block` — Create a TextBlock element\n- `fact_set` — Create a FactSet element\n- `action_open_url` — Create an OpenUrl action\n- `action_submit` — Create a Submit action\n- `message_attachment` — Wrap a card as a message attachment\n\n### Loop Components\n- `create_loop_file` — Create a new `.loop` file in a user's OneDrive; returns drive item metadata including `webUrl`\n- `loop_attachment` — Build a `fluidEmbedCard` attachment array for embedding an existing Loop component URL in a Teams message\n- `post_loop_to_chat` — Post a Loop component inline into a Teams chat thread\n- `post_loop_to_channel` — Post a Loop component inline into a Teams channel thread\n\n\u003e **Note:** Creating a `.loop` file provisions the OneDrive item; the Fluid Framework collaborative session is initialized by Teams on first open. Programmatic write access to Loop page *content* is not yet available via Microsoft Graph.\n\n### Bot Framework\n- `send_activity` — Send an activity to a conversation\n- `reply_to_activity` — Reply to an existing activity\n- `send_text` — Send a simple text message via bot\n- `send_card` — Send an Adaptive Card via bot\n- `create_conversation` — Create a new bot conversation\n- `get_conversation_members` — List conversation members\n\n### AI Bot (v0.2.0)\n- `handle_message` — LLM-powered response loop for direct 1:1 bot chats (polls Graph API, replies via Graph or Bot Framework)\n- `observe_message` — Conversation observer that extracts tasks, context, and relationship data from subscribed human chats (disabled by default, compliance-gated)\n\n**Actors:**\n- `CacheBulkIngest` — Once at startup: full local LevelDB cache ingest\n- `CacheSync` — Every 5min: incremental new-message ingest from local cache\n- `DirectChatPoller` — Every 5s: polls bot DM chats via Graph API, publishes to AMQP\n- `ObservedChatPoller` — Every 30s: polls subscribed conversations (compliance-gated, disabled by default)\n- `MessageProcessor` — AMQP subscription actor, routes messages by mode\n- `AuthValidator` — Once at boot: validates and restores delegated tokens\n- `TokenRefresher` — Every 15min: keeps delegated tokens fresh\n- `ProfileIngest` — Once (5s delay): four-phase cognitive data pipeline after auth\n- `ApiIngest` — Every 30min: Graph API ingest with HWM dedup\n- `ChannelPoller` — Every 60s: polls joined team channels for new messages\n- `MeetingIngest` — Every 5min: polls online meetings, fetches transcripts and AI insights\n- `PresencePoller` — Every 60s: polls Graph API presence, logs changes\n- `AbsorbMeeting` — Subscription: absorbs Teams meeting data via absorber framework\n- `IncrementalSync` — Every 15min: periodic re-sync with HWM dedup\n\n**Helpers:**\n- `SessionManager` — Multi-turn LLM session lifecycle with lex-memory persistence\n- `PromptResolver` — Layered system prompt resolution (settings default -\u003e mode -\u003e per-conversation -\u003e trace context)\n- `HighWaterMark` — Per-chat message deduplication via legion-cache\n- `TokenCache` — In-memory OAuth token cache with pre-expiry refresh (app + delegated slots)\n- `SubscriptionRegistry` — Conversation observation subscriptions (in-memory + lex-memory)\n- `BrowserAuth` — Delegated OAuth orchestrator (PKCE, headless detection, browser launch)\n- `CallbackServer` — Ephemeral TCP server for OAuth redirect callback\n- `TraceRetriever` — Retrieves and formats memory traces as LLM context (2000-token budget, strength-ranked dedup)\n\n### Delegated Authentication (v0.5.0)\n\nOpt-in browser-based OAuth for delegated Microsoft Graph permissions (e.g., meeting transcripts).\n\n**Authorization Code + PKCE** (primary): Opens the user's browser for Entra ID login, captures the callback on an ephemeral local port, exchanges the code with PKCE verification.\n\n**Device Code** (fallback): Automatically selected in headless/SSH environments (no `DISPLAY`/`WAYLAND_DISPLAY`). Displays a URL and code for the user to enter on any device.\n\n```ruby\n# Via CLI\n# legion auth teams --tenant-id TENANT --client-id CLIENT\n\n# Via code\nauth = Legion::Extensions::MicrosoftTeams::Helpers::BrowserAuth.new(\n  tenant_id: 'your-tenant-id',\n  client_id: 'your-client-id'\n)\nresult = auth.authenticate  # returns token hash with access_token, refresh_token, expires_in\n```\n\nTokens are stored in Vault at a per-user path (`{USER}/microsoft_teams/delegated_token`) and silently refreshed before expiry.\n\n## Standalone Client\n\nThe `Client` class includes all runner modules (Auth, Teams, Chats, Messages, Channels, ChannelMessages, Subscriptions, AdaptiveCards, Bot, Presence, Meetings, Transcripts, LocalCache, CacheIngest, People, ProfileIngest, ApiIngest, AiInsights, Ownership).\n\n```ruby\nclient = Legion::Extensions::MicrosoftTeams::Client.new(\n  tenant_id:     'your-tenant-id',\n  client_id:     'your-app-id',\n  client_secret: 'your-client-secret'\n)\nclient.authenticate!\n\n# Graph API\nclient.list_chats\nclient.send_chat_message(chat_id: 'chat-id', content: 'Hello!')\n\n# Bot Framework\nclient.send_text(\n  service_url: 'https://smba.trafficmanager.net/teams/',\n  conversation_id: 'conv-id',\n  text: 'Hello from bot'\n)\n\n# Local cache (no credentials needed)\nclient.local_cache_available?\nclient.extract_local_messages(since: Time.now - 86_400)\n```\n\n## Requirements\n\n- Ruby \u003e= 3.4\n- [LegionIO](https://github.com/LegionIO/LegionIO) framework\n- Microsoft Entra ID application with appropriate Graph API permissions\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flegionio%2Flex-microsoft_teams","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flegionio%2Flex-microsoft_teams","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flegionio%2Flex-microsoft_teams/lists"}