@open-everywhere/provider-slack 0.7.0 → 0.8.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/agent/access/slack-attachment-fetch.ts +2 -1
- package/agent/app-manifest.ts +15 -1
- package/agent/channels/slack-agent-session.ts +249 -0
- package/agent/channels/slack-attachments.ts +20 -11
- package/agent/channels/slack-commands.ts +172 -12
- package/agent/channels/slack-context.ts +0 -5
- package/agent/channels/slack-events.ts +103 -29
- package/agent/channels/slack-follow-ups.ts +148 -0
- package/agent/channels/slack-front.ts +232 -26
- package/agent/channels/slack-home.ts +9 -3
- package/agent/channels/slack-identity.ts +9 -1
- package/agent/channels/slack-memory-canvas.ts +192 -51
- package/agent/channels/slack-origin-codec.ts +9 -0
- package/agent/channels/slack-post-arm.ts +68 -11
- package/agent/channels/slack-read.ts +27 -2
- package/agent/channels/slack-reply-blocks.ts +180 -0
- package/agent/channels/slack-reply-feedback.ts +75 -0
- package/agent/channels/slack-shortcut.ts +1 -1
- package/agent/channels/slack-voice-clips.ts +82 -0
- package/agent/channels/slack-wake-backscroll.ts +0 -5
- package/agent/channels/slack.ts +74 -13
- package/agent/docs-generated.ts +1282 -2
- package/agent/ops.ts +14 -21
- package/agent/register.ts +13 -0
- package/agent/setup/credentials.ts +17 -0
- package/agent/setup/page.ts +6 -3
- package/agent/surface-parity.ts +2 -0
- package/dist/agent/access/slack-attachment-fetch.d.ts.map +1 -1
- package/dist/agent/access/slack-attachment-fetch.js.map +1 -1
- package/dist/agent/app-manifest.d.ts.map +1 -1
- package/dist/agent/app-manifest.js +15 -1
- package/dist/agent/app-manifest.js.map +1 -1
- package/dist/agent/channels/slack-agent-session.d.ts +81 -0
- package/dist/agent/channels/slack-agent-session.d.ts.map +1 -0
- package/dist/agent/channels/slack-agent-session.js +198 -0
- package/dist/agent/channels/slack-agent-session.js.map +1 -0
- package/dist/agent/channels/slack-attachments.d.ts +11 -0
- package/dist/agent/channels/slack-attachments.d.ts.map +1 -1
- package/dist/agent/channels/slack-attachments.js +21 -14
- package/dist/agent/channels/slack-attachments.js.map +1 -1
- package/dist/agent/channels/slack-commands.d.ts +113 -10
- package/dist/agent/channels/slack-commands.d.ts.map +1 -1
- package/dist/agent/channels/slack-commands.js +146 -13
- package/dist/agent/channels/slack-commands.js.map +1 -1
- package/dist/agent/channels/slack-context.d.ts +1 -2
- package/dist/agent/channels/slack-context.d.ts.map +1 -1
- package/dist/agent/channels/slack-context.js +0 -4
- package/dist/agent/channels/slack-context.js.map +1 -1
- package/dist/agent/channels/slack-events.d.ts +46 -97
- package/dist/agent/channels/slack-events.d.ts.map +1 -1
- package/dist/agent/channels/slack-events.js +86 -21
- package/dist/agent/channels/slack-events.js.map +1 -1
- package/dist/agent/channels/slack-follow-ups.d.ts +44 -0
- package/dist/agent/channels/slack-follow-ups.d.ts.map +1 -0
- package/dist/agent/channels/slack-follow-ups.js +129 -0
- package/dist/agent/channels/slack-follow-ups.js.map +1 -0
- package/dist/agent/channels/slack-front.d.ts +28 -45
- package/dist/agent/channels/slack-front.d.ts.map +1 -1
- package/dist/agent/channels/slack-front.js +207 -22
- package/dist/agent/channels/slack-front.js.map +1 -1
- package/dist/agent/channels/slack-home.d.ts.map +1 -1
- package/dist/agent/channels/slack-home.js +10 -3
- package/dist/agent/channels/slack-home.js.map +1 -1
- package/dist/agent/channels/slack-identity.d.ts +7 -21
- package/dist/agent/channels/slack-identity.d.ts.map +1 -1
- package/dist/agent/channels/slack-identity.js +3 -1
- package/dist/agent/channels/slack-identity.js.map +1 -1
- package/dist/agent/channels/slack-memory-canvas.d.ts +21 -5
- package/dist/agent/channels/slack-memory-canvas.d.ts.map +1 -1
- package/dist/agent/channels/slack-memory-canvas.js +162 -52
- package/dist/agent/channels/slack-memory-canvas.js.map +1 -1
- package/dist/agent/channels/slack-origin-codec.d.ts.map +1 -1
- package/dist/agent/channels/slack-origin-codec.js +10 -0
- package/dist/agent/channels/slack-origin-codec.js.map +1 -1
- package/dist/agent/channels/slack-post-arm.d.ts +21 -1
- package/dist/agent/channels/slack-post-arm.d.ts.map +1 -1
- package/dist/agent/channels/slack-post-arm.js +57 -10
- package/dist/agent/channels/slack-post-arm.js.map +1 -1
- package/dist/agent/channels/slack-read.d.ts +11 -1
- package/dist/agent/channels/slack-read.d.ts.map +1 -1
- package/dist/agent/channels/slack-read.js +27 -3
- package/dist/agent/channels/slack-read.js.map +1 -1
- package/dist/agent/channels/slack-reply-blocks.d.ts +29 -0
- package/dist/agent/channels/slack-reply-blocks.d.ts.map +1 -0
- package/dist/agent/channels/slack-reply-blocks.js +172 -0
- package/dist/agent/channels/slack-reply-blocks.js.map +1 -0
- package/dist/agent/channels/slack-reply-feedback.d.ts +23 -0
- package/dist/agent/channels/slack-reply-feedback.d.ts.map +1 -0
- package/dist/agent/channels/slack-reply-feedback.js +63 -0
- package/dist/agent/channels/slack-reply-feedback.js.map +1 -0
- package/dist/agent/channels/slack-shortcut.d.ts +10 -0
- package/dist/agent/channels/slack-shortcut.d.ts.map +1 -1
- package/dist/agent/channels/slack-shortcut.js +1 -1
- package/dist/agent/channels/slack-shortcut.js.map +1 -1
- package/dist/agent/channels/slack-voice-clips.d.ts +16 -0
- package/dist/agent/channels/slack-voice-clips.d.ts.map +1 -0
- package/dist/agent/channels/slack-voice-clips.js +80 -0
- package/dist/agent/channels/slack-voice-clips.js.map +1 -0
- package/dist/agent/channels/slack-wake-backscroll.d.ts +0 -2
- package/dist/agent/channels/slack-wake-backscroll.d.ts.map +1 -1
- package/dist/agent/channels/slack-wake-backscroll.js +0 -4
- package/dist/agent/channels/slack-wake-backscroll.js.map +1 -1
- package/dist/agent/channels/slack.d.ts +22 -1
- package/dist/agent/channels/slack.d.ts.map +1 -1
- package/dist/agent/channels/slack.js +63 -13
- package/dist/agent/channels/slack.js.map +1 -1
- package/dist/agent/docs-generated.d.ts.map +1 -1
- package/dist/agent/docs-generated.js +1282 -2
- package/dist/agent/docs-generated.js.map +1 -1
- package/dist/agent/ops.d.ts +1 -1
- package/dist/agent/ops.d.ts.map +1 -1
- package/dist/agent/ops.js +15 -21
- package/dist/agent/ops.js.map +1 -1
- package/dist/agent/register.d.ts.map +1 -1
- package/dist/agent/register.js +12 -1
- package/dist/agent/register.js.map +1 -1
- package/dist/agent/setup/credentials.d.ts +12 -0
- package/dist/agent/setup/credentials.d.ts.map +1 -1
- package/dist/agent/setup/credentials.js +17 -0
- package/dist/agent/setup/credentials.js.map +1 -1
- package/dist/agent/setup/page.d.ts.map +1 -1
- package/dist/agent/setup/page.js +6 -3
- package/dist/agent/setup/page.js.map +1 -1
- package/dist/agent/surface-parity.d.ts.map +1 -1
- package/dist/agent/surface-parity.js +2 -0
- package/dist/agent/surface-parity.js.map +1 -1
- package/package.json +31 -3
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
// slackForm (slack-events.ts) — every Slack post here funnels through it.
|
|
6
6
|
import { slackForm, botDisplayName } from "./slack-events.js";
|
|
7
7
|
import { markdownToSlackMrkdwn } from "./slack-mrkdwn.js";
|
|
8
|
+
import { isSlackBlocksRefusal, slackReplyBlocks } from "./slack-reply-blocks.js";
|
|
8
9
|
import { markNotApplied } from "@open-everywhere/core/agent/adapter-api.js";
|
|
9
10
|
// --- OPE-508: the reply TIER signal, native on Slack ------------------------------------------
|
|
10
11
|
//
|
|
@@ -95,12 +96,35 @@ function classifiedPostError(res, message) {
|
|
|
95
96
|
const err = new Error(message);
|
|
96
97
|
return res?.ok === false ? markNotApplied(err) : err;
|
|
97
98
|
}
|
|
99
|
+
/**
|
|
100
|
+
* Post an ANSWER (OPE-2520): `base` carries the channel, the thread and the mrkdwn `text`; when the
|
|
101
|
+
* intent asks for source links or the native thumbs, the first attempt adds the answer's `blocks`
|
|
102
|
+
* (slack-reply-blocks.ts). A post Slack refuses FOR ITS BLOCKS is retried once without them, so a
|
|
103
|
+
* workspace that rejects a block still gets the answer. Only that refusal retries: Slack answered
|
|
104
|
+
* `ok:false`, so nothing posted and the plain retry cannot double the message.
|
|
105
|
+
*/
|
|
106
|
+
export async function postSlackAnswer(base, intent, replier, errPrefix, post = livePost, resolveDisplayName = botDisplayName) {
|
|
107
|
+
const blocks = slackReplyBlocks(base.get("text") ?? "", intent);
|
|
108
|
+
if (blocks === undefined)
|
|
109
|
+
return postSlackMessage(base, replier, errPrefix, post, resolveDisplayName);
|
|
110
|
+
const withBlocks = new URLSearchParams(base);
|
|
111
|
+
withBlocks.set("blocks", JSON.stringify(blocks));
|
|
112
|
+
try {
|
|
113
|
+
return await postSlackMessage(withBlocks, replier, errPrefix, post, resolveDisplayName);
|
|
114
|
+
}
|
|
115
|
+
catch (err) {
|
|
116
|
+
if (!isSlackBlocksRefusal(err))
|
|
117
|
+
throw err;
|
|
118
|
+
console.warn("[open-everywhere:slack-post-arm] Slack refused the answer's blocks; posting the text alone");
|
|
119
|
+
return postSlackMessage(base, replier, errPrefix, post, resolveDisplayName);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
98
122
|
/** MID-TURN: post via chat.postMessage (returns `ts`), thread-anchored when the trigger was threaded. */
|
|
99
|
-
async function dispatchSlackReply(target, text, replier) {
|
|
123
|
+
async function dispatchSlackReply(target, text, replier, intent) {
|
|
100
124
|
const body = new URLSearchParams({ channel: target.channelId, text: markdownToSlackMrkdwn(text) });
|
|
101
125
|
if (target.threadTs)
|
|
102
126
|
body.set("thread_ts", target.threadTs);
|
|
103
|
-
return
|
|
127
|
+
return postSlackAnswer(body, intent, replier, "reply couldn't post to Slack");
|
|
104
128
|
}
|
|
105
129
|
/**
|
|
106
130
|
* The `thread_ts` a unified reply posts under, or undefined for a top-level post. PURE, and the ONE
|
|
@@ -118,12 +142,12 @@ export function slackThreadTarget(origin) {
|
|
|
118
142
|
return anchor && anchor.length > 0 ? anchor : undefined;
|
|
119
143
|
}
|
|
120
144
|
/** UNIFIED: post into the wake origin's channel/thread (planSupervisorReply's exact semantics). */
|
|
121
|
-
async function liveSlackPost(origin, text, replier) {
|
|
145
|
+
async function liveSlackPost(origin, text, replier, intent) {
|
|
122
146
|
const body = new URLSearchParams({ channel: origin.channelId, text: markdownToSlackMrkdwn(text) });
|
|
123
147
|
const threadTarget = slackThreadTarget(origin);
|
|
124
148
|
if (threadTarget)
|
|
125
149
|
body.set("thread_ts", threadTarget);
|
|
126
|
-
return
|
|
150
|
+
return postSlackAnswer(body, intent, replier, "unified reply couldn't post to Slack");
|
|
127
151
|
}
|
|
128
152
|
/**
|
|
129
153
|
* THE COMPONENT PLANE (OPE-1060 S3) — the `actions` a {@link DirectMessageRequest} carries, rendered
|
|
@@ -197,9 +221,25 @@ async function deliverSlackDirectMessage(input) {
|
|
|
197
221
|
* posted) is the backstop under that, and its refusal arrives as a token-free throw the model reads.
|
|
198
222
|
* `chat.update` needs the same `chat:write` scope the post path already has.
|
|
199
223
|
*/
|
|
200
|
-
async function editSlackMessage(locus, messageId, text
|
|
201
|
-
|
|
202
|
-
|
|
224
|
+
export async function editSlackMessage(locus, messageId, text, intent,
|
|
225
|
+
/** The `chat.update` write — the live `slackForm` client; a test supplies a scripted one. */
|
|
226
|
+
form = slackForm) {
|
|
227
|
+
const rendered = markdownToSlackMrkdwn(text);
|
|
228
|
+
const body = new URLSearchParams({ channel: locus.channelId, ts: messageId, text: rendered });
|
|
229
|
+
// OPE-2520: an edit sends the answer's blocks too. A message posted with blocks shows its blocks,
|
|
230
|
+
// not its `text`, so an edit that sent `text` alone would leave the old answer on screen.
|
|
231
|
+
const blocks = slackReplyBlocks(rendered, intent);
|
|
232
|
+
if (blocks !== undefined)
|
|
233
|
+
body.set("blocks", JSON.stringify(blocks));
|
|
234
|
+
let res = await form("chat.update", body.toString());
|
|
235
|
+
if (res?.ok !== true && blocks !== undefined && isSlackBlocksRefusal(String(res?.error))) {
|
|
236
|
+
// Slack refused the BLOCKS, so the message did not change. Retry once with the text alone and an
|
|
237
|
+
// EMPTY block list: `chat.update` keeps a message's existing blocks unless new ones are sent
|
|
238
|
+
// (surface-message-ops.ts), so a retry that only dropped the field would leave the old answer on
|
|
239
|
+
// screen while Slack answered `ok`.
|
|
240
|
+
body.set("blocks", "[]");
|
|
241
|
+
res = await form("chat.update", body.toString());
|
|
242
|
+
}
|
|
203
243
|
if (res?.ok !== true) {
|
|
204
244
|
// DEFINITIVE (OPE-802): `chat.update` answers HTTP 200 with `ok:false`, so Slack read the request
|
|
205
245
|
// and decided against it — the message did not change. There is no status to carry that, so the
|
|
@@ -216,14 +256,21 @@ export const slackPostArm = {
|
|
|
216
256
|
return channelId ? { platform: "slack", channelId, threadTs: bag.threadTs } : null;
|
|
217
257
|
},
|
|
218
258
|
displayNameCapable: true,
|
|
219
|
-
dispatchReply: (target, text, replier) => dispatchSlackReply(target, text, replier),
|
|
220
|
-
|
|
259
|
+
dispatchReply: (target, text, replier, intent) => dispatchSlackReply(target, text, replier, intent),
|
|
260
|
+
// OPE-2558: a Slack target and a Slack origin name the same two facts, a channel and a thread.
|
|
261
|
+
originOfTarget: (target) => {
|
|
262
|
+
const t = target;
|
|
263
|
+
return { platform: "slack", channelId: t.channelId, ...(t.threadTs !== undefined && t.threadTs.length > 0 ? { threadTs: t.threadTs } : {}) };
|
|
264
|
+
},
|
|
265
|
+
dispatchUnified: (origin, text, deps, replier, intent) => deps.postSlack ? deps.postSlack(origin, text) : liveSlackPost(origin, text, replier, intent),
|
|
266
|
+
// OPE-2520: a `D…` channel is a 1:1 DM between the app and one person. A group DM is `G…`/`C…`.
|
|
267
|
+
isDirectConversation: (locus) => locus.channelId.startsWith("D"),
|
|
221
268
|
describeRedriveTarget: (origin) => {
|
|
222
269
|
const o = origin;
|
|
223
270
|
return `slack ${o.threadTs ? `thread in ${o.channelId}` : `channel ${o.channelId}`}`;
|
|
224
271
|
},
|
|
225
272
|
redriveContainerId: (origin) => origin.channelId,
|
|
226
273
|
deliverDirectMessage: deliverSlackDirectMessage,
|
|
227
|
-
editMessage: editSlackMessage,
|
|
274
|
+
editMessage: (locus, messageId, text, intent) => editSlackMessage(locus, messageId, text, intent),
|
|
228
275
|
};
|
|
229
276
|
//# sourceMappingURL=slack-post-arm.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"slack-post-arm.js","sourceRoot":"","sources":["../../../agent/channels/slack-post-arm.ts"],"names":[],"mappings":"AAAA,sGAAsG;AACtG,iGAAiG;AACjG,yFAAyF;AACzF,iGAAiG;AACjG,0EAA0E;AAE1E,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAC9D,OAAO,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,4CAA4C,CAAC;
|
|
1
|
+
{"version":3,"file":"slack-post-arm.js","sourceRoot":"","sources":["../../../agent/channels/slack-post-arm.ts"],"names":[],"mappings":"AAAA,sGAAsG;AACtG,iGAAiG;AACjG,yFAAyF;AACzF,iGAAiG;AACjG,0EAA0E;AAE1E,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAC9D,OAAO,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAC1D,OAAO,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AACjF,OAAO,EAAE,cAAc,EAAE,MAAM,4CAA4C,CAAC;AAkB5E,iGAAiG;AACjG,EAAE;AACF,sGAAsG;AACtG,qGAAqG;AACrG,mGAAmG;AACnG,uGAAuG;AACvG,qGAAqG;AACrG,iGAAiG;AACjG,EAAE;AACF,iGAAiG;AACjG,mGAAmG;AACnG,gGAAgG;AAChG,iGAAiG;AACjG,oGAAoG;AACpG,qGAAqG;AACrG,6FAA6F;AAC7F,oGAAoG;AACpG,2DAA2D;AAC3D,EAAE;AACF,mGAAmG;AACnG,oGAAoG;AACpG,iGAAiG;AAEjG;;;;qCAIqC;AACrC,MAAM,UAAU,kBAAkB,CAAC,SAA6B,EAAE,OAAiC;IACjG,IAAI,CAAC,OAAO,IAAI,CAAC,SAAS,IAAI,SAAS,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IACvE,OAAO,EAAE,QAAQ,EAAE,GAAG,SAAS,KAAK,OAAO,CAAC,SAAS,GAAG,EAAE,CAAC;AAC7D,CAAC;AAcD,MAAM,QAAQ,GAAgB,CAAC,IAAI,EAAE,EAAE,CAAC,SAAS,CAAC,kBAAkB,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;AAEvF;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,IAAqB,EACrB,OAAiC,EACjC,SAAiB,EACjB,IAAI,GAAgB,QAAQ,EAC5B,kBAAkB,GAAsC,cAAc;IAEtE,IAAI,iBAAiB,GAAG,KAAK,CAAC;IAC9B,IAAI,OAAO,GAAG,IAAI,CAAC;IACnB,IAAI,OAAO,EAAE,CAAC;QACZ,MAAM,IAAI,GAAG,MAAM,kBAAkB,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;QAC/D,MAAM,MAAM,GAAG,kBAAkB,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QACjD,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACnC,OAAO,GAAG,IAAI,eAAe,CAAC,IAAI,CAAC,CAAC;YACpC,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC;gBAAE,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;YAC/D,iBAAiB,GAAG,IAAI,CAAC;QAC3B,CAAC;IACH,CAAC;IACD,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,CAAC;IAChC,MAAM,EAAE,GAAG,OAAO,GAAG,EAAE,EAAE,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;IAC5D,IAAI,GAAG,EAAE,EAAE,KAAK,IAAI,IAAI,EAAE;QAAE,OAAO,EAAE,CAAC;IACtC,IAAI,iBAAiB,EAAE,CAAC;QACtB,4FAA4F;QAC5F,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/B,MAAM,OAAO,GAAG,OAAO,KAAK,EAAE,EAAE,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;QACrE,IAAI,KAAK,EAAE,EAAE,KAAK,IAAI,IAAI,OAAO;YAAE,OAAO,OAAO,CAAC;QAClD,MAAM,mBAAmB,CAAC,KAAK,EAAE,GAAG,SAAS,MAAO,KAAK,EAAE,KAAgB,IAAK,GAAG,EAAE,KAAgB,IAAI,wCAAwC,EAAE,CAAC,CAAC;IACvJ,CAAC;IACD,MAAM,mBAAmB,CAAC,GAAG,EAAE,GAAG,SAAS,MAAO,GAAG,EAAE,KAAgB,IAAI,wCAAwC,EAAE,CAAC,CAAC;AACzH,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,SAAS,mBAAmB,CAAC,GAAgC,EAAE,OAAe;IAC5E,MAAM,GAAG,GAAG,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC;IAC/B,OAAO,GAAG,EAAE,EAAE,KAAK,KAAK,CAAC,CAAC,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;AACvD,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,IAAqB,EACrB,MAA8B,EAC9B,OAAiC,EACjC,SAAiB,EACjB,IAAI,GAAgB,QAAQ,EAC5B,kBAAkB,GAAsC,cAAc;IAEtE,MAAM,MAAM,GAAG,gBAAgB,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,MAAM,CAAC,CAAC;IAChE,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,gBAAgB,CAAC,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,kBAAkB,CAAC,CAAC;IACtG,MAAM,UAAU,GAAG,IAAI,eAAe,CAAC,IAAI,CAAC,CAAC;IAC7C,UAAU,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC;IACjD,IAAI,CAAC;QACH,OAAO,MAAM,gBAAgB,CAAC,UAAU,EAAE,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,kBAAkB,CAAC,CAAC;IAC1F,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,CAAC,oBAAoB,CAAC,GAAG,CAAC;YAAE,MAAM,GAAG,CAAC;QAC1C,OAAO,CAAC,IAAI,CAAC,4FAA4F,CAAC,CAAC;QAC3G,OAAO,gBAAgB,CAAC,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,kBAAkB,CAAC,CAAC;IAC9E,CAAC;AACH,CAAC;AAED,yGAAyG;AACzG,KAAK,UAAU,kBAAkB,CAAC,MAAmB,EAAE,IAAY,EAAE,OAAsB,EAAE,MAAmB;IAC9G,MAAM,IAAI,GAAG,IAAI,eAAe,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,SAAS,EAAE,IAAI,EAAE,qBAAqB,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACnG,IAAI,MAAM,CAAC,QAAQ;QAAE,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;IAC5D,OAAO,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,8BAA8B,CAAC,CAAC;AAChF,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,iBAAiB,CAAC,MAAuD;IACvF,MAAM,MAAM,GAAG,MAAM,CAAC,QAAQ,IAAI,MAAM,CAAC,aAAa,CAAC;IACvD,OAAO,MAAM,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;AAC1D,CAAC;AAED,mGAAmG;AACnG,KAAK,UAAU,aAAa,CAAC,MAAmB,EAAE,IAAY,EAAE,OAAsB,EAAE,MAAmB;IACzG,MAAM,IAAI,GAAG,IAAI,eAAe,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,SAAS,EAAE,IAAI,EAAE,qBAAqB,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACnG,MAAM,YAAY,GAAG,iBAAiB,CAAC,MAAM,CAAC,CAAC;IAC/C,IAAI,YAAY;QAAE,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE,YAAY,CAAC,CAAC;IACtD,OAAO,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,sCAAsC,CAAC,CAAC;AACxF,CAAC;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,SAAS,6BAA6B,CAAC,OAAuC;IAC5E,MAAM,QAAQ,GAAG,OAAO;SACrB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,MAAM,IAAI,EAAE,CAAC;SAClG,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACX,SAAS,EAAE,CAAC,CAAC,EAAE;QACf,IAAI,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,KAAK,EAAE,IAAI,EAAE,YAAY,EAAE;QACxD,IAAI,EAAE,QAAQ;QACd,GAAG,CAAC,CAAC,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACtD,CAAC,CAAC,CAAC;IACN,OAAO,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;AACzE,CAAC;AAED;;;;;;;;;GASG;AACH,KAAK,UAAU,yBAAyB,CAAC,KAA2B;IAClE,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,oBAAoB,EAAE,IAAI,eAAe,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;IACnH,MAAM,OAAO,GAAG,MAAM,EAAE,OAAuC,CAAC;IAChE,MAAM,WAAW,GAAG,OAAO,OAAO,EAAE,EAAE,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;IAC7E,IAAI,MAAM,EAAE,EAAE,KAAK,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;QACxC,MAAM,IAAI,KAAK,CACb,iDAAkD,MAAM,EAAE,KAAgB,IAAI,wEAAwE,EAAE,CACzJ,CAAC;IACJ,CAAC;IACD,MAAM,QAAQ,GAAG,qBAAqB,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACnD,MAAM,WAAW,GAAG,KAAK,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,6BAA6B,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAC3G,MAAM,IAAI,GAAG,IAAI,eAAe,CAAC,EAAE,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC;IAC3E,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;QAC9B,kGAAkG;QAClG,6FAA6F;QAC7F,iCAAiC;QACjC,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC;IACnH,CAAC;IACD,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,kBAAkB,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;IACpE,MAAM,EAAE,GAAG,OAAO,MAAM,EAAE,EAAE,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;IAClE,IAAI,MAAM,EAAE,EAAE,KAAK,IAAI,IAAI,CAAC,EAAE,EAAE,CAAC;QAC/B,MAAM,IAAI,KAAK,CAAC,gCAAiC,MAAM,EAAE,KAAgB,IAAI,wCAAwC,EAAE,CAAC,CAAC;IAC3H,CAAC;IACD,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC;AACnD,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,KAAgB,EAChB,SAAiB,EACjB,IAAY,EACZ,MAAmB;AACnB,6FAA6F;AAC7F,IAAI,GAAmF,SAAS;IAEhG,MAAM,QAAQ,GAAG,qBAAqB,CAAC,IAAI,CAAC,CAAC;IAC7C,MAAM,IAAI,GAAG,IAAI,eAAe,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,SAAS,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC;IAC9F,kGAAkG;IAClG,0FAA0F;IAC1F,MAAM,MAAM,GAAG,gBAAgB,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IAClD,IAAI,MAAM,KAAK,SAAS;QAAE,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC;IACrE,IAAI,GAAG,GAAG,MAAM,IAAI,CAAC,aAAa,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;IACrD,IAAI,GAAG,EAAE,EAAE,KAAK,IAAI,IAAI,MAAM,KAAK,SAAS,IAAI,oBAAoB,CAAC,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC;QACzF,iGAAiG;QACjG,6FAA6F;QAC7F,iGAAiG;QACjG,oCAAoC;QACpC,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;QACzB,GAAG,GAAG,MAAM,IAAI,CAAC,aAAa,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;IACnD,CAAC;IACD,IAAI,GAAG,EAAE,EAAE,KAAK,IAAI,EAAE,CAAC;QACrB,kGAAkG;QAClG,gGAAgG;QAChG,gGAAgG;QAChG,8EAA8E;QAC9E,MAAM,cAAc,CAClB,IAAI,KAAK,CAAC,kDAAmD,GAAG,EAAE,KAAgB,IAAI,oDAAoD,EAAE,CAAC,CAC9I,CAAC;IACJ,CAAC;AACH,CAAC;AAED,MAAM,CAAC,MAAM,YAAY,GAAY;IACnC,QAAQ,EAAE,OAAO;IACjB,aAAa,EAAE,CAAC,GAAqB,EAAsB,EAAE;QAC3D,MAAM,SAAS,GAAG,GAAG,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QACvC,iFAAiF;QACjF,OAAO,SAAS,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IACrF,CAAC;IACD,kBAAkB,EAAE,IAAI;IACxB,aAAa,EAAE,CAAC,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,CAAC,kBAAkB,CAAC,MAAqB,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,CAAC;IAClH,+FAA+F;IAC/F,cAAc,EAAE,CAAC,MAAM,EAAE,EAAE;QACzB,MAAM,CAAC,GAAG,MAAqB,CAAC;QAChC,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC,CAAC,QAAQ,KAAK,SAAS,IAAI,CAAC,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;IAC/I,CAAC;IACD,eAAe,EAAE,CAAC,MAAM,EAAE,IAAI,EAAE,IAAsB,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,CACzE,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,MAAqB,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,MAAqB,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,CAAC;IAC5H,gGAAgG;IAChG,oBAAoB,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,UAAU,CAAC,GAAG,CAAC;IAChE,qBAAqB,EAAE,CAAC,MAAM,EAAE,EAAE;QAChC,MAAM,CAAC,GAAG,MAAqB,CAAC;QAChC,OAAO,SAAS,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC;IACvF,CAAC;IACD,kBAAkB,EAAE,CAAC,MAAM,EAAE,EAAE,CAAE,MAAsB,CAAC,SAAS;IACjE,oBAAoB,EAAE,yBAAyB;IAC/C,WAAW,EAAE,CAAC,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,CAAC,gBAAgB,CAAC,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,CAAC;CAClG,CAAC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ChannelScopeError, type BindableContext, type ReadScopeAuditDeps, type RenderedLine, type WakeReadAddress } from "@open-everywhere/core/agent/adapter-api.js";
|
|
1
|
+
import { ChannelScopeError, type BindableContext, type ReadScopeAuditDeps, type ReadFile, type RenderedLine, type WakeReadAddress } from "@open-everywhere/core/agent/adapter-api.js";
|
|
2
2
|
import { type SlackMemberProbe } from "./slack-events.js";
|
|
3
3
|
export { ChannelScopeError };
|
|
4
4
|
/**
|
|
@@ -47,7 +47,17 @@ export interface RenderedMessage {
|
|
|
47
47
|
/** A machine author (`bot_id` present). Excluded from the probe: a bot is below a member but is
|
|
48
48
|
* not a person outside the org — the same exclusion access/taint-signal.ts makes for `relay`. */
|
|
49
49
|
readonly bot?: boolean;
|
|
50
|
+
/** The message's files: id, name and media type only (core channel-read.ts `ReadFile`). */
|
|
51
|
+
readonly files?: readonly ReadFile[];
|
|
50
52
|
}
|
|
53
|
+
/**
|
|
54
|
+
* A Slack message's `files` array, reduced to what a reader needs: the file id (`F…`, the id
|
|
55
|
+
* `describe_image` resolves as an attachment), the name (else the title) and the `mimetype`.
|
|
56
|
+
* Every other field is dropped, `url_private` and the permalinks above all: a reader that held a
|
|
57
|
+
* URL could fetch outside the governed attachment seam. A deleted file (`mode: "tombstone"`) and an
|
|
58
|
+
* entry with no id are skipped. PURE.
|
|
59
|
+
*/
|
|
60
|
+
export declare function slackMessageFiles(raw: unknown): ReadFile[];
|
|
51
61
|
/**
|
|
52
62
|
* Normalize a raw Slack messages array (history/replies) to rendered lines, oldest-first.
|
|
53
63
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"slack-read.d.ts","sourceRoot":"","sources":["../../../agent/channels/slack-read.ts"],"names":[],"mappings":"AAgBA,OAAO,EAOL,iBAAiB,EAEjB,KAAK,eAAe,EACpB,KAAK,kBAAkB,EACvB,KAAK,YAAY,EACjB,KAAK,eAAe,EAErB,MAAM,4CAA4C,CAAC;AAIpD,OAAO,EAAuB,KAAK,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAM/E,OAAO,EAAE,iBAAiB,EAAE,CAAC;AAW7B;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,eAAe,GAAG;IAAE,GAAG,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAa7F;AAED;;;;;GAKG;AACH,wBAAsB,oBAAoB,CAAC,GAAG,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAc5H;AAED,UAAU,iBAAiB;IACzB,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACjC;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAcpI;AAED,oEAAoE;AACpE,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB;wGACoG;IACpG,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B;sGACkG;IAClG,QAAQ,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"slack-read.d.ts","sourceRoot":"","sources":["../../../agent/channels/slack-read.ts"],"names":[],"mappings":"AAgBA,OAAO,EAOL,iBAAiB,EAEjB,KAAK,eAAe,EACpB,KAAK,kBAAkB,EACvB,KAAK,QAAQ,EACb,KAAK,YAAY,EACjB,KAAK,eAAe,EAErB,MAAM,4CAA4C,CAAC;AAIpD,OAAO,EAAuB,KAAK,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAM/E,OAAO,EAAE,iBAAiB,EAAE,CAAC;AAW7B;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,eAAe,GAAG;IAAE,GAAG,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAa7F;AAED;;;;;GAKG;AACH,wBAAsB,oBAAoB,CAAC,GAAG,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAc5H;AAED,UAAU,iBAAiB;IACzB,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACjC;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAcpI;AAED,oEAAoE;AACpE,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB;wGACoG;IACpG,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B;sGACkG;IAClG,QAAQ,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC;IACvB,2FAA2F;IAC3F,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,QAAQ,EAAE,CAAC;CACtC;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,OAAO,GAAG,QAAQ,EAAE,CAU1D;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,GAAE;IAAE,WAAW,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,eAAe,EAAE,CAsBpG;AAUD,oGAAoG;AACpG,MAAM,MAAM,aAAa,GAAG,OAAO,aAAa,CAAC;AA2BjD,2FAA2F;AAC3F,eAAO,MAAM,gBAAgB;IAC3B,QAAQ,EAAE,OAAO;IACjB;;;;;;;OAOG;IACH,WAAW,MAAM,eAAe,GAAG,eAAe,GAAG,SAAS;IAMxD,WAAW,MAAM,eAAe,WAAW,MAAM,UAAU,MAAM,SAAQ,aAAa,GAAmB,OAAO,CAAC,SAAS,YAAY,EAAE,CAAC;IAKzI,UAAU,MAAM,eAAe,WAAW,MAAM,YAAY,MAAM,UAAU,MAAM,SAAQ,aAAa,GAAmB,OAAO,CAAC,SAAS,YAAY,EAAE,CAAC;IAKhK;;;;2DAIuD;IACjD,gBAAgB,MAAM,eAAe,SAAS,SAAS,YAAY,EAAE,UAAS,gBAAgB,GAAyB,OAAO,CAAC,SAAS,MAAM,EAAE,CAAC;CAWxJ,CAAC"}
|
|
@@ -98,6 +98,27 @@ export async function callSlackRead(operation, params) {
|
|
|
98
98
|
throw markNotApplied(new Error(`Slack ${operation} failed: ${json.error ?? "unknown error"}`));
|
|
99
99
|
return json;
|
|
100
100
|
}
|
|
101
|
+
/**
|
|
102
|
+
* A Slack message's `files` array, reduced to what a reader needs: the file id (`F…`, the id
|
|
103
|
+
* `describe_image` resolves as an attachment), the name (else the title) and the `mimetype`.
|
|
104
|
+
* Every other field is dropped, `url_private` and the permalinks above all: a reader that held a
|
|
105
|
+
* URL could fetch outside the governed attachment seam. A deleted file (`mode: "tombstone"`) and an
|
|
106
|
+
* entry with no id are skipped. PURE.
|
|
107
|
+
*/
|
|
108
|
+
export function slackMessageFiles(raw) {
|
|
109
|
+
if (!Array.isArray(raw))
|
|
110
|
+
return [];
|
|
111
|
+
const out = [];
|
|
112
|
+
for (const f of raw) {
|
|
113
|
+
if (typeof f !== "object" || f === null)
|
|
114
|
+
continue;
|
|
115
|
+
if (typeof f.id !== "string" || f.id.length === 0 || f.mode === "tombstone")
|
|
116
|
+
continue;
|
|
117
|
+
const name = typeof f.name === "string" && f.name.length > 0 ? f.name : typeof f.title === "string" ? f.title : "";
|
|
118
|
+
out.push({ id: f.id, name, ...(typeof f.mimetype === "string" && f.mimetype.length > 0 ? { mimetype: f.mimetype } : {}) });
|
|
119
|
+
}
|
|
120
|
+
return out;
|
|
121
|
+
}
|
|
101
122
|
/**
|
|
102
123
|
* Normalize a raw Slack messages array (history/replies) to rendered lines, oldest-first.
|
|
103
124
|
*
|
|
@@ -115,10 +136,12 @@ export function renderMessages(raw, opts = {}) {
|
|
|
115
136
|
return [];
|
|
116
137
|
const out = [];
|
|
117
138
|
for (const m of raw) {
|
|
118
|
-
|
|
119
|
-
|
|
139
|
+
const files = slackMessageFiles(m.files);
|
|
140
|
+
// Skip joins, edits and system lines. A `file_share` line is a person's upload, so it stays.
|
|
141
|
+
if (typeof m.subtype === "string" && m.subtype.length > 0 && !(m.subtype === "file_share" && files.length > 0))
|
|
142
|
+
continue;
|
|
120
143
|
const text = typeof m.text === "string" ? m.text : "";
|
|
121
|
-
if (!text)
|
|
144
|
+
if (!text && files.length === 0)
|
|
122
145
|
continue;
|
|
123
146
|
const user = typeof m.user === "string" && m.user.length > 0 ? m.user : undefined;
|
|
124
147
|
const botId = typeof m.bot_id === "string" && m.bot_id.length > 0 ? m.bot_id : undefined;
|
|
@@ -127,6 +150,7 @@ export function renderMessages(raw, opts = {}) {
|
|
|
127
150
|
ts: m.ts ?? "",
|
|
128
151
|
text,
|
|
129
152
|
...(botId !== undefined ? { bot: true } : user !== undefined ? { authorId: user } : {}),
|
|
153
|
+
...(files.length > 0 ? { files } : {}),
|
|
130
154
|
});
|
|
131
155
|
}
|
|
132
156
|
// conversations.history returns newest-first; replies returns oldest-first.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"slack-read.js","sourceRoot":"","sources":["../../../agent/channels/slack-read.ts"],"names":[],"mappings":"AAAA,sFAAsF;AACtF,wFAAwF;AACxF,wFAAwF;AACxF,2FAA2F;AAC3F,uFAAuF;AACvF,6EAA6E;AAC7E,EAAE;AACF,4FAA4F;AAC5F,qGAAqG;AACrG,4FAA4F;AAC5F,gGAAgG;AAChG,iGAAiG;AACjG,0CAA0C;AAE1C,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,EACL,uBAAuB,EACvB,QAAQ,EACR,SAAS,EACT,gBAAgB,EAChB,gBAAgB,EAChB,oBAAoB,EACpB,iBAAiB,EACjB,cAAc,
|
|
1
|
+
{"version":3,"file":"slack-read.js","sourceRoot":"","sources":["../../../agent/channels/slack-read.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { PostIntent, SourceLink } from "@open-everywhere/core/agent/adapter-api.js";
|
|
2
|
+
/** The action id of the native thumbs control. Exact, never a prefix: no other door uses it. */
|
|
3
|
+
export declare const SLACK_FEEDBACK_ACTION_ID = "oe_feedback";
|
|
4
|
+
/** The two button values, which ARE the rating a click records. */
|
|
5
|
+
export declare const SLACK_FEEDBACK_VALUE_UP = "up";
|
|
6
|
+
export declare const SLACK_FEEDBACK_VALUE_DOWN = "down";
|
|
7
|
+
/** The action id prefix of a follow-up button: `oe_followup:<n>`. No other door uses it. */
|
|
8
|
+
export declare const SLACK_FOLLOW_UP_ACTION_PREFIX = "oe_followup:";
|
|
9
|
+
/** The block id of the follow-up row, so a press can find and remove it (`slack-follow-ups.ts`). */
|
|
10
|
+
export declare const SLACK_FOLLOW_UP_BLOCK_ID = "oe_followups";
|
|
11
|
+
/** A control (`Cc`) or format (`Cf`) character: it draws nothing on a button. The follow-up row and
|
|
12
|
+
* the press parse (`slack-follow-ups.ts`) both refuse a text that holds one. */
|
|
13
|
+
export declare const SLACK_INVISIBLE_CHARACTER: RegExp;
|
|
14
|
+
/**
|
|
15
|
+
* Cut mrkdwn into section-sized chunks at line ends. A line longer than a chunk is cut by code point.
|
|
16
|
+
* A chunk that ends inside a ``` fence closes it, and the next chunk reopens it, so each chunk renders
|
|
17
|
+
* on its own. Exported for the unit test.
|
|
18
|
+
*/
|
|
19
|
+
export declare function chunkSlackSectionText(text: string, max?: number): string[];
|
|
20
|
+
/** The numbered source links as ONE line of mrkdwn: `*Sources:* [1] <url|title> · [2] <url|title>`. */
|
|
21
|
+
export declare function slackSourcesLine(sources: readonly SourceLink[]): string;
|
|
22
|
+
/**
|
|
23
|
+
* The blocks for one answer, or `undefined` when the intent asks for no links, no thumbs and no follow-ups — the
|
|
24
|
+
* post then sends `text` alone, as before OPE-2520. `mrkdwn` is the already-converted answer text.
|
|
25
|
+
*/
|
|
26
|
+
export declare function slackReplyBlocks(mrkdwn: string, intent: PostIntent | undefined): Record<string, unknown>[] | undefined;
|
|
27
|
+
/** True when a Slack error names the blocks as the reason it refused the post. */
|
|
28
|
+
export declare function isSlackBlocksRefusal(err: unknown): boolean;
|
|
29
|
+
//# sourceMappingURL=slack-reply-blocks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slack-reply-blocks.d.ts","sourceRoot":"","sources":["../../../agent/channels/slack-reply-blocks.ts"],"names":[],"mappings":"AAwBA,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,4CAA4C,CAAC;AAEzF,gGAAgG;AAChG,eAAO,MAAM,wBAAwB,gBAAgB,CAAC;AAEtD,mEAAmE;AACnE,eAAO,MAAM,uBAAuB,OAAO,CAAC;AAC5C,eAAO,MAAM,yBAAyB,SAAS,CAAC;AAEhD,4FAA4F;AAC5F,eAAO,MAAM,6BAA6B,iBAAiB,CAAC;AAE5D,oGAAoG;AACpG,eAAO,MAAM,wBAAwB,iBAAiB,CAAC;AAEvD;iFACiF;AACjF,eAAO,MAAM,yBAAyB,QAAoB,CAAC;AAgB3D;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,GAAE,MAAyB,GAAG,MAAM,EAAE,CAqC5F;AAED,wGAAwG;AACxG,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,SAAS,UAAU,EAAE,GAAG,MAAM,CAGvE;AAgDD;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,SAAS,CAgBtH;AAED,kFAAkF;AAClF,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAG1D"}
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
// slack-reply-blocks — the Block Kit shape of an agent's ANSWER on Slack (OPE-2520): the answer's text,
|
|
2
|
+
// its numbered source links, Slack's native thumbs up / down, and the suggested follow-ups (OPE-2516).
|
|
3
|
+
//
|
|
4
|
+
// A reply used to post `text` alone. An answer now also carries two blocks Slack draws natively:
|
|
5
|
+
// • a `context` block with the numbered source links — `[1] Launch checklist · [2] OPE-42 Fix login`,
|
|
6
|
+
// the link on each title. Only present when the reply choke point decided links may show (a 1:1 DM,
|
|
7
|
+
// the reach rule held — `reply-provenance.ts`).
|
|
8
|
+
// • a `context_actions` block holding one `feedback_buttons` element — Slack's own thumbs up / down
|
|
9
|
+
// for an AI app's message. A click arrives at the interactivity URL as a `block_actions` payload
|
|
10
|
+
// with the action id {@link SLACK_FEEDBACK_ACTION_ID}, and `slack-front.ts` records it.
|
|
11
|
+
//
|
|
12
|
+
// • an `actions` block with up to three suggested FOLLOW-UPS (OPE-2516) — one button each, labelled
|
|
13
|
+
// with the whole text a press sends. A press arrives as a `block_actions` payload whose action id
|
|
14
|
+
// starts {@link SLACK_FOLLOW_UP_ACTION_PREFIX}, and `slack-follow-ups.ts` turns it into the
|
|
15
|
+
// person's next message. Only present when the choke point decided they may show (a 1:1 DM).
|
|
16
|
+
//
|
|
17
|
+
// 🔴 ONCE `blocks` IS PRESENT, SLACK SHOWS THE BLOCKS AND NOT `text`. `text` becomes the notification
|
|
18
|
+
// fallback only. So the answer itself must ride the blocks too, as `section` blocks — and a section
|
|
19
|
+
// holds at most 3000 characters, so a long answer is cut into several. A cut never splits a code fence
|
|
20
|
+
// open: a chunk that ends inside a ``` fence closes it, and the next chunk opens it again.
|
|
21
|
+
//
|
|
22
|
+
// 🔴 A REFUSED BLOCK MUST NEVER COST THE ANSWER. The arm retries a post Slack refused for its blocks
|
|
23
|
+
// (`invalid_blocks`) once without them, so a workspace that rejects a block shows the plain answer.
|
|
24
|
+
/** The action id of the native thumbs control. Exact, never a prefix: no other door uses it. */
|
|
25
|
+
export const SLACK_FEEDBACK_ACTION_ID = "oe_feedback";
|
|
26
|
+
/** The two button values, which ARE the rating a click records. */
|
|
27
|
+
export const SLACK_FEEDBACK_VALUE_UP = "up";
|
|
28
|
+
export const SLACK_FEEDBACK_VALUE_DOWN = "down";
|
|
29
|
+
/** The action id prefix of a follow-up button: `oe_followup:<n>`. No other door uses it. */
|
|
30
|
+
export const SLACK_FOLLOW_UP_ACTION_PREFIX = "oe_followup:";
|
|
31
|
+
/** The block id of the follow-up row, so a press can find and remove it (`slack-follow-ups.ts`). */
|
|
32
|
+
export const SLACK_FOLLOW_UP_BLOCK_ID = "oe_followups";
|
|
33
|
+
/** A control (`Cc`) or format (`Cf`) character: it draws nothing on a button. The follow-up row and
|
|
34
|
+
* the press parse (`slack-follow-ups.ts`) both refuse a text that holds one. */
|
|
35
|
+
export const SLACK_INVISIBLE_CHARACTER = /[\p{Cc}\p{Cf}]/u;
|
|
36
|
+
/** Slack's cap on a button label, which is also the core cap on a follow-up's length. */
|
|
37
|
+
const BUTTON_TEXT_MAX = 75;
|
|
38
|
+
/** Slack's cap on one section block's text. */
|
|
39
|
+
const SECTION_TEXT_MAX = 3000;
|
|
40
|
+
/** Slack's cap on blocks in one message. */
|
|
41
|
+
const MAX_BLOCKS = 50;
|
|
42
|
+
/** Escape the three characters Slack's mrkdwn reads as control characters, for a host-written label. */
|
|
43
|
+
function escapeMrkdwn(text) {
|
|
44
|
+
return text.replace(/&/gu, "&").replace(/</gu, "<").replace(/>/gu, ">");
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Cut mrkdwn into section-sized chunks at line ends. A line longer than a chunk is cut by code point.
|
|
48
|
+
* A chunk that ends inside a ``` fence closes it, and the next chunk reopens it, so each chunk renders
|
|
49
|
+
* on its own. Exported for the unit test.
|
|
50
|
+
*/
|
|
51
|
+
export function chunkSlackSectionText(text, max = SECTION_TEXT_MAX) {
|
|
52
|
+
const fence = "```";
|
|
53
|
+
const reopen = `${fence}\n`;
|
|
54
|
+
// Room for the closing fence a chunk may need, and the opening fence the next chunk then carries.
|
|
55
|
+
const budget = max - 2 * reopen.length;
|
|
56
|
+
const chunks = [];
|
|
57
|
+
let cur = "";
|
|
58
|
+
// True while the text placed so far stands inside an open ``` fence.
|
|
59
|
+
let open = false;
|
|
60
|
+
const push = () => {
|
|
61
|
+
chunks.push(open ? `${cur}\n${fence}` : cur);
|
|
62
|
+
cur = open ? reopen : "";
|
|
63
|
+
};
|
|
64
|
+
for (const line of text.split("\n")) {
|
|
65
|
+
let rest = line;
|
|
66
|
+
for (;;) {
|
|
67
|
+
const sep = cur.length === 0 || cur === reopen ? "" : "\n";
|
|
68
|
+
if (cur.length + sep.length + rest.length <= budget) {
|
|
69
|
+
cur += sep + rest;
|
|
70
|
+
break;
|
|
71
|
+
}
|
|
72
|
+
if (sep.length > 0) {
|
|
73
|
+
push();
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
// The line alone does not fit an empty chunk: cut it by code point, never inside a character.
|
|
77
|
+
const cps = Array.from(rest);
|
|
78
|
+
const room = budget - cur.length;
|
|
79
|
+
cur += cps.slice(0, room).join("");
|
|
80
|
+
rest = cps.slice(room).join("");
|
|
81
|
+
push();
|
|
82
|
+
}
|
|
83
|
+
// An odd count of fences on the line opens or closes a fence.
|
|
84
|
+
if ((line.split(fence).length - 1) % 2 === 1)
|
|
85
|
+
open = !open;
|
|
86
|
+
}
|
|
87
|
+
if (cur.length > 0 && cur !== reopen)
|
|
88
|
+
chunks.push(cur);
|
|
89
|
+
return chunks;
|
|
90
|
+
}
|
|
91
|
+
/** The numbered source links as ONE line of mrkdwn: `*Sources:* [1] <url|title> · [2] <url|title>`. */
|
|
92
|
+
export function slackSourcesLine(sources) {
|
|
93
|
+
const items = sources.map((s, i) => `[${i + 1}] <${s.url}|${escapeMrkdwn(s.name)}>`);
|
|
94
|
+
return `*Sources:* ${items.join(" · ")}`;
|
|
95
|
+
}
|
|
96
|
+
/** Slack's native thumbs up / down, as one `context_actions` block. */
|
|
97
|
+
function slackFeedbackBlock() {
|
|
98
|
+
return {
|
|
99
|
+
type: "context_actions",
|
|
100
|
+
elements: [
|
|
101
|
+
{
|
|
102
|
+
type: "feedback_buttons",
|
|
103
|
+
action_id: SLACK_FEEDBACK_ACTION_ID,
|
|
104
|
+
positive_button: {
|
|
105
|
+
text: { type: "plain_text", text: "Good response" },
|
|
106
|
+
accessibility_label: "Mark this response as good",
|
|
107
|
+
value: SLACK_FEEDBACK_VALUE_UP,
|
|
108
|
+
},
|
|
109
|
+
negative_button: {
|
|
110
|
+
text: { type: "plain_text", text: "Bad response" },
|
|
111
|
+
accessibility_label: "Mark this response as bad",
|
|
112
|
+
value: SLACK_FEEDBACK_VALUE_DOWN,
|
|
113
|
+
},
|
|
114
|
+
},
|
|
115
|
+
],
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* The suggested follow-ups as one `actions` block: one button per item, its label the whole text and
|
|
120
|
+
* its value the same text. An item over Slack's label cap, or holding an invisible character, is
|
|
121
|
+
* dropped here too: the friendly pass runs after core's check, and a resolved name can lengthen a label
|
|
122
|
+
* or bring a joiner back in an emoji. Over the cap, Slack would refuse the block and cost the thumbs as
|
|
123
|
+
* well. With an invisible character, the press parse would refuse the press, so the button would do
|
|
124
|
+
* nothing.
|
|
125
|
+
*/
|
|
126
|
+
function slackFollowUpsBlock(followUps) {
|
|
127
|
+
const fit = followUps.filter((f) => f.length > 0 && Array.from(f).length <= BUTTON_TEXT_MAX && !SLACK_INVISIBLE_CHARACTER.test(f));
|
|
128
|
+
if (fit.length === 0)
|
|
129
|
+
return undefined;
|
|
130
|
+
return {
|
|
131
|
+
type: "actions",
|
|
132
|
+
block_id: SLACK_FOLLOW_UP_BLOCK_ID,
|
|
133
|
+
elements: fit.map((text, i) => ({
|
|
134
|
+
type: "button",
|
|
135
|
+
action_id: `${SLACK_FOLLOW_UP_ACTION_PREFIX}${i}`,
|
|
136
|
+
text: { type: "plain_text", text, emoji: true },
|
|
137
|
+
value: text,
|
|
138
|
+
})),
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* The blocks for one answer, or `undefined` when the intent asks for no links, no thumbs and no follow-ups — the
|
|
143
|
+
* post then sends `text` alone, as before OPE-2520. `mrkdwn` is the already-converted answer text.
|
|
144
|
+
*/
|
|
145
|
+
export function slackReplyBlocks(mrkdwn, intent) {
|
|
146
|
+
const sources = intent?.sources ?? [];
|
|
147
|
+
const feedback = intent?.feedback === true;
|
|
148
|
+
const followUps = slackFollowUpsBlock(intent?.followUps ?? []);
|
|
149
|
+
if (sources.length === 0 && !feedback && followUps === undefined)
|
|
150
|
+
return undefined;
|
|
151
|
+
const blocks = [];
|
|
152
|
+
for (const chunk of chunkSlackSectionText(mrkdwn)) {
|
|
153
|
+
if (chunk.trim().length === 0)
|
|
154
|
+
continue;
|
|
155
|
+
blocks.push({ type: "section", text: { type: "mrkdwn", text: chunk } });
|
|
156
|
+
}
|
|
157
|
+
if (sources.length > 0)
|
|
158
|
+
blocks.push({ type: "context", elements: [{ type: "mrkdwn", text: slackSourcesLine(sources) }] });
|
|
159
|
+
if (feedback)
|
|
160
|
+
blocks.push(slackFeedbackBlock());
|
|
161
|
+
// The next steps sit last, under the answer and its thumbs.
|
|
162
|
+
if (followUps !== undefined)
|
|
163
|
+
blocks.push(followUps);
|
|
164
|
+
// An answer too long for Slack's block cap posts as text alone: the answer matters more than the extras.
|
|
165
|
+
return blocks.length > MAX_BLOCKS ? undefined : blocks;
|
|
166
|
+
}
|
|
167
|
+
/** True when a Slack error names the blocks as the reason it refused the post. */
|
|
168
|
+
export function isSlackBlocksRefusal(err) {
|
|
169
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
170
|
+
return /invalid_blocks|invalid_attachments|invalid_blocks_format|msg_blocks_too_long/u.test(message);
|
|
171
|
+
}
|
|
172
|
+
//# sourceMappingURL=slack-reply-blocks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slack-reply-blocks.js","sourceRoot":"","sources":["../../../agent/channels/slack-reply-blocks.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { type ReplyFeedbackClick, type ReplyFeedbackRating } from "@open-everywhere/core/agent/adapter-api.js";
|
|
2
|
+
/** One parsed click on the native thumbs control. IDS ONLY. */
|
|
3
|
+
export interface ParsedSlackFeedbackClick {
|
|
4
|
+
readonly rating: ReplyFeedbackRating;
|
|
5
|
+
readonly userId: string;
|
|
6
|
+
readonly channelId: string;
|
|
7
|
+
readonly messageTs: string;
|
|
8
|
+
readonly teamId?: string;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Parse a decoded interactivity payload into a thumbs click, or `undefined` when it is not one: not a
|
|
12
|
+
* `block_actions`, no `oe_feedback` action, a value other than `up`/`down`, or a missing user, channel
|
|
13
|
+
* or message. Pure and total: it never throws.
|
|
14
|
+
*/
|
|
15
|
+
export declare function parseSlackFeedbackClick(payload: unknown): ParsedSlackFeedbackClick | undefined;
|
|
16
|
+
/** What {@link routeSlackFeedbackClick} writes through. The live default is core's audit writer. */
|
|
17
|
+
export interface SlackFeedbackRouteDeps {
|
|
18
|
+
readonly record?: (click: ReplyFeedbackClick) => Promise<boolean>;
|
|
19
|
+
}
|
|
20
|
+
/** Record one thumbs click as a `reply.feedback` row, under the clicked conversation's partition.
|
|
21
|
+
* Answers whether the row was written. Never throws. */
|
|
22
|
+
export declare function routeSlackFeedbackClick(click: ParsedSlackFeedbackClick, deps?: SlackFeedbackRouteDeps): Promise<boolean>;
|
|
23
|
+
//# sourceMappingURL=slack-reply-feedback.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slack-reply-feedback.d.ts","sourceRoot":"","sources":["../../../agent/channels/slack-reply-feedback.ts"],"names":[],"mappings":"AAYA,OAAO,EAAyC,KAAK,kBAAkB,EAAE,KAAK,mBAAmB,EAAE,MAAM,4CAA4C,CAAC;AAItJ,+DAA+D;AAC/D,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,MAAM,EAAE,mBAAmB,CAAC;IACrC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AAKD;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,OAAO,GAAG,wBAAwB,GAAG,SAAS,CAc9F;AAED,oGAAoG;AACpG,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,kBAAkB,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CACnE;AAED;yDACyD;AACzD,wBAAsB,uBAAuB,CAAC,KAAK,EAAE,wBAAwB,EAAE,IAAI,GAAE,sBAA2B,GAAG,OAAO,CAAC,OAAO,CAAC,CAkBlI"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
// slack-reply-feedback — a click on Slack's native thumbs up / down under an agent answer (OPE-2520).
|
|
2
|
+
//
|
|
3
|
+
// The answer carries one `feedback_buttons` element (slack-reply-blocks.ts). Slack sends a click to the
|
|
4
|
+
// app's interactivity URL as a signed `block_actions` payload whose action id is exactly
|
|
5
|
+
// `oe_feedback` and whose value is `up` or `down`. The front route classifies it (`slack-front.ts`,
|
|
6
|
+
// FrontDecision `feedback-click`), runs the tenant fence, acknowledges with an empty 200, and hands it
|
|
7
|
+
// here. This module turns it into core's surface-neutral click and writes the `reply.feedback` row.
|
|
8
|
+
//
|
|
9
|
+
// 🔴 ONLY OUR OWN MESSAGES CARRY THE BUTTON. Slack sends a `block_actions` payload only for a block the
|
|
10
|
+
// app itself posted, so a click always rates one of this app's messages: no bot-author check is needed,
|
|
11
|
+
// unlike the reaction road, where a 👍 can land on anyone's message.
|
|
12
|
+
import { recordReplyFeedback, resolvePartition } from "@open-everywhere/core/agent/adapter-api.js";
|
|
13
|
+
import { bindableForSlackIds } from "./slack-events.js";
|
|
14
|
+
import { SLACK_FEEDBACK_ACTION_ID, SLACK_FEEDBACK_VALUE_DOWN, SLACK_FEEDBACK_VALUE_UP } from "./slack-reply-blocks.js";
|
|
15
|
+
const obj = (v) => (typeof v === "object" && v !== null ? v : undefined);
|
|
16
|
+
const str = (v) => (typeof v === "string" && v.length > 0 ? v : undefined);
|
|
17
|
+
/**
|
|
18
|
+
* Parse a decoded interactivity payload into a thumbs click, or `undefined` when it is not one: not a
|
|
19
|
+
* `block_actions`, no `oe_feedback` action, a value other than `up`/`down`, or a missing user, channel
|
|
20
|
+
* or message. Pure and total: it never throws.
|
|
21
|
+
*/
|
|
22
|
+
export function parseSlackFeedbackClick(payload) {
|
|
23
|
+
const p = obj(payload);
|
|
24
|
+
if (p?.type !== "block_actions" || !Array.isArray(p.actions))
|
|
25
|
+
return undefined;
|
|
26
|
+
const action = p.actions.map(obj).find((a) => a?.action_id === SLACK_FEEDBACK_ACTION_ID);
|
|
27
|
+
if (action === undefined)
|
|
28
|
+
return undefined;
|
|
29
|
+
const value = str(action.value);
|
|
30
|
+
const rating = value === SLACK_FEEDBACK_VALUE_UP ? "up" : value === SLACK_FEEDBACK_VALUE_DOWN ? "down" : undefined;
|
|
31
|
+
if (rating === undefined)
|
|
32
|
+
return undefined;
|
|
33
|
+
const userId = str(obj(p.user)?.id);
|
|
34
|
+
const channelId = str(obj(p.channel)?.id) ?? str(obj(p.container)?.channel_id);
|
|
35
|
+
const messageTs = str(obj(p.message)?.ts) ?? str(obj(p.container)?.message_ts);
|
|
36
|
+
if (userId === undefined || channelId === undefined || messageTs === undefined)
|
|
37
|
+
return undefined;
|
|
38
|
+
const teamId = str(obj(p.team)?.id) ?? str(obj(p.user)?.team_id);
|
|
39
|
+
return { rating, userId, channelId, messageTs, ...(teamId === undefined ? {} : { teamId }) };
|
|
40
|
+
}
|
|
41
|
+
/** Record one thumbs click as a `reply.feedback` row, under the clicked conversation's partition.
|
|
42
|
+
* Answers whether the row was written. Never throws. */
|
|
43
|
+
export async function routeSlackFeedbackClick(click, deps = {}) {
|
|
44
|
+
try {
|
|
45
|
+
const p = resolvePartition(bindableForSlackIds({ teamId: click.teamId, channelId: click.channelId, userId: click.userId }));
|
|
46
|
+
const record = deps.record ?? ((c) => recordReplyFeedback(c));
|
|
47
|
+
return await record({
|
|
48
|
+
surface: "slack",
|
|
49
|
+
rating: click.rating,
|
|
50
|
+
raterId: click.userId,
|
|
51
|
+
channelId: click.channelId,
|
|
52
|
+
messageId: click.messageTs,
|
|
53
|
+
org: p.org,
|
|
54
|
+
platform: p.platform,
|
|
55
|
+
workspace: p.workspace,
|
|
56
|
+
surfaceKey: p.surfaceKey,
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=slack-reply-feedback.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slack-reply-feedback.js","sourceRoot":"","sources":["../../../agent/channels/slack-reply-feedback.ts"],"names":[],"mappings":"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"}
|
|
@@ -113,6 +113,16 @@ export declare function shortcutWakeKey(sc: ParsedSlackShortcut): string;
|
|
|
113
113
|
* fenced as untrusted content — the same reasoning that leaves a slash-command name unfenced.
|
|
114
114
|
*/
|
|
115
115
|
export declare function globalShortcutText(sc: ParsedSlackShortcut): string;
|
|
116
|
+
/**
|
|
117
|
+
* A Slack-shaped `ts` for the one wake that has no message behind it: a global shortcut.
|
|
118
|
+
*
|
|
119
|
+
* Slack's format is `<seconds>.<microseconds>`, and the wake envelope reads it back with
|
|
120
|
+
* `Number.parseFloat` to render `sent-at`. Minting from the clock therefore makes `sent-at` say
|
|
121
|
+
* exactly what is true — when the person pressed the button. The microsecond field carries this
|
|
122
|
+
* instant's milliseconds; the last three digits are zero, because a millisecond clock cannot
|
|
123
|
+
* honestly claim more precision than it has.
|
|
124
|
+
*/
|
|
125
|
+
export declare function slackTsFromMs(nowMs: number): string;
|
|
116
126
|
/**
|
|
117
127
|
* Map a shortcut onto the shared {@link ParsedMessageEvent} shape, so the front door's existing
|
|
118
128
|
* wake spine (partition → seat → window → dedupe → gates → divert) runs over it unchanged.
|