@open-everywhere/provider-teams 0.0.0-stage β 0.1.0
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.
- package/LICENSE +201 -0
- package/NOTICE +21 -0
- package/README.md +46 -2
- package/agent/channels/teams-bot-name.ts +162 -0
- package/agent/channels/teams-catch-up.ts +244 -0
- package/agent/channels/teams-connector.ts +183 -0
- package/agent/channels/teams-conversation-ref.ts +398 -0
- package/agent/channels/teams-directory.ts +193 -0
- package/agent/channels/teams-engagement.ts +391 -0
- package/agent/channels/teams-fire-eligibility.ts +152 -0
- package/agent/channels/teams-front.ts +1404 -0
- package/agent/channels/teams-graph-boundary.ts +178 -0
- package/agent/channels/teams-graph-team-id.ts +106 -0
- package/agent/channels/teams-id-restore.ts +131 -0
- package/agent/channels/teams-identity.ts +395 -0
- package/agent/channels/teams-input-response.ts +129 -0
- package/agent/channels/teams-message-ops.ts +79 -0
- package/agent/channels/teams-origin-codec.ts +104 -0
- package/agent/channels/teams-post-arm.ts +323 -0
- package/agent/channels/teams-reaction-feedback.ts +127 -0
- package/agent/channels/teams-read.ts +510 -0
- package/agent/channels/teams-roster.ts +136 -0
- package/agent/channels/teams-stop.ts +319 -0
- package/agent/channels/teams-supervisor.ts +638 -0
- package/agent/channels/teams.ts +270 -0
- package/agent/contributions.ts +31 -0
- package/agent/docs-generated.ts +15 -0
- package/agent/ops.ts +129 -0
- package/agent/provider-events.ts +69 -0
- package/agent/register.ts +219 -0
- package/agent/surface-parity.ts +112 -0
- package/dist/agent/channels/teams-bot-name.d.ts +36 -0
- package/dist/agent/channels/teams-bot-name.d.ts.map +1 -0
- package/dist/agent/channels/teams-bot-name.js +141 -0
- package/dist/agent/channels/teams-bot-name.js.map +1 -0
- package/dist/agent/channels/teams-catch-up.d.ts +53 -0
- package/dist/agent/channels/teams-catch-up.d.ts.map +1 -0
- package/dist/agent/channels/teams-catch-up.js +221 -0
- package/dist/agent/channels/teams-catch-up.js.map +1 -0
- package/dist/agent/channels/teams-connector.d.ts +57 -0
- package/dist/agent/channels/teams-connector.d.ts.map +1 -0
- package/dist/agent/channels/teams-connector.js +132 -0
- package/dist/agent/channels/teams-connector.js.map +1 -0
- package/dist/agent/channels/teams-conversation-ref.d.ts +123 -0
- package/dist/agent/channels/teams-conversation-ref.d.ts.map +1 -0
- package/dist/agent/channels/teams-conversation-ref.js +368 -0
- package/dist/agent/channels/teams-conversation-ref.js.map +1 -0
- package/dist/agent/channels/teams-directory.d.ts +11 -0
- package/dist/agent/channels/teams-directory.d.ts.map +1 -0
- package/dist/agent/channels/teams-directory.js +179 -0
- package/dist/agent/channels/teams-directory.js.map +1 -0
- package/dist/agent/channels/teams-engagement.d.ts +174 -0
- package/dist/agent/channels/teams-engagement.d.ts.map +1 -0
- package/dist/agent/channels/teams-engagement.js +336 -0
- package/dist/agent/channels/teams-engagement.js.map +1 -0
- package/dist/agent/channels/teams-fire-eligibility.d.ts +26 -0
- package/dist/agent/channels/teams-fire-eligibility.d.ts.map +1 -0
- package/dist/agent/channels/teams-fire-eligibility.js +126 -0
- package/dist/agent/channels/teams-fire-eligibility.js.map +1 -0
- package/dist/agent/channels/teams-front.d.ts +249 -0
- package/dist/agent/channels/teams-front.d.ts.map +1 -0
- package/dist/agent/channels/teams-front.js +1143 -0
- package/dist/agent/channels/teams-front.js.map +1 -0
- package/dist/agent/channels/teams-graph-boundary.d.ts +45 -0
- package/dist/agent/channels/teams-graph-boundary.d.ts.map +1 -0
- package/dist/agent/channels/teams-graph-boundary.js +168 -0
- package/dist/agent/channels/teams-graph-boundary.js.map +1 -0
- package/dist/agent/channels/teams-graph-team-id.d.ts +30 -0
- package/dist/agent/channels/teams-graph-team-id.d.ts.map +1 -0
- package/dist/agent/channels/teams-graph-team-id.js +89 -0
- package/dist/agent/channels/teams-graph-team-id.js.map +1 -0
- package/dist/agent/channels/teams-id-restore.d.ts +34 -0
- package/dist/agent/channels/teams-id-restore.d.ts.map +1 -0
- package/dist/agent/channels/teams-id-restore.js +123 -0
- package/dist/agent/channels/teams-id-restore.js.map +1 -0
- package/dist/agent/channels/teams-identity.d.ts +148 -0
- package/dist/agent/channels/teams-identity.d.ts.map +1 -0
- package/dist/agent/channels/teams-identity.js +336 -0
- package/dist/agent/channels/teams-identity.js.map +1 -0
- package/dist/agent/channels/teams-input-response.d.ts +23 -0
- package/dist/agent/channels/teams-input-response.d.ts.map +1 -0
- package/dist/agent/channels/teams-input-response.js +102 -0
- package/dist/agent/channels/teams-input-response.js.map +1 -0
- package/dist/agent/channels/teams-message-ops.d.ts +3 -0
- package/dist/agent/channels/teams-message-ops.d.ts.map +1 -0
- package/dist/agent/channels/teams-message-ops.js +72 -0
- package/dist/agent/channels/teams-message-ops.js.map +1 -0
- package/dist/agent/channels/teams-origin-codec.d.ts +16 -0
- package/dist/agent/channels/teams-origin-codec.d.ts.map +1 -0
- package/dist/agent/channels/teams-origin-codec.js +99 -0
- package/dist/agent/channels/teams-origin-codec.js.map +1 -0
- package/dist/agent/channels/teams-post-arm.d.ts +37 -0
- package/dist/agent/channels/teams-post-arm.d.ts.map +1 -0
- package/dist/agent/channels/teams-post-arm.js +280 -0
- package/dist/agent/channels/teams-post-arm.js.map +1 -0
- package/dist/agent/channels/teams-reaction-feedback.d.ts +22 -0
- package/dist/agent/channels/teams-reaction-feedback.d.ts.map +1 -0
- package/dist/agent/channels/teams-reaction-feedback.js +108 -0
- package/dist/agent/channels/teams-reaction-feedback.js.map +1 -0
- package/dist/agent/channels/teams-read.d.ts +127 -0
- package/dist/agent/channels/teams-read.d.ts.map +1 -0
- package/dist/agent/channels/teams-read.js +424 -0
- package/dist/agent/channels/teams-read.js.map +1 -0
- package/dist/agent/channels/teams-roster.d.ts +54 -0
- package/dist/agent/channels/teams-roster.d.ts.map +1 -0
- package/dist/agent/channels/teams-roster.js +121 -0
- package/dist/agent/channels/teams-roster.js.map +1 -0
- package/dist/agent/channels/teams-stop.d.ts +74 -0
- package/dist/agent/channels/teams-stop.d.ts.map +1 -0
- package/dist/agent/channels/teams-stop.js +252 -0
- package/dist/agent/channels/teams-stop.js.map +1 -0
- package/dist/agent/channels/teams-supervisor.d.ts +351 -0
- package/dist/agent/channels/teams-supervisor.d.ts.map +1 -0
- package/dist/agent/channels/teams-supervisor.js +366 -0
- package/dist/agent/channels/teams-supervisor.js.map +1 -0
- package/dist/agent/channels/teams.d.ts +5 -0
- package/dist/agent/channels/teams.d.ts.map +1 -0
- package/dist/agent/channels/teams.js +246 -0
- package/dist/agent/channels/teams.js.map +1 -0
- package/dist/agent/contributions.d.ts +12 -0
- package/dist/agent/contributions.d.ts.map +1 -0
- package/dist/agent/contributions.js +31 -0
- package/dist/agent/contributions.js.map +1 -0
- package/dist/agent/docs-generated.d.ts +3 -0
- package/dist/agent/docs-generated.d.ts.map +1 -0
- package/dist/agent/docs-generated.js +13 -0
- package/dist/agent/docs-generated.js.map +1 -0
- package/dist/agent/ops.d.ts +14 -0
- package/dist/agent/ops.d.ts.map +1 -0
- package/dist/agent/ops.js +122 -0
- package/dist/agent/ops.js.map +1 -0
- package/dist/agent/provider-events.d.ts +3 -0
- package/dist/agent/provider-events.d.ts.map +1 -0
- package/dist/agent/provider-events.js +67 -0
- package/dist/agent/provider-events.js.map +1 -0
- package/dist/agent/register.d.ts +16 -0
- package/dist/agent/register.d.ts.map +1 -0
- package/dist/agent/register.js +198 -0
- package/dist/agent/register.js.map +1 -0
- package/dist/agent/surface-parity.d.ts +3 -0
- package/dist/agent/surface-parity.d.ts.map +1 -0
- package/dist/agent/surface-parity.js +106 -0
- package/dist/agent/surface-parity.js.map +1 -0
- package/package.json +183 -4
- package/tsconfig.build.json +22 -0
- package/tsconfig.json +15 -0
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
import { type VendorEventTime, type NormalizedWake, type WakeEngagementTier, type WakeTrust, type UnifiedWindowWake, type WakeMessageInput, type IngestedChatMessage, type SessionTailWakeRow, type SeatCatchUpRequest, type SeatCatchUpResult } from "@open-everywhere/core/agent/adapter-api.js";
|
|
2
|
+
import type { OpenEverywhereTeamsAuth } from "./teams-identity.js";
|
|
3
|
+
/** The per-container supervisor token for a Teams channel container (the grain fallback β
|
|
4
|
+
* see the header note; a live Teams dispatch always resolves the unified domain token). */
|
|
5
|
+
export declare function teamsSupervisorToken(channelKey: string, generation: number): string;
|
|
6
|
+
/** The host-extracted Teams facts the floor decides from β every field comes off the
|
|
7
|
+
* JWT-VERIFIED inbound activity (or the operator's own registers), never model output. */
|
|
8
|
+
export interface TeamsSingleWindowFacts {
|
|
9
|
+
/** Normalized conversation scope ("personal" | "groupChat" | "channel" | "unknown"). */
|
|
10
|
+
readonly scope: string | undefined;
|
|
11
|
+
/** Channel membershipType ("standard" | "private" | "shared") when the activity's channelData
|
|
12
|
+
* positively carried it β inbound activities usually OMIT it (teams-identity.ts). */
|
|
13
|
+
readonly membershipType?: string;
|
|
14
|
+
/** The tenant (org boundary). Absent β the surface can't be anchored to an org β refuse. */
|
|
15
|
+
readonly tenantId?: string;
|
|
16
|
+
/** The operator's explicit vouch for THIS surface: isVouchedSurface on the channel key AND the
|
|
17
|
+
* team rung, which WALKS the declaration rungs (OPE-1521/OPE-1538), so a tenant-grain
|
|
18
|
+
* `teams/<tenant>` declaration vouches every room under it and a `public` `team:<id>` carve-out
|
|
19
|
+
* demotes one team out of it β see below. Or the blanket OE_TRUST=internal. Resolved by the
|
|
20
|
+
* live wiring (teams-front.ts). */
|
|
21
|
+
readonly vouched: boolean;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* The Teams privacy floor for the cross-surface window, FAIL-CLOSED. Every surface has one so a
|
|
25
|
+
* public/external surface can never join a private shared window (GitHub: `repository.private
|
|
26
|
+
* === true`; Slack: positively-confirmed-internal channel/group; Linear: team positively
|
|
27
|
+
* private; Notion: operator vouch). Teams' rule:
|
|
28
|
+
*
|
|
29
|
+
* ADMIT βΊ scope === "channel" AND tenantId present AND membershipType β "shared"
|
|
30
|
+
* AND the OPERATOR VOUCHED the surface (vouch register / OE_TRUST=internal).
|
|
31
|
+
*
|
|
32
|
+
* WHY OPERATOR-VOUCH AND NOT A PLATFORM SIGNAL (the Notion posture, deliberately): Teams has NO
|
|
33
|
+
* reliable in-band fact that means "internal-only, no external eyes".
|
|
34
|
+
* β’ `membershipType` is usually ABSENT on inbound activities, and even when positively
|
|
35
|
+
* "standard" or "private" it does NOT exclude tenant GUESTS β a guest (an external identity
|
|
36
|
+
* invited into the tenant) sees every standard channel of the teams they're on, and can be a
|
|
37
|
+
* member of private channels too. So the memory-gate verdict (teams-identity.ts teamsTrust,
|
|
38
|
+
* which reads standard/private+tenant as internal) is deliberately NOT sufficient here β
|
|
39
|
+
* the window floor is STRICTER than the memory floor.
|
|
40
|
+
* β’ A Graph roster sweep (TeamMember.Read.All β userType === "Guest") could positively prove
|
|
41
|
+
* guest-freedom, but OE has no Graph credential plane wired (the bot speaks Bot Connector
|
|
42
|
+
* only), the sweep is racy (membership changes after the check), and Bot-Framework
|
|
43
|
+
* pagedMembers' `userRole` is not a documented-reliable field β inventing a weaker signal
|
|
44
|
+
* is exactly what the floor doctrine forbids. So: the operator vouches, code enforces.
|
|
45
|
+
*
|
|
46
|
+
* ATTACKER ANALYSIS: the leak vector is a message from a surface visible outside the org being
|
|
47
|
+
* admitted to (and answered from) a private cross-surface window. All four conjuncts are
|
|
48
|
+
* host-derived: scope/membershipType/tenantId come off the Bot-Connector-signed activity (a
|
|
49
|
+
* user cannot author channelData β the Teams service stamps it), and the vouch is the
|
|
50
|
+
* operator's own register. Absence of membershipType never ADMITS (only the vouch admits;
|
|
51
|
+
* membershipType only REFUSES). The one positive-external fact we CAN see β membershipType ===
|
|
52
|
+
* "shared", a Teams Connect shared channel spanning tenants β refuses EVEN WHEN VOUCHED (a
|
|
53
|
+
* positive cross-org fact beats a standing assertion). BUT membershipType is usually ABSENT
|
|
54
|
+
* inbound, and an absent signal never demotes, so that guard catches only the rooms Teams labels
|
|
55
|
+
* for us.
|
|
56
|
+
*
|
|
57
|
+
* π΄ THERE IS NO EXACT-GRAIN BACKSTOP BEHIND IT β the operator's declaration IS the protection.
|
|
58
|
+
* `isVouchedSurface` walks the declaration rungs (OPE-1521), the same most-specific-wins walk every
|
|
59
|
+
* other trust reader uses, and since OPE-1538 the wiring hands it the TEAM rung too, so the walk
|
|
60
|
+
* here has the same reach the binding and memory planes have: a `public` `teams/<tenant>/team:<id>`
|
|
61
|
+
* carve-out now demotes one team out of an internal tenant at this floor, where it used to be
|
|
62
|
+
* skipped and the room admitted. A coarse `teams/<tenant>` declaration still admits EVERY room under
|
|
63
|
+
* that tenant that no narrower entry demotes. `agent/identity/surfaces.ts` ships exactly such a tenant line today. A native
|
|
64
|
+
* internal channel and a cross-tenant Connect/shared channel look alike at that grain, so a
|
|
65
|
+
* shared room whose inbound activities omit membershipType IS admitted on the tenant line. That is
|
|
66
|
+
* the ruling, not a gap: a declaration vouches, and only a POSITIVE external signal demotes. The
|
|
67
|
+
* operator narrows the reach by declaring the channel rung instead. This floor admits or refuses a
|
|
68
|
+
* room that is ALREADY a window member β it enrolls nobody; the domain CONFIG
|
|
69
|
+
* (`agent/memory/config/domains.ts`, read by teams-front.ts) enrolls. Do not read that as a second
|
|
70
|
+
* bound on the reach: a domain's container `reach` entry is legal at TENANT grain, so a tenant claim
|
|
71
|
+
* beside a tenant declaration puts every room in the tenant through this floor, and config load
|
|
72
|
+
* cannot enumerate them. In-tree domains name exact channels today. Residual: the standing
|
|
73
|
+
* "operator vouched something they shouldn't have" residual every vouch surface carries (identical
|
|
74
|
+
* to vouching a web-published Notion page) β now at whatever grain the operator wrote, so a tenant
|
|
75
|
+
* declaration carries it for the whole tenant. Personal and group chats
|
|
76
|
+
* are refused outright: they are per-person surfaces, not org containers, mirroring Slack's
|
|
77
|
+
* channels/groups-only rule. Residual acceptance: a vouched tenant/channel that LATER gains a
|
|
78
|
+
* guest is admitted until the operator retracts the vouch β the documented trade of the vouch
|
|
79
|
+
* posture (identical to Notion's), and strictly safer than any inference we could make.
|
|
80
|
+
*/
|
|
81
|
+
export declare function teamsSingleWindowPrivacyOk(f: TeamsSingleWindowFacts): boolean;
|
|
82
|
+
/** The host-frozen reply-target facts one Teams activity resolves β everything
|
|
83
|
+
* {@link planTeamsSingleWindow} needs to mint the wake origin (unified-window.ts's teams arm). */
|
|
84
|
+
export interface TeamsSingleWindowTarget {
|
|
85
|
+
/** Bot Connector base URL off the verified activity β the reply's transport host. Empty β no
|
|
86
|
+
* routable reply target β NO window (fail closed, never an unanswerable wake). */
|
|
87
|
+
readonly serviceUrl: string;
|
|
88
|
+
/** The Bot Framework conversation id (channel messages carry the reply-chain anchor in it). */
|
|
89
|
+
readonly conversationId: string;
|
|
90
|
+
/** The reply-chain ROOT activity id (eve's teamsThreadRootActivityId: the trigger's replyToId
|
|
91
|
+
* when it was itself a reply, else the trigger activity) β replyToTeamsActivity's target. */
|
|
92
|
+
readonly replyToActivityId?: string;
|
|
93
|
+
readonly tenantId?: string;
|
|
94
|
+
/** The first latency anchor (OPE-1716), recorded on the ingress row. A Bot-Framework activity
|
|
95
|
+
* carries no parsed timestamp on eve's shape, so the caller passes its own FRONT-DOOR RECEIPT β
|
|
96
|
+
* which makes the vendorβingress segment a lower bound, and the row's `vendorTsSource` says so. */
|
|
97
|
+
readonly vendorTs?: VendorEventTime;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* The ONE single-window decision for a Teams delivery, mirroring planNotionSingleWindow: given
|
|
101
|
+
* the grain's `singleWindow`, whether the activity @mentions the bot, the PRIVACY-FLOOR facts,
|
|
102
|
+
* and the frozen reply target, return the {@link UnifiedWindowWake} the dispatch should carry β
|
|
103
|
+
* or undefined for the byte-identical native path (teams-front then FORWARDS the activity to
|
|
104
|
+
* eve's native teamsChannel exactly as today).
|
|
105
|
+
*
|
|
106
|
+
* Teams' mention signal lives in ONE Bot-Framework activity (no Slack-style dual event), and its
|
|
107
|
+
* "native" handler is the forward this plan suppresses β so suppress-native and divert are the
|
|
108
|
+
* SAME act, both read off this one verdict (never a double turn, never a gap):
|
|
109
|
+
* β’ @mention on a singleWindow, floor-passing channel β the seam suppresses the native forward
|
|
110
|
+
* and stamps `addressing:"direct-mention"` (the terminal-prose delivery bridge's arm);
|
|
111
|
+
* β’ ambient (non-mention) channel message on the same surface β Leg A: the window WITHOUT the
|
|
112
|
+
* addressed stamp (judged treatment in the shared window, prose stays hard-dropped);
|
|
113
|
+
* β’ floor fails, singleWindow off, or no routable reply target β undefined (forward β a
|
|
114
|
+
* mention then keeps today's native conversation-session turn).
|
|
115
|
+
*/
|
|
116
|
+
export declare function planTeamsSingleWindow(singleWindow: boolean, isMention: boolean, facts: TeamsSingleWindowFacts, target: TeamsSingleWindowTarget): UnifiedWindowWake | undefined;
|
|
117
|
+
export interface TeamsSupervisorWakeInput {
|
|
118
|
+
/** The Teams CHANNEL id (the container β the envelope's `<channel id>`; the conversation id
|
|
119
|
+
* when the activity carried no channel id). */
|
|
120
|
+
readonly channelId: string;
|
|
121
|
+
/** The trigger activity's facts (host-extracted). */
|
|
122
|
+
readonly trigger: {
|
|
123
|
+
readonly id: string;
|
|
124
|
+
readonly authorId: string;
|
|
125
|
+
readonly authorName?: string;
|
|
126
|
+
readonly sentAt: string;
|
|
127
|
+
readonly text: string;
|
|
128
|
+
/** Per-message trust tier (identity/wake-trust.ts) β resolved by the live dispatch.
|
|
129
|
+
* π΄ REQUIRED (OPE-596): this builder fail-closed to `relay` while its five siblings defaulted
|
|
130
|
+
* UPWARD, so all six now refuse the omission at compile time instead of each picking a floor.
|
|
131
|
+
* A caller that cannot resolve a tier states the fail-closed one itself: `relay` for a machine
|
|
132
|
+
* author, `unauth` for a human the gate cannot vouch. */
|
|
133
|
+
readonly trust: WakeTrust;
|
|
134
|
+
};
|
|
135
|
+
/** Present β the trigger sat inside an EXISTING reply chain (its replyToId) β envelope thread
|
|
136
|
+
* meta only; the reply target is the frozen origin, never this. */
|
|
137
|
+
readonly threadRootId?: string;
|
|
138
|
+
/** The seam's addressed verdict (window.addressing === "direct-mention"). */
|
|
139
|
+
readonly directMention: boolean;
|
|
140
|
+
/** Host-minted wake id β always present (Teams only dispatches on the single-window path). */
|
|
141
|
+
readonly wakeId: string;
|
|
142
|
+
/** Engagement calibration for the judged preamble β channel-watch only. */
|
|
143
|
+
readonly engagementTier?: WakeEngagementTier;
|
|
144
|
+
/** The OUTGOING generation's recorded TAIL (OPE-794), rendered as this first wake's backscroll.
|
|
145
|
+
* Only a FRESH generation's first wake carries one. */
|
|
146
|
+
readonly tail?: readonly WakeMessageInput[];
|
|
147
|
+
/** This surface could not read its own channel since the seat's last wake (core
|
|
148
|
+
* channels/seat-catch-up.ts). Rendered as a trusted `<system-note>`; unset β no note. */
|
|
149
|
+
readonly catchUpUnavailable?: string;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Build the NormalizedWake for one Teams single-window turn. platform "teams", containerNoun
|
|
153
|
+
* "channel" (a Teams channel is a channel), locus.channel = the Teams channel, locus.thread =
|
|
154
|
+
* the reply chain the trigger sat in (when it did). NO PLATFORM-FETCH BOOTSTRAP: the Bot Connector
|
|
155
|
+
* API this wake arrives over has no message-history read (unlike Slack's conversations.history), so a
|
|
156
|
+
* FRESH generation carries the RECORDED TAIL of the outgoing generation (OPE-794) and nothing else β
|
|
157
|
+
* which is why the recorded ring matters more on Teams than anywhere else. A Teams seat with no
|
|
158
|
+
* recorded tail opens cold, honestly.
|
|
159
|
+
* π΄ AN ONGOING GENERATION IS A DIFFERENT QUESTION, AND IT IS ANSWERED (OPE-1726): the since-last-wake
|
|
160
|
+
* catch-up reads MICROSOFT GRAPH β a different credential and a different transport from the Bot
|
|
161
|
+
* Connector, the one `read_channel` has always used β so a Teams seat does see what the channel said
|
|
162
|
+
* between its own wakes. See channels/teams-catch-up.ts; the bootstrap gap above is unchanged.
|
|
163
|
+
* Always the unified render (platform address + P5 disclosure): Teams has no non-window
|
|
164
|
+
* supervisor path, so there is no per-container twin to stay byte-identical with.
|
|
165
|
+
*/
|
|
166
|
+
export declare function buildTeamsSupervisorWake(input: TeamsSupervisorWakeInput): NormalizedWake;
|
|
167
|
+
/** The live supervisor session pointer, as the deps report it (mirrors the other surfaces). */
|
|
168
|
+
export interface TeamsSupervisorSession {
|
|
169
|
+
readonly token: string;
|
|
170
|
+
readonly generation: number;
|
|
171
|
+
readonly freshGeneration: boolean;
|
|
172
|
+
/** ISO-8601 of the most recent wake this generation delivered (the registry row's `lastWakeAt`),
|
|
173
|
+
* or null on a freshly minted/rotated generation β the lower bound of the since-last-wake catch-up
|
|
174
|
+
* read (OPE-1726); absent β no catch-up. */
|
|
175
|
+
readonly lastWakeAt?: string | null;
|
|
176
|
+
/** The OUTGOING generation's recorded tail, oldest-first β empty unless this is a fresh
|
|
177
|
+
* generation's first wake (OPE-794). */
|
|
178
|
+
readonly tail: readonly WakeMessageInput[];
|
|
179
|
+
}
|
|
180
|
+
/** Deps for {@link handleTeamsSingleWindowDispatch} β injected so the core is unit-testable over
|
|
181
|
+
* a mock store + a capture `wake` (scripts/unified-window-test.ts). org is baked into the live
|
|
182
|
+
* impl's closures (a deployment fact β teams-front.ts), so it never crosses this boundary. */
|
|
183
|
+
export interface TeamsSupervisorDeps {
|
|
184
|
+
/** Create-or-fetch the live supervisor session for this surface's grain: generation 1 on first
|
|
185
|
+
* sighting, rotate when shouldRotate says it aged out, else the current generation. */
|
|
186
|
+
readonly getOrCreateSession: (surfaceKey: string, channelId: string, atIso: string) => Promise<TeamsSupervisorSession>;
|
|
187
|
+
/** Record one wake on the current generation (lastWakeAt/turnCount). Best-effort. */
|
|
188
|
+
readonly touchSession?: (surfaceKey: string, atIso: string) => Promise<void>;
|
|
189
|
+
/**
|
|
190
|
+
* THE SINCE-LAST-WAKE CATCH-UP, through the ONE shared path every surface takes
|
|
191
|
+
* (channels/seat-catch-up.ts `seatCatchUp`). Optional so older test doubles keep compiling
|
|
192
|
+
* (absent β no catch-up, the pre-OPE-1726 behaviour); fail-soft by construction.
|
|
193
|
+
*/
|
|
194
|
+
readonly catchUp?: (req: SeatCatchUpRequest) => Promise<SeatCatchUpResult>;
|
|
195
|
+
/**
|
|
196
|
+
* Record this delivered wake onto the LIVE generation's TAIL ring (OPE-794). Injected because the
|
|
197
|
+
* entry has to be filed under an ORG and a registry key, and this core deliberately holds neither
|
|
198
|
+
* β the live wiring does. Absent (a unit test) β nothing is recorded and the dispatch is
|
|
199
|
+
* unchanged, which is the same posture `touchSession` takes.
|
|
200
|
+
*/
|
|
201
|
+
readonly recordWake?: (entry: SessionTailWakeRow, token: string, surfaceKey: string) => Promise<void>;
|
|
202
|
+
/** Deliver the rendered wake. The live wiring (teams-front.ts) ALWAYS diverts through eve's
|
|
203
|
+
* cross-channel `receive` into the synthetic `unified` channel (divertToUnifiedWindow) β a
|
|
204
|
+
* Teams dispatch has no native send fallback, by construction (window required below). */
|
|
205
|
+
readonly wake: (input: {
|
|
206
|
+
token: string;
|
|
207
|
+
auth: OpenEverywhereTeamsAuth;
|
|
208
|
+
message: string;
|
|
209
|
+
context: readonly string[];
|
|
210
|
+
window: UnifiedWindowWake;
|
|
211
|
+
}) => Promise<void>;
|
|
212
|
+
/** Clock seam (defaults to the real clock). */
|
|
213
|
+
readonly now?: () => string;
|
|
214
|
+
}
|
|
215
|
+
/** Everything teams-front hands the dispatch: identity/session facts + the wake parts + the
|
|
216
|
+
* REQUIRED window (a Teams dispatch exists only on the single-window path). */
|
|
217
|
+
export interface TeamsSupervisorDispatch {
|
|
218
|
+
/** The DOMAIN-GRAIN surface key (`teams/<tenant>/<channel>` β memory/partition.ts domainKeyOf):
|
|
219
|
+
* the gate/registry/audit key, and what unified.receive re-checks fail-closed. */
|
|
220
|
+
readonly surfaceKey: string;
|
|
221
|
+
/**
|
|
222
|
+
* π΄ THE ROOM KEY β `partition.surfaceKey`, the CONVERSATION grain (`teams/<tenant>/<conversation
|
|
223
|
+
* id>`), and NOT {@link surfaceKey} above. It is the `container` this wake row carries, and it is
|
|
224
|
+
* a CONTRACT with the post row: `channels/session-tail-record.ts` `tailWindowFor` builds a post's
|
|
225
|
+
* container from `partition.surfaceKey`, and `channels/reply-fold.ts` filters the ring by exact
|
|
226
|
+
* container equality. Two spellings therefore hide every wake row from the fold policy.
|
|
227
|
+
*
|
|
228
|
+
* WHY THE TWO KEYS DIFFER HERE. `bindTeams` (teams-identity.ts) sets `surface` to the conversation
|
|
229
|
+
* id (one reply chain) and `domainSurface` to the channel id, so `surfaceKey` and `domainKeyOf` are
|
|
230
|
+
* different strings on Teams. π΄ TEAMS IS NOT THE ONLY SURFACE THAT SPLITS THEM. `bindDiscord`
|
|
231
|
+
* (discord-identity.ts) sets `domainSurface` to the parent channel id, so a Discord THREAD splits
|
|
232
|
+
* the same two grains. Those two are the whole set β `memory/partition.ts` names both, and no other
|
|
233
|
+
* binding sets `domainSurface`. Slack sets none, so its two keys are one string and
|
|
234
|
+
* `slack-events.ts` reads `p.surfaceKey` with nothing to get wrong. Discord
|
|
235
|
+
* passes `input.partition.surfaceKey` explicitly and is correct today; a future change to that ring
|
|
236
|
+
* row must keep the surface key, for the reason this field exists. Recording the domain key here
|
|
237
|
+
* made the fold policy refuse a post that a human message had already cleared (OPE-1528, ship #174).
|
|
238
|
+
*/
|
|
239
|
+
readonly containerKey: string;
|
|
240
|
+
/** The Teams channel id (envelope container + the per-container token fallback). */
|
|
241
|
+
readonly channelId: string;
|
|
242
|
+
/** The TEAM the channel belongs to, in GRAPH's spelling β the Microsoft 365 GROUP id, NOT the
|
|
243
|
+
* `channelData.team.id` an activity carries (channels/teams-graph-team-id.ts resolves the one
|
|
244
|
+
* into the other; OPE-1808). Graph addresses a channel read as `/teams/{team}/channels/{channel}`,
|
|
245
|
+
* so the catch-up needs both ids and neither is derivable from the other. Absent (a chat activity,
|
|
246
|
+
* or a team id that would not resolve) β no catch-up, never a guessed team. */
|
|
247
|
+
readonly teamId?: string;
|
|
248
|
+
/** The activity DID name a team and its Graph id would not resolve ON THIS WAKE β the TRANSIENT
|
|
249
|
+
* shape, kept apart from the chat shape because the two owe the seat DIFFERENT sentences (the
|
|
250
|
+
* catch-up arm below). Absent β the activity named no team at all. */
|
|
251
|
+
readonly teamAddressUnresolved?: boolean;
|
|
252
|
+
readonly auth: OpenEverywhereTeamsAuth;
|
|
253
|
+
/**
|
|
254
|
+
* THE AUTHOR FACTS for every message whose bytes enter this wake's context (OPE-1747), in the same
|
|
255
|
+
* shape and for the same reason the other three seat surfaces carry it. A Teams channel activity is
|
|
256
|
+
* one message per wake, so the front passes exactly one entry β the resolved tier, the Bot Connector
|
|
257
|
+
* roster's `userRole: "guest"` refutation, and the OPERATOR's register query.
|
|
258
|
+
*
|
|
259
|
+
* π΄ REQUIRED, NOT OPTIONAL, for the reason `stampNonMemberChatAuth` makes its own `room` argument
|
|
260
|
+
* required: an optional field lets a new leg silently lose the author question, and a carriage that is
|
|
261
|
+
* absent looks identical to a carriage that answered "member". The front already computed these facts
|
|
262
|
+
* for its own taint join; what this field adds is that the TAIL ROW records them, so a tail-built
|
|
263
|
+
* envelope is judged by the same two legs a freshly-fetched one is. A leg with genuinely nothing to
|
|
264
|
+
* say passes `[]` and says so on purpose.
|
|
265
|
+
*/
|
|
266
|
+
readonly ingested: readonly IngestedChatMessage[];
|
|
267
|
+
readonly trigger: TeamsSupervisorWakeInput["trigger"];
|
|
268
|
+
readonly threadRootId?: string;
|
|
269
|
+
/**
|
|
270
|
+
* π΄ THE REPLY CHAIN THIS WAKE SITS IN β the second half of the catch-up's read, and NOT {@link
|
|
271
|
+
* threadRootId} (OPE-1817). A Teams CHANNEL activity always sits in one reply chain, named by its
|
|
272
|
+
* conversation id's `;messageid=<root>` suffix, and {@link containerKey} is that same conversation
|
|
273
|
+
* grain. `threadRootId` answers a different question β whether the ENVELOPE renders thread-scoped
|
|
274
|
+
* β and is deliberately absent on a top-level post.
|
|
275
|
+
*
|
|
276
|
+
* Naming the chain matters because Graph's `/channels/{c}/messages` returns TOP-LEVEL messages
|
|
277
|
+
* ONLY: a reply never appears there. So a wake that named no chain read nothing for a chain that
|
|
278
|
+
* had carried the message, with no error to see (ship #206, ship #207). The fetch reads the
|
|
279
|
+
* channel AND the named chain and merges them (channels/teams-catch-up.ts). Absent β the
|
|
280
|
+
* conversation names no chain, and the read is the container's alone.
|
|
281
|
+
*/
|
|
282
|
+
readonly replyChainRootId?: string;
|
|
283
|
+
readonly engagementTier?: WakeEngagementTier;
|
|
284
|
+
/** The minted single-window wake (planTeamsSingleWindow) β REQUIRED: without a window there is
|
|
285
|
+
* nothing for this dispatch to do (the front forwards to the native channel instead). */
|
|
286
|
+
readonly window: UnifiedWindowWake;
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* Route one floor-passing Teams activity to the domain's single-window supervisor: get-or-create
|
|
290
|
+
* the (unified-grain) session, build + render the wake for that generation, and deliver it via
|
|
291
|
+
* the wake dep (whose live wiring diverts into the unified channel β registering the durable
|
|
292
|
+
* wakeIdβorigin map entry BEFORE the send).
|
|
293
|
+
*
|
|
294
|
+
* A DELIVERY failure (the enqueue/divert itself) propagates to the caller's catch. A session that
|
|
295
|
+
* dies at TURN time does not: nothing here observes it, so the trigger is lost SILENTLY, and no
|
|
296
|
+
* reactive arm can exist (OPE-174 removed the inert one; channels/session-resume.ts holds the
|
|
297
|
+
* measurement). The working remedy is PRE-DISPATCH β the live `getOrCreateSession` claims the
|
|
298
|
+
* OPE-599 runtime-change rotation before this call and hands back a session the running eve build
|
|
299
|
+
* can read.
|
|
300
|
+
*/
|
|
301
|
+
export declare function handleTeamsSingleWindowDispatch(d: TeamsSupervisorDispatch, deps: TeamsSupervisorDeps): Promise<void>;
|
|
302
|
+
/** Everything {@link buildTeamsDmWake} needs β deliberately NARROWER than {@link
|
|
303
|
+
* TeamsSupervisorWakeInput}: a DM has no channel container and no engagement tier, and both
|
|
304
|
+
* absences are a property of the surface rather than a field a caller might or might not fill in
|
|
305
|
+
* (the buildDiscordDmWake discipline). */
|
|
306
|
+
export interface TeamsDmWakeInput {
|
|
307
|
+
/** The DM conversation id β a DM's whole locus (the envelope's `<channel id>`). */
|
|
308
|
+
readonly conversationId: string;
|
|
309
|
+
readonly wakeId: string;
|
|
310
|
+
/** The OUTGOING generation's recorded TAIL (OPE-794), rendered as this first wake's backscroll.
|
|
311
|
+
* Only a FRESH generation's first wake carries one. */
|
|
312
|
+
readonly tail?: readonly WakeMessageInput[];
|
|
313
|
+
readonly trigger: {
|
|
314
|
+
readonly id: string;
|
|
315
|
+
readonly author: string;
|
|
316
|
+
readonly authorId: string;
|
|
317
|
+
readonly sentAt: string;
|
|
318
|
+
readonly text: string;
|
|
319
|
+
/** Resolved per-wake trust tier (identity/wake-trust.ts). π΄ REQUIRED (OPE-596) β the field
|
|
320
|
+
* used to default to `principal`, the highest tier, on the reasoning that a DM partner IS the
|
|
321
|
+
* seat's principal. That reasoning is about the ROOM, and the tier is about the AUTHOR. See
|
|
322
|
+
* {@link TeamsSupervisorWakeInput}'s trigger tier. */
|
|
323
|
+
readonly trust: WakeTrust;
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
/**
|
|
327
|
+
* THE 1:1 (and group) DM WAKE for a first-classed Teams DM window (OPE-357) β the Teams twin of
|
|
328
|
+
* slack-events.ts's `slackDmWake` and discord-gateway.ts's {@link buildTeamsDmWake} sibling
|
|
329
|
+
* `buildDiscordDmWake`, and it renders through the SAME core renderer with no platform branch, so all
|
|
330
|
+
* three surfaces' DM envelopes are one dialect.
|
|
331
|
+
*
|
|
332
|
+
* ADDRESSING IS `direct-mention`, ALWAYS, doing the same two jobs it does on Slack/Discord. Semantically
|
|
333
|
+
* it is simply TRUE: everything said in a DM is said to the agent, which is why this path bypasses the
|
|
334
|
+
* engagement gate and the name-drop judge entirely β a DM IS ALWAYS ANSWERED. Mechanically it is
|
|
335
|
+
* LOAD-BEARING: `direct-mention` stamps `oe_addressing` through the divert, which marks the wake as
|
|
336
|
+
* OWED a reply and selects the `[direct]` preamble's reply mandate. π΄ IT IS NOT A DELIVERY PATH
|
|
337
|
+
* (OPE-1982): the addressed-prose bridge it used to arm is deleted, so a DM answer written as prose
|
|
338
|
+
* rather than a `reply` call is DROPPED on that channel like any other, and re-driven once.
|
|
339
|
+
*
|
|
340
|
+
* `reason` is `dm`, not `mention`: the envelope's reason describes the SURFACE SHAPE, and it is the
|
|
341
|
+
* one reason that survives the OPE-744 collapse of `mention` into `channel-activity` β no other
|
|
342
|
+
* attribute states "this is a direct-message room". NO `engagementTier` either β that dial raises
|
|
343
|
+
* the bar for AMBIENT watching, and a DM is always answered.
|
|
344
|
+
*
|
|
345
|
+
* NO PLATFORM-FETCH BACKSCROLL, EVER β and here that is not merely the native path's choice (as on
|
|
346
|
+
* Discord) but a platform fact: the Bot Connector exposes no DM message-history read and the Graph
|
|
347
|
+
* chat-history endpoint is deliberately unwired (teams-read.ts). So a fresh Teams DM generation
|
|
348
|
+
* carries the RECORDED TAIL and nothing else. Pure β unit-testable.
|
|
349
|
+
*/
|
|
350
|
+
export declare function buildTeamsDmWake(input: TeamsDmWakeInput): NormalizedWake;
|
|
351
|
+
//# sourceMappingURL=teams-supervisor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"teams-supervisor.d.ts","sourceRoot":"","sources":["../../../agent/channels/teams-supervisor.ts"],"names":[],"mappings":"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"}
|