lex-microsoft_teams 0.6.26 → 0.6.28
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.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +3 -3
- data/.rubocop.yml +11 -49
- data/CHANGELOG.md +24 -0
- data/CLAUDE.md +15 -6
- data/Gemfile +2 -1
- data/lib/legion/extensions/microsoft_teams/absorbers/meeting.rb +1 -1
- data/lib/legion/extensions/microsoft_teams/actors/api_ingest.rb +7 -1
- data/lib/legion/extensions/microsoft_teams/actors/auth_validator.rb +6 -3
- data/lib/legion/extensions/microsoft_teams/actors/channel_poller.rb +1 -1
- data/lib/legion/extensions/microsoft_teams/actors/direct_chat_poller.rb +1 -1
- data/lib/legion/extensions/microsoft_teams/actors/incremental_sync.rb +1 -1
- data/lib/legion/extensions/microsoft_teams/actors/message_processor.rb +1 -1
- data/lib/legion/extensions/microsoft_teams/actors/observed_chat_poller.rb +1 -1
- data/lib/legion/extensions/microsoft_teams/actors/profile_ingest.rb +7 -1
- data/lib/legion/extensions/microsoft_teams/actors/token_refresher.rb +8 -1
- data/lib/legion/extensions/microsoft_teams/helpers/browser_auth.rb +2 -2
- data/lib/legion/extensions/microsoft_teams/helpers/callback_server.rb +2 -2
- data/lib/legion/extensions/microsoft_teams/helpers/high_water_mark.rb +6 -6
- data/lib/legion/extensions/microsoft_teams/helpers/subscription_registry.rb +2 -1
- data/lib/legion/extensions/microsoft_teams/helpers/token_cache.rb +12 -6
- data/lib/legion/extensions/microsoft_teams/helpers/trace_retriever.rb +4 -2
- data/lib/legion/extensions/microsoft_teams/hooks/auth.rb +1 -1
- data/lib/legion/extensions/microsoft_teams/local_cache/sstable_reader.rb +3 -3
- data/lib/legion/extensions/microsoft_teams/runners/api_ingest.rb +1 -1
- data/lib/legion/extensions/microsoft_teams/runners/bot.rb +1 -1
- data/lib/legion/extensions/microsoft_teams/runners/profile_ingest.rb +3 -3
- data/lib/legion/extensions/microsoft_teams/version.rb +1 -1
- data/lib/legion/extensions/microsoft_teams.rb +2 -2
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 2635c7d3e8d564623f365709464ce8b8e20bb84e535c20d6a268d2419cf816cc
|
|
4
|
+
data.tar.gz: e3886e4a92ab9e885d48308d2657fea15d9a853d6be25ca56a4083033a50cba6
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 159525c1fbf00aa64cdd5ce9b992b2210dbd1077382c8a51ba188be8670139c7b393612f10401ab88f457d24ab3b998890f9ca4c972a104873c78ce428d0d010
|
|
7
|
+
data.tar.gz: 6d1110df11e58b20a3f518f0df2bbd6788cc351408b247010a7039666fde2ed46754153e4ffc20381c426417b291d42381b13157589bcdaf0ea931ab3b5fd353
|
data/.github/workflows/ci.yml
CHANGED
|
@@ -10,8 +10,8 @@ jobs:
|
|
|
10
10
|
ci:
|
|
11
11
|
uses: LegionIO/.github/.github/workflows/ci.yml@main
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
uses: LegionIO/.github/.github/workflows/
|
|
13
|
+
excluded-files:
|
|
14
|
+
uses: LegionIO/.github/.github/workflows/excluded-files.yml@main
|
|
15
15
|
|
|
16
16
|
security:
|
|
17
17
|
uses: LegionIO/.github/.github/workflows/security-scan.yml@main
|
|
@@ -27,7 +27,7 @@ jobs:
|
|
|
27
27
|
uses: LegionIO/.github/.github/workflows/stale.yml@main
|
|
28
28
|
|
|
29
29
|
release:
|
|
30
|
-
needs: [ci,
|
|
30
|
+
needs: [ci, excluded-files]
|
|
31
31
|
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
|
32
32
|
uses: LegionIO/.github/.github/workflows/release.yml@main
|
|
33
33
|
secrets:
|
data/.rubocop.yml
CHANGED
|
@@ -1,56 +1,18 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
NewCops: enable
|
|
4
|
-
SuggestExtensions: false
|
|
1
|
+
inherit_gem:
|
|
2
|
+
rubocop-legion: config/lex.yml
|
|
5
3
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
Layout/SpaceAroundEqualsInParameterDefault:
|
|
10
|
-
EnforcedStyle: space
|
|
11
|
-
|
|
12
|
-
Layout/HashAlignment:
|
|
13
|
-
EnforcedHashRocketStyle: table
|
|
14
|
-
EnforcedColonStyle: table
|
|
15
|
-
|
|
16
|
-
Metrics/MethodLength:
|
|
17
|
-
Max: 50
|
|
18
|
-
|
|
19
|
-
Metrics/ClassLength:
|
|
20
|
-
Max: 1500
|
|
21
|
-
|
|
22
|
-
Metrics/ModuleLength:
|
|
23
|
-
Max: 1500
|
|
24
|
-
|
|
25
|
-
Metrics/BlockLength:
|
|
26
|
-
Max: 40
|
|
27
|
-
Exclude:
|
|
28
|
-
- 'spec/**/*'
|
|
29
|
-
|
|
30
|
-
Metrics/ParameterLists:
|
|
31
|
-
Max: 8
|
|
32
|
-
|
|
33
|
-
Metrics/AbcSize:
|
|
34
|
-
Max: 60
|
|
35
|
-
|
|
36
|
-
Metrics/CyclomaticComplexity:
|
|
37
|
-
Max: 15
|
|
38
|
-
|
|
39
|
-
Metrics/PerceivedComplexity:
|
|
40
|
-
Max: 17
|
|
41
|
-
|
|
42
|
-
Style/Documentation:
|
|
4
|
+
# This repo uses Faraday JSON middleware (string keys), not Legion::JSON.load (symbol keys)
|
|
5
|
+
Legion/Framework/ApiStringKeys:
|
|
43
6
|
Enabled: false
|
|
44
7
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
Style/FrozenStringLiteralComment:
|
|
49
|
-
Enabled: true
|
|
50
|
-
EnforcedStyle: always
|
|
8
|
+
# All actors in this extension define `enabled?` with cheap settings/defined? checks only
|
|
9
|
+
Legion/Extension/ActorEnabledSideEffects:
|
|
10
|
+
Enabled: false
|
|
51
11
|
|
|
52
|
-
|
|
12
|
+
# Every actors define `def time` as an instance method override, not via class-level DSL call
|
|
13
|
+
Legion/Extension/EveryActorRequiresTime:
|
|
53
14
|
Enabled: false
|
|
54
15
|
|
|
55
|
-
|
|
16
|
+
# RunnerReturnHash fires on private helper methods inside runner modules (false positives)
|
|
17
|
+
Legion/Extension/RunnerReturnHash:
|
|
56
18
|
Enabled: false
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,30 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [0.6.28] - 2026-03-30
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
- `teams_auth_settings` in AuthValidator, TokenRefresher, and TokenCache now falls back to parent `[:microsoft_teams][:tenant_id]`/`[:client_id]` when not found under `[:auth]`, fixing browser auth never triggering when config uses top-level keys
|
|
9
|
+
- `TokenCache#teams_auth_settings` now includes ENV fallback for `AZURE_TENANT_ID`/`AZURE_CLIENT_ID` (previously missing, inconsistent with actor implementations) and parent-level `client_secret` fallback
|
|
10
|
+
- Silent rescue blocks in TraceRetriever (`format_single_trace`, `trace_age_label`), SubscriptionRegistry (`parse_stored`), and ProfileIngest runner (`ingest_self` presence fetch) now log errors instead of swallowing them
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
- AuthValidator actor delay increased from 2s to 90s to allow Vault, transport, cache, and delegated auth to fully initialize before validation runs
|
|
14
|
+
- ProfileIngest actor delay increased from 5s to 95s to fire after AuthValidator completes (Once actor — no retry if token missing)
|
|
15
|
+
- ApiIngest actor delay increased from 10s to 95s to fire after AuthValidator completes delegated auth
|
|
16
|
+
- CLAUDE.md updated: added 5 undocumented actors (AbsorbMeeting, ApiIngest, ChannelPoller, MeetingIngest, PresencePoller), 3 runners (AiInsights, ApiIngest, Ownership), 1 helper (GraphClient), corrected spec counts
|
|
17
|
+
|
|
18
|
+
## [0.6.27] - 2026-03-29
|
|
19
|
+
|
|
20
|
+
### Changed
|
|
21
|
+
- Update to rubocop-legion 0.1.7 — resolve all 63 offenses
|
|
22
|
+
- Replace `defined?(Legion::Transport)` with `Legion.const_defined?(:Transport, false)` across 4 files
|
|
23
|
+
- Fix `llm_ask` call in `ProfileIngest` to use `message:` keyword (was `prompt:` + `caller:`)
|
|
24
|
+
- Add rescue variable captures (`=> _e`) for 5 rescue-logging offenses
|
|
25
|
+
- Add inline rubocop disables for 4 structural false positives
|
|
26
|
+
- Disable 3 cops in `.rubocop.yml` that produce systematic false positives
|
|
27
|
+
- Auto-correct Layout/ArgumentAlignment and Performance cops via rubocop -A
|
|
28
|
+
|
|
5
29
|
## [0.6.26] - 2026-03-29
|
|
6
30
|
|
|
7
31
|
### Fixed
|
data/CLAUDE.md
CHANGED
|
@@ -10,7 +10,7 @@ Legion Extension that connects LegionIO to Microsoft Teams via Graph API and Bot
|
|
|
10
10
|
|
|
11
11
|
**GitHub**: https://github.com/LegionIO/lex-microsoft_teams
|
|
12
12
|
**License**: MIT
|
|
13
|
-
**Version**: 0.6.
|
|
13
|
+
**Version**: 0.6.28
|
|
14
14
|
|
|
15
15
|
## Architecture
|
|
16
16
|
|
|
@@ -32,16 +32,24 @@ Legion::Extensions::MicrosoftTeams
|
|
|
32
32
|
│ ├── LocalCache # Offline message extraction from local LevelDB cache
|
|
33
33
|
│ ├── CacheIngest # Ingest cached messages into lex-memory as episodic traces
|
|
34
34
|
│ ├── People # Graph API /me and /me/people (profile + relevant contacts)
|
|
35
|
-
│
|
|
35
|
+
│ ├── ProfileIngest # Four-phase cognitive pipeline (self, people, conversations, teams/meetings)
|
|
36
|
+
│ ├── ApiIngest # Graph API ingest (top contacts, 1:1 chat messages, HWM dedup)
|
|
37
|
+
│ ├── AiInsights # Graph API meeting AI insights, recordings, call records
|
|
38
|
+
│ └── Ownership # Graph API ownership sync
|
|
36
39
|
├── Actors/
|
|
37
40
|
│ ├── CacheBulkIngest # Once: full cache ingest at startup (imprint window support)
|
|
38
41
|
│ ├── CacheSync # Every 5min: incremental ingest of new messages
|
|
39
42
|
│ ├── DirectChatPoller # Every 5s: polls bot DM chats via Graph API
|
|
40
43
|
│ ├── ObservedChatPoller # Every 30s: polls subscribed human conversations (compliance-gated)
|
|
41
44
|
│ ├── MessageProcessor # Subscription: consumes AMQP queue, routes by mode
|
|
42
|
-
│ ├── AuthValidator # Once: validates/restores delegated tokens on boot
|
|
45
|
+
│ ├── AuthValidator # Once (90s delay): validates/restores delegated tokens on boot
|
|
43
46
|
│ ├── TokenRefresher # Every 15min (configurable): keeps delegated tokens fresh
|
|
44
|
-
│ ├── ProfileIngest # Once (
|
|
47
|
+
│ ├── ProfileIngest # Once (95s delay): four-phase data pipeline after auth
|
|
48
|
+
│ ├── ApiIngest # Every 30min (95s delay): Graph API ingest with HWM dedup
|
|
49
|
+
│ ├── ChannelPoller # Every 60s: polls joined team channels for new messages
|
|
50
|
+
│ ├── MeetingIngest # Every 5min: polls online meetings, fetches transcripts and AI insights
|
|
51
|
+
│ ├── PresencePoller # Every 60s: polls Graph API presence, logs changes
|
|
52
|
+
│ ├── AbsorbMeeting # Subscription: absorbs Teams meeting data via absorber framework
|
|
45
53
|
│ └── IncrementalSync # Every 15min: periodic re-sync with HWM dedup
|
|
46
54
|
├── Transport/
|
|
47
55
|
│ ├── Exchanges/Messages # teams.messages topic exchange
|
|
@@ -62,7 +70,8 @@ Legion::Extensions::MicrosoftTeams
|
|
|
62
70
|
│ ├── CallbackServer # Ephemeral TCP server for OAuth redirect callback
|
|
63
71
|
│ ├── PermissionGuard # Circuit breaker for 403 errors with exponential backoff
|
|
64
72
|
│ ├── TraceRetriever # Retrieves memory traces from the shared store for bot context (2000-token budget, strength-ranked dedup)
|
|
65
|
-
│
|
|
73
|
+
│ ├── TransformDefinitions # lex-transformer definitions for conversation extraction and person summary
|
|
74
|
+
│ └── GraphClient # Graph API wrapper mixin (graph_get, graph_post, graph_paginate, GraphError)
|
|
66
75
|
├── Hooks/
|
|
67
76
|
│ └── Auth # OAuth callback hook (mount '/callback') → /api/extensions/microsoft_teams/hooks/auth/handle
|
|
68
77
|
├── CLI/
|
|
@@ -255,7 +264,7 @@ Optional framework dependencies (guarded with `defined?`, not in gemspec):
|
|
|
255
264
|
|
|
256
265
|
```bash
|
|
257
266
|
bundle install
|
|
258
|
-
bundle exec rspec # ~
|
|
267
|
+
bundle exec rspec # ~342 specs across 43 spec files (as of v0.6.28)
|
|
259
268
|
bundle exec rubocop # Clean
|
|
260
269
|
```
|
|
261
270
|
|
data/Gemfile
CHANGED
|
@@ -4,7 +4,7 @@ module Legion
|
|
|
4
4
|
module Extensions
|
|
5
5
|
module MicrosoftTeams
|
|
6
6
|
module Absorbers
|
|
7
|
-
class Meeting < Legion::Extensions::Absorbers::Base
|
|
7
|
+
class Meeting < Legion::Extensions::Absorbers::Base # rubocop:disable Legion/Extension/AbsorberMissingAbsorbMethod
|
|
8
8
|
pattern :url, 'teams.microsoft.com/l/meetup-join/*'
|
|
9
9
|
pattern :url, '*.teams.microsoft.com/meet/*'
|
|
10
10
|
description 'Absorbs Teams meeting transcripts, AI insights, and participants into Apollo'
|
|
@@ -18,7 +18,13 @@ module Legion
|
|
|
18
18
|
def run_now? = true
|
|
19
19
|
|
|
20
20
|
def delay
|
|
21
|
-
|
|
21
|
+
if defined?(Legion::Extensions::MicrosoftTeams::Actor::AuthValidator)
|
|
22
|
+
auth_validator = Legion::Extensions::MicrosoftTeams::Actor::AuthValidator.allocate
|
|
23
|
+
base_delay = auth_validator.respond_to?(:delay) ? auth_validator.delay.to_f : 90.0
|
|
24
|
+
base_delay + 5.0 # must fire shortly after AuthValidator completes delegated auth
|
|
25
|
+
else
|
|
26
|
+
95.0 # conservative boot-ordering fallback if AuthValidator is unavailable
|
|
27
|
+
end
|
|
22
28
|
end
|
|
23
29
|
|
|
24
30
|
def time
|
|
@@ -4,13 +4,13 @@ module Legion
|
|
|
4
4
|
module Extensions
|
|
5
5
|
module MicrosoftTeams
|
|
6
6
|
module Actor
|
|
7
|
-
class AuthValidator < Legion::Extensions::Actors::Once
|
|
7
|
+
class AuthValidator < Legion::Extensions::Actors::Once # rubocop:disable Legion/Extension/SelfContainedActorRunnerClass
|
|
8
8
|
def use_runner? = false
|
|
9
9
|
def check_subtask? = false
|
|
10
10
|
def generate_task? = false
|
|
11
11
|
|
|
12
12
|
def delay
|
|
13
|
-
|
|
13
|
+
90.0
|
|
14
14
|
end
|
|
15
15
|
|
|
16
16
|
def enabled?
|
|
@@ -105,7 +105,10 @@ module Legion
|
|
|
105
105
|
def teams_auth_settings
|
|
106
106
|
settings = if defined?(Legion::Settings)
|
|
107
107
|
ms = Legion::Settings[:microsoft_teams]
|
|
108
|
-
|
|
108
|
+
auth = ms && ms[:auth].is_a?(Hash) ? ms[:auth].dup : {}
|
|
109
|
+
auth[:tenant_id] ||= ms[:tenant_id] if ms
|
|
110
|
+
auth[:client_id] ||= ms[:client_id] if ms
|
|
111
|
+
auth
|
|
109
112
|
else
|
|
110
113
|
{}
|
|
111
114
|
end
|
|
@@ -128,7 +128,7 @@ module Legion
|
|
|
128
128
|
store_channel_message_trace(team_name: team_name, channel_name: channel_name, msg: msg) if memory_available?
|
|
129
129
|
end
|
|
130
130
|
|
|
131
|
-
latest = new_msgs.
|
|
131
|
+
latest = new_msgs.filter_map { |m| m['createdDateTime'] }.max
|
|
132
132
|
@channel_hwm[channel_id] = latest if latest
|
|
133
133
|
end
|
|
134
134
|
|
|
@@ -27,7 +27,7 @@ module Legion
|
|
|
27
27
|
|
|
28
28
|
def enabled?
|
|
29
29
|
defined?(Legion::Extensions::MicrosoftTeams::Runners::Bot) &&
|
|
30
|
-
|
|
30
|
+
Legion.const_defined?(:Transport, false)
|
|
31
31
|
rescue StandardError => e
|
|
32
32
|
log.debug("DirectChatPoller#enabled?: #{e.message}")
|
|
33
33
|
false
|
|
@@ -12,7 +12,7 @@ module Legion
|
|
|
12
12
|
|
|
13
13
|
def enabled?
|
|
14
14
|
defined?(Legion::Extensions::MicrosoftTeams::Runners::Bot) &&
|
|
15
|
-
|
|
15
|
+
Legion.const_defined?(:Transport, false)
|
|
16
16
|
rescue StandardError => e
|
|
17
17
|
log.debug("MessageProcessor#enabled?: #{e.message}")
|
|
18
18
|
false
|
|
@@ -26,7 +26,7 @@ module Legion
|
|
|
26
26
|
|
|
27
27
|
def enabled?
|
|
28
28
|
return false unless defined?(Legion::Extensions::MicrosoftTeams::Runners::Bot)
|
|
29
|
-
return false unless
|
|
29
|
+
return false unless Legion.const_defined?(:Transport, false)
|
|
30
30
|
return false unless defined?(Legion::Settings)
|
|
31
31
|
|
|
32
32
|
Legion::Settings.dig(:microsoft_teams, :bot, :observe, :enabled) == true
|
|
@@ -12,7 +12,13 @@ module Legion
|
|
|
12
12
|
def generate_task? = false
|
|
13
13
|
|
|
14
14
|
def delay
|
|
15
|
-
|
|
15
|
+
if defined?(Legion::Extensions::MicrosoftTeams::Actor::AuthValidator)
|
|
16
|
+
auth_validator = Legion::Extensions::MicrosoftTeams::Actor::AuthValidator.allocate
|
|
17
|
+
base_delay = auth_validator.respond_to?(:delay) ? auth_validator.delay.to_f : 90.0
|
|
18
|
+
base_delay + 5.0
|
|
19
|
+
else
|
|
20
|
+
95.0
|
|
21
|
+
end
|
|
16
22
|
end
|
|
17
23
|
|
|
18
24
|
def enabled?
|
|
@@ -100,7 +100,14 @@ module Legion
|
|
|
100
100
|
def teams_auth_settings
|
|
101
101
|
settings = if defined?(Legion::Settings)
|
|
102
102
|
ms = Legion::Settings[:microsoft_teams]
|
|
103
|
-
|
|
103
|
+
auth = if ms && ms[:auth].is_a?(Hash)
|
|
104
|
+
ms[:auth].dup
|
|
105
|
+
else
|
|
106
|
+
{}
|
|
107
|
+
end
|
|
108
|
+
auth[:tenant_id] ||= ms[:tenant_id] if ms
|
|
109
|
+
auth[:client_id] ||= ms[:client_id] if ms
|
|
110
|
+
auth
|
|
104
111
|
else
|
|
105
112
|
{}
|
|
106
113
|
end
|
|
@@ -84,7 +84,7 @@ module Legion
|
|
|
84
84
|
|
|
85
85
|
def gui_available?
|
|
86
86
|
os = host_os
|
|
87
|
-
return true if
|
|
87
|
+
return true if /darwin|mswin|mingw/.match?(os)
|
|
88
88
|
|
|
89
89
|
!ENV['DISPLAY'].nil? || !ENV['WAYLAND_DISPLAY'].nil?
|
|
90
90
|
end
|
|
@@ -107,7 +107,7 @@ module Legion
|
|
|
107
107
|
private
|
|
108
108
|
|
|
109
109
|
def log
|
|
110
|
-
return Legion::Logging if defined?(Legion::Logging)
|
|
110
|
+
return Legion::Logging if defined?(Legion::Logging) # rubocop:disable Legion/HelperMigration/LoggingGuard
|
|
111
111
|
|
|
112
112
|
@log ||= Object.new.tap do |nl|
|
|
113
113
|
%i[debug info warn error fatal].each { |m| nl.define_singleton_method(m) { |*| nil } }
|
|
@@ -26,7 +26,7 @@ module Legion
|
|
|
26
26
|
def start
|
|
27
27
|
@server = TCPServer.new('127.0.0.1', 0)
|
|
28
28
|
@port = @server.addr[1]
|
|
29
|
-
@thread = Thread.new { listen }
|
|
29
|
+
@thread = Thread.new { listen } # rubocop:disable ThreadSafety/NewThread
|
|
30
30
|
end
|
|
31
31
|
|
|
32
32
|
def wait_for_callback(timeout: 120)
|
|
@@ -75,7 +75,7 @@ module Legion
|
|
|
75
75
|
client.close
|
|
76
76
|
break if @result
|
|
77
77
|
end
|
|
78
|
-
rescue IOError
|
|
78
|
+
rescue IOError # rubocop:disable Legion/RescueLogging/NoCapture
|
|
79
79
|
nil # server closed during shutdown
|
|
80
80
|
rescue StandardError => e
|
|
81
81
|
@mutex.synchronize do
|
|
@@ -16,7 +16,7 @@ module Legion
|
|
|
16
16
|
def get_hwm(chat_id:)
|
|
17
17
|
key = hwm_key(chat_id: chat_id)
|
|
18
18
|
if cache_available?
|
|
19
|
-
|
|
19
|
+
cache_get(key)
|
|
20
20
|
else
|
|
21
21
|
@hwm_fallback ||= {}
|
|
22
22
|
@hwm_fallback[key]
|
|
@@ -26,7 +26,7 @@ module Legion
|
|
|
26
26
|
def set_hwm(chat_id:, timestamp:)
|
|
27
27
|
key = hwm_key(chat_id: chat_id)
|
|
28
28
|
if cache_available?
|
|
29
|
-
|
|
29
|
+
cache_set(key, timestamp, HWM_TTL)
|
|
30
30
|
else
|
|
31
31
|
@hwm_fallback ||= {}
|
|
32
32
|
@hwm_fallback[key] = timestamp
|
|
@@ -50,7 +50,7 @@ module Legion
|
|
|
50
50
|
def get_extended_hwm(chat_id:)
|
|
51
51
|
key = "teams:ehwm:#{chat_id}"
|
|
52
52
|
raw = if cache_available?
|
|
53
|
-
|
|
53
|
+
cache_get(key)
|
|
54
54
|
else
|
|
55
55
|
@ehwm_fallback ||= {}
|
|
56
56
|
@ehwm_fallback[key]
|
|
@@ -68,7 +68,7 @@ module Legion
|
|
|
68
68
|
value = { last_message_at: last_message_at, last_ingested_at: last_ingested_at,
|
|
69
69
|
message_count: message_count }
|
|
70
70
|
if cache_available?
|
|
71
|
-
|
|
71
|
+
cache_set(key, ::JSON.dump(value), HWM_TTL)
|
|
72
72
|
else
|
|
73
73
|
@ehwm_fallback ||= {}
|
|
74
74
|
@ehwm_fallback[key] = value
|
|
@@ -108,7 +108,7 @@ module Legion
|
|
|
108
108
|
last_ingested_at: data[:last_ingested_at], message_count: data[:message_count] || 0)
|
|
109
109
|
end
|
|
110
110
|
rescue StandardError => e
|
|
111
|
-
|
|
111
|
+
log.warn("Failed to restore HWM from traces: #{e.message}")
|
|
112
112
|
end
|
|
113
113
|
|
|
114
114
|
def memory_runner
|
|
@@ -124,7 +124,7 @@ module Legion
|
|
|
124
124
|
def cache_available?
|
|
125
125
|
defined?(Legion::Cache) &&
|
|
126
126
|
Legion::Cache.respond_to?(:connected?) &&
|
|
127
|
-
|
|
127
|
+
cache_connected?
|
|
128
128
|
end
|
|
129
129
|
end
|
|
130
130
|
end
|
|
@@ -123,7 +123,8 @@ module Legion
|
|
|
123
123
|
v[:created_at] = Time.parse(v[:created_at]) if v[:created_at].is_a?(String)
|
|
124
124
|
v
|
|
125
125
|
end
|
|
126
|
-
rescue ::JSON::ParserError
|
|
126
|
+
rescue ::JSON::ParserError => e
|
|
127
|
+
log.warn("SubscriptionRegistry: corrupted subscription data, resetting: #{e.message}")
|
|
127
128
|
{}
|
|
128
129
|
end
|
|
129
130
|
|
|
@@ -174,11 +174,10 @@ module Legion
|
|
|
174
174
|
end
|
|
175
175
|
|
|
176
176
|
log.info("Saving delegated token to Vault (#{vault_path})")
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
scopes: data[:scopes])
|
|
177
|
+
vault_write(vault_path, access_token: data[:token],
|
|
178
|
+
refresh_token: data[:refresh_token],
|
|
179
|
+
expires_at: data[:expires_at].utc.iso8601,
|
|
180
|
+
scopes: data[:scopes])
|
|
182
181
|
log.info('Delegated token saved to Vault')
|
|
183
182
|
true
|
|
184
183
|
rescue StandardError => e
|
|
@@ -387,7 +386,14 @@ module Legion
|
|
|
387
386
|
return {} unless defined?(Legion::Settings)
|
|
388
387
|
|
|
389
388
|
ms = Legion::Settings[:microsoft_teams]
|
|
390
|
-
|
|
389
|
+
auth = ms && ms[:auth].is_a?(Hash) ? ms[:auth].dup : {}
|
|
390
|
+
auth[:tenant_id] ||= ms[:tenant_id] if ms
|
|
391
|
+
auth[:client_id] ||= ms[:client_id] if ms
|
|
392
|
+
auth[:client_secret] ||= ms[:client_secret] if ms
|
|
393
|
+
auth[:tenant_id] ||= ENV.fetch('AZURE_TENANT_ID', nil)
|
|
394
|
+
auth[:client_id] ||= ENV.fetch('AZURE_CLIENT_ID', nil)
|
|
395
|
+
auth[:client_secret] ||= ENV.fetch('AZURE_CLIENT_SECRET', nil)
|
|
396
|
+
auth
|
|
391
397
|
end
|
|
392
398
|
end
|
|
393
399
|
end
|
|
@@ -95,7 +95,8 @@ module Legion
|
|
|
95
95
|
age = trace_age_label(trace[:created_at] || trace[:last_reinforced])
|
|
96
96
|
|
|
97
97
|
"- [#{type}] #{content} (#{age}, tags: #{tags})"
|
|
98
|
-
rescue StandardError
|
|
98
|
+
rescue StandardError => e
|
|
99
|
+
log_trace_error('format_single_trace', e)
|
|
99
100
|
nil
|
|
100
101
|
end
|
|
101
102
|
|
|
@@ -109,7 +110,8 @@ module Legion
|
|
|
109
110
|
when 86_400..604_800 then "#{(seconds / 86_400).to_i}d ago"
|
|
110
111
|
else "#{(seconds / 604_800).to_i}w ago"
|
|
111
112
|
end
|
|
112
|
-
rescue StandardError
|
|
113
|
+
rescue StandardError => e
|
|
114
|
+
log_trace_error('trace_age_label', e)
|
|
113
115
|
'unknown age'
|
|
114
116
|
end
|
|
115
117
|
|
|
@@ -4,7 +4,7 @@ module Legion
|
|
|
4
4
|
module Extensions
|
|
5
5
|
module MicrosoftTeams
|
|
6
6
|
module Hooks
|
|
7
|
-
class Auth < Legion::Extensions::Hooks::Base
|
|
7
|
+
class Auth < Legion::Extensions::Hooks::Base # rubocop:disable Legion/Extension/HookMissingRunnerClass
|
|
8
8
|
mount '/callback'
|
|
9
9
|
|
|
10
10
|
def self.runner_class
|
|
@@ -58,11 +58,11 @@ module Legion
|
|
|
58
58
|
when 0x00 then block
|
|
59
59
|
when 0x01 then Snappy.inflate(block)
|
|
60
60
|
end
|
|
61
|
-
rescue Snappy::Error
|
|
61
|
+
rescue Snappy::Error => _e
|
|
62
62
|
nil
|
|
63
63
|
end
|
|
64
64
|
|
|
65
|
-
def parse_block_entries(block
|
|
65
|
+
def parse_block_entries(block)
|
|
66
66
|
return unless block && block.bytesize > 4
|
|
67
67
|
|
|
68
68
|
num_restarts = block.byteslice(-4, 4).unpack1('V')
|
|
@@ -88,7 +88,7 @@ module Legion
|
|
|
88
88
|
pos += value_len
|
|
89
89
|
|
|
90
90
|
prev_key = key
|
|
91
|
-
|
|
91
|
+
yield(key, value)
|
|
92
92
|
end
|
|
93
93
|
end
|
|
94
94
|
|
|
@@ -84,7 +84,7 @@ module Legion
|
|
|
84
84
|
|
|
85
85
|
people_ingested += 1
|
|
86
86
|
update_extended_hwm(chat_id: chat['id'],
|
|
87
|
-
last_message_at: messages.
|
|
87
|
+
last_message_at: messages.filter_map { |m| m['createdDateTime'] }.max,
|
|
88
88
|
new_message_count: msg_stored, ingested: true)
|
|
89
89
|
end
|
|
90
90
|
|
|
@@ -41,7 +41,8 @@ module Legion
|
|
|
41
41
|
|
|
42
42
|
presence = begin
|
|
43
43
|
conn.get('me/presence').body
|
|
44
|
-
rescue StandardError
|
|
44
|
+
rescue StandardError => e
|
|
45
|
+
log.debug("ProfileIngest: presence fetch failed: #{e.message}") if defined?(log)
|
|
45
46
|
{}
|
|
46
47
|
end
|
|
47
48
|
unless presence.empty?
|
|
@@ -229,8 +230,7 @@ module Legion
|
|
|
229
230
|
result = client.transform(text: text, **definition)
|
|
230
231
|
result[:result] || result[:error] ? nil : result
|
|
231
232
|
elsif defined?(Legion::LLM)
|
|
232
|
-
|
|
233
|
-
caller: { extension: 'lex-microsoft_teams', runner: 'profile_ingest' })
|
|
233
|
+
llm_ask(message: "#{definition[:prompt]}\n\nConversation with #{peer_name}:\n#{text}")
|
|
234
234
|
end
|
|
235
235
|
rescue StandardError => e
|
|
236
236
|
log.debug("ProfileIngest: extract_conversation failed: #{e.message}")
|
|
@@ -36,7 +36,7 @@ require 'legion/extensions/microsoft_teams/helpers/transform_definitions'
|
|
|
36
36
|
require 'legion/extensions/microsoft_teams/helpers/graph_client'
|
|
37
37
|
|
|
38
38
|
# Transport
|
|
39
|
-
if
|
|
39
|
+
if Legion.const_defined?(:Transport, false)
|
|
40
40
|
require 'legion/extensions/microsoft_teams/transport/exchanges/messages'
|
|
41
41
|
require 'legion/extensions/microsoft_teams/transport/queues/messages_process'
|
|
42
42
|
require 'legion/extensions/microsoft_teams/transport/messages/teams_message'
|
|
@@ -53,7 +53,7 @@ end
|
|
|
53
53
|
module Legion
|
|
54
54
|
module Extensions
|
|
55
55
|
module MicrosoftTeams
|
|
56
|
-
extend Legion::Extensions::Core if Legion::Extensions.const_defined? :Core
|
|
56
|
+
extend Legion::Extensions::Core if Legion::Extensions.const_defined? :Core, false
|
|
57
57
|
end
|
|
58
58
|
end
|
|
59
59
|
end
|