@stratusagent/channel-slack 0.11.8 → 0.11.10
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/README.md +43 -9
- package/dist/index.d.ts +71 -21
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +778 -12
- package/dist/index.js.map +1 -1
- package/dist/mrkdwn.d.ts.map +1 -1
- package/dist/mrkdwn.js +198 -9
- package/dist/mrkdwn.js.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
Slack adapter for Stratus agents. **One Slack app per agent** — Slack has no way to give a single bot several identities with real avatars, presence, and DMs, so each agent gets its own app, and the adapter runs one Socket Mode connection per agent (no public ingress needed; Mac Minis behind NAT are fine).
|
|
4
4
|
|
|
5
5
|
- **Resumable conversations**: session keys are `slack:<agent>:<team>:<channel>:<thread_ts ?? ts>` (DMs: the DM channel id) — a thread is a conversation, it survives daemon restarts, and two agents sharing a thread keep fully separate sessions. A turn parked on a human when the daemon died is re-asked after the restart, and a turn that was still running is continued from where it got to (unless the agent runs on a harness — `codex` or a Claude subscription — where it is failed instead, since the harness may already have acted on it); either way, when it finishes its reply is posted into the thread as a fresh message — the placeholder it would have edited belonged to the old process.
|
|
6
|
-
- **Replies post when they are ready**: by default
|
|
7
|
-
- **Markdown is translated to Slack's mrkdwn** on the way out — `**bold**` to `*bold*`, `*italic*` to `_italic_`, `~~struck~~` to `~struck~`, `[text](https://…)` to `<https://…|text>`, and a `#` heading to a bold line, since mrkdwn has no headings. The reply is read once into tokens and written back from those, so what counts as code is decided one time rather than by each rule in turn. Three things follow from that. **A code run is one token**: nothing reads or rewrites inside it, an unclosed fence included, and the newlines in a fence are not line breaks — so a `#` on a line of somebody's shell script is not a heading. A run of N backticks opens code and only a run of exactly N closes it, which is what lets ``a span with a ` in it`` and a ````-fence holding a ```-fence work; one or two unmatched backticks are text, as they are in Markdown, but a pair is a span however far apart, because Slack pairs them too. **A delimiter is matched to its partner**, across whatever sits between — ``**the `fs.read` tool**`` is bold around a snippet, not four literal asterisks — though never across a line, so a marker still being streamed stays literal until its closing half arrives. A run is spent rather than matched whole, so the three asterisks ending `**bold and *italic***` close the italic with one and the bold with two; what no pair spends stays on the line as text, and what a run cannot buy — the third tilde of `~~~struck~~~`, a style that does not exist — is never charged for. **A wrapper is only written where its own character is not already loose** in what it wraps: Slack has one delimiter per style and no way to nest it, so a heading that already contains bold keeps the bold it has rather than gaining a second pair that would print instead of render, and `# glob *.ts` keeps an asterisk that was never a marker. A heading sheds its hashes and its trailing spaces from the prose that holds them, never from a snippet. Anything whose spelling already matches — lists, block quotes, inline code — is untouched. **A pipe table**, which mrkdwn has no syntax for, becomes a code block with its columns padded to line up (alignment colons respected, `**`/`` ` `` markers dropped from cells, since nothing renders inside code); a grid wider than 60 characters — past what a phone shows unwrapped — or one with a link in it (a link inside a code block is not clickable) becomes one line per row, `*Header*: value · *Header*: value`. A one-column table has nothing to line up and becomes a bulleted list under its bold header. A table inside a fence is somebody's text and stays as written, and a grid longer than one message is split like any code block, closed at the cut and reopened in the next, with its header and rule repeated so every part names its columns.
|
|
8
|
-
- **Mention to start, then it stays in the thread.** A mention opens a conversation; every reply in that thread reaches the agent without tagging it again, and free-form DMs are unchanged. Who an untagged reply is for is decided by [Who a message is for](#who-a-message-is-for). Inbound mentions of other users are humanized to `@Display Name` for the model; redeliveries are deduped so a slow turn never runs twice — in memory while the process remembers them, and after a restart by the gateway: each message is dispatched with its own key (`idempotencyKey`), a repeat runs no second turn, and the adapter posts that message's own reply and files (a file changed since that turn is skipped, since the path may now hold another file), or its failure if the turn failed — once more, if the process died after posting it, which beats a reply never posted.
|
|
6
|
+
- **Replies post when they are ready**: by default each message is posted once, finished: what the agent writes before starting a tool is posted as the tool starts, and the reply follows, with Slack's loading status (`assistant.threads.setStatus` — "is thinking…", "is running shell.run…") shown while the turn works, so the notification carries the answer. The `stream` reply mode (`slack.replies` in the [config](../../docs/guides/slack.md#how-replies-appear)) keeps the placeholder-and-edit rendering instead: post `…`, edit as deltas arrive (throttled for `chat.update` limits), show `⚙ tool…` status lines, finalize with the full reply. Either way a reply that outgrows one message is split across several.
|
|
7
|
+
- **Markdown is translated to Slack's mrkdwn** on the way out — `**bold**` to `*bold*`, `*italic*` to `_italic_`, `~~struck~~` to `~struck~`, `[text](https://…)` to `<https://…|text>`, and a `#` heading to a bold line, since mrkdwn has no headings. A bare address is sent as `<https://…>`, Slack's own link markup, so emphasis around it (`**https://…**`) cannot be read as part of it, and a `*`, `_`, or `~` inside one is part of the address rather than a marker. Trailing punctuation (`.`, `,`, `**`) and a `)` the address never opened belong to the sentence, as in GFM autolinks, so `…/wiki/Function_(mathematics)` stays whole. A bare address is sent as `<https://…>`, Slack's own link markup, so emphasis around it (`**https://…**`) cannot be read as part of it, and the `*`, `_`, or `~` inside one is part of the address rather than a marker; trailing punctuation (`.`, `,`, `**`) is the sentence's, as in GFM autolinks. The reply is read once into tokens and written back from those, so what counts as code is decided one time rather than by each rule in turn. Three things follow from that. **A code run is one token**: nothing reads or rewrites inside it, an unclosed fence included, and the newlines in a fence are not line breaks — so a `#` on a line of somebody's shell script is not a heading. A run of N backticks opens code and only a run of exactly N closes it, which is what lets ``a span with a ` in it`` and a ````-fence holding a ```-fence work; one or two unmatched backticks are text, as they are in Markdown, but a pair is a span however far apart, because Slack pairs them too. **A delimiter is matched to its partner**, across whatever sits between — ``**the `fs.read` tool**`` is bold around a snippet, not four literal asterisks — though never across a line, so a marker still being streamed stays literal until its closing half arrives. A run is spent rather than matched whole, so the three asterisks ending `**bold and *italic***` close the italic with one and the bold with two; what no pair spends stays on the line as text, and what a run cannot buy — the third tilde of `~~~struck~~~`, a style that does not exist — is never charged for. **A wrapper is only written where its own character is not already loose** in what it wraps: Slack has one delimiter per style and no way to nest it, so a heading that already contains bold keeps the bold it has rather than gaining a second pair that would print instead of render, and `# glob *.ts` keeps an asterisk that was never a marker. A heading sheds its hashes and its trailing spaces from the prose that holds them, never from a snippet. Anything whose spelling already matches — lists, block quotes, inline code — is untouched. **A pipe table**, which mrkdwn has no syntax for, becomes a code block with its columns padded to line up (alignment colons respected, `**`/`` ` `` markers dropped from cells, since nothing renders inside code); a grid wider than 60 characters — past what a phone shows unwrapped — or one with a link in it (a link inside a code block is not clickable) becomes one line per row, `*Header*: value · *Header*: value`. A one-column table has nothing to line up and becomes a bulleted list under its bold header. A table inside a fence is somebody's text and stays as written, and a grid longer than one message is split like any code block, closed at the cut and reopened in the next, with its header and rule repeated so every part names its columns.
|
|
8
|
+
- **Mention to start, then it stays in the thread.** A mention opens a conversation; every reply in that thread reaches the agent without tagging it again, and free-form DMs are unchanged. A mention partway into an existing thread opens the conversation with what was said before it: the thread's parent and its newest 39 earlier messages. A mention at the top of a channel opens with the channel's 20 most recent messages instead, which is where a channel per client or per project keeps its context. Either way each message keeps its own speaker and its own trust, so a principal's mention does not carry a stranger's earlier words in under the principal's label (other bots count as `unknown`, and under `admit: "principals"` unlisted senders are left out). This needs the history scopes below; without them the agent sees only the message that named it, and the adapter logs a warning. Who an untagged reply is for is decided by [Who a message is for](#who-a-message-is-for). Inbound mentions of other users are humanized to `@Display Name` for the model; redeliveries are deduped so a slow turn never runs twice — in memory while the process remembers them, and after a restart by the gateway: each message is dispatched with its own key (`idempotencyKey`), a repeat runs no second turn, and the adapter posts that message's own reply and files (a file changed since that turn is skipped, since the path may now hold another file), or its failure if the turn failed — once more, if the process died after posting it, which beats a reply never posted.
|
|
9
9
|
- **Approval buttons** for the gateway's `remote` permission mode: a gated tool call parks the turn and asks in its thread with **Allow once** / **Always allow** / **Deny**. See [Approving tool calls](#approving-tool-calls) — clicks are authorized by *who clicked*, never by who can see the message, and **Always allow** is offered only where the daemon would actually remember it.
|
|
10
10
|
- **Tokens are gateway infrastructure secrets**, stored in the `channels` namespace of `~/.stratus/credentials.json` — never in an agent's credential allowlist:
|
|
11
11
|
|
|
@@ -35,7 +35,11 @@ they are the whole model:
|
|
|
35
35
|
is durable, so a daemon restart mid-thread forgets nothing.
|
|
36
36
|
3. **The room is not a conversation.** A channel message outside any thread
|
|
37
37
|
is never a follow-up, however much of the channel the app can see. An
|
|
38
|
-
agent that has not been spoken to does not join in.
|
|
38
|
+
agent that has not been spoken to does not join in. The one exception is
|
|
39
|
+
an agent's **home channel** (`slack.agents.<id>.homeChannels` in the
|
|
40
|
+
[config](../../docs/guides/slack.md#a-home-channel)): there every new
|
|
41
|
+
top-level message from someone it admits is addressed to it, unless the
|
|
42
|
+
message names another agent.
|
|
39
43
|
4. **In a thread with several agents, an untagged reply goes to whoever
|
|
40
44
|
spoke last.** The same rule people use: you are answering the voice that
|
|
41
45
|
just answered you. Naming another agent moves the conversation to them —
|
|
@@ -154,10 +158,12 @@ here, too large, not downloaded or not in time, not readable, or not opened
|
|
|
154
158
|
because the message was overheard), which is what lets it answer honestly
|
|
155
159
|
instead of as though it had read them, or guessing at why. Such a file dropped
|
|
156
160
|
in with nothing said is not a question, and gets no reply.
|
|
157
|
-
Sessions are still per agent
|
|
158
|
-
that
|
|
159
|
-
|
|
160
|
-
|
|
161
|
+
Sessions are still per agent, but a new one opens with what was said
|
|
162
|
+
before the mention that created it: in a thread, its parent and newest
|
|
163
|
+
earlier messages, and at the top of a channel, the channel's most recent
|
|
164
|
+
messages (see the overview above for the limits and the trust rules). That
|
|
165
|
+
needs the history scopes; without them an agent hears a thread only from
|
|
166
|
+
the mention that brought it in. A colleague's reply is
|
|
161
167
|
heard by the daemon that posted it, not through Slack — an agent served by
|
|
162
168
|
another daemon is a stranger's bot to this one, and its replies are not
|
|
163
169
|
heard at all.
|
|
@@ -230,7 +236,7 @@ editing `credentials.json` by hand.
|
|
|
230
236
|
The manual equivalent, if you prefer:
|
|
231
237
|
|
|
232
238
|
1. https://api.slack.com/apps → **Create New App → From a manifest** → paste `manifest/stratus-agent.manifest.json` with `NAME` replaced by the agent's name.
|
|
233
|
-
The manifest asks for the `channels:history` / `groups:history` / `mpim:history` scopes and the matching `message.*` events, which is what lets an agent [stay in a thread](#who-a-message-is-for) instead of needing a mention every time, and for `files:read`, which is what lets it [see an attached image](#who-a-message-is-for). An app created before those shipped needs them added under **OAuth & Permissions** and **Event Subscriptions** and reinstalled once; leave the history scopes off and it answers mentions and DMs, exactly as it did before; leave `files:read` off and it hears about attachments, images and text files alike, by name only.
|
|
239
|
+
The manifest asks for the `channels:history` / `groups:history` / `mpim:history` scopes and the matching `message.*` events, which is what lets an agent [stay in a thread](#who-a-message-is-for) instead of needing a mention every time, and for `files:read`, which is what lets it [see an attached image](#who-a-message-is-for). An app created before those shipped needs them added under **OAuth & Permissions** and **Event Subscriptions** and reinstalled once; leave the history scopes off and it answers mentions and DMs, exactly as it did before, without the earlier messages of a thread it is mentioned into; leave `files:read` off and it hears about attachments, images and text files alike, by name only.
|
|
234
240
|
It also turns on the **Messages Tab** under App Home (`features.app_home.messages_tab_enabled`), which Slack creates apps without — until it is on, a DM to the app gets Slack's own *Sending messages to this app has been turned off* and never reaches the adapter. An app created before the manifest carried it needs **App Home → Messages Tab → Allow users to send Slash commands and messages from the messages tab** switched on once; reopen the DM afterwards.
|
|
235
241
|
2. Still on **Basic Information**, scroll to **App-Level Tokens** → **Generate Token and Scopes** → name it anything → **Add Scope** → `connections:write` → **Generate**, and copy the token (that's the `appToken`, `xapp-…`). It is not on **OAuth & Permissions**, where the bot token is.
|
|
236
242
|
3. **Install App** → **Install to** the workspace → **Allow** → copy the **Bot User OAuth Token** (that's the `botToken`, `xoxb-…`).
|
|
@@ -464,6 +470,34 @@ project-local `stratus.config.json` cannot appoint itself the principal.
|
|
|
464
470
|
The labels themselves are documented in
|
|
465
471
|
[Memory](../../docs/concepts/memory.md#where-a-fact-came-from).
|
|
466
472
|
|
|
473
|
+
## Reading a channel
|
|
474
|
+
|
|
475
|
+
The adapter implements the channel contract's `readConversation`, which is
|
|
476
|
+
what the gateway's `message.read` tool reads through: a channel's top level
|
|
477
|
+
(`conversations.history`, newest first) or one thread
|
|
478
|
+
(`conversations.replies`, root first), paged up to the call's limit. It uses
|
|
479
|
+
the `channels:history` / `groups:history` and `users:read` scopes already in
|
|
480
|
+
the manifest, so nothing needs reinstalling. Message text comes back as
|
|
481
|
+
plain text: mentions, channel links, links, dates, and `<`-style escapes
|
|
482
|
+
are decoded, and a mention is named only for a principal or the agent
|
|
483
|
+
itself. `message.read` also stops at 40,000 characters of text per call and
|
|
484
|
+
says `more`, so a channel of long posts cannot outgrow the model's context.
|
|
485
|
+
|
|
486
|
+
The boundary is the outbound one plus a rule for DMs:
|
|
487
|
+
|
|
488
|
+
- The agent's **own** app reads. An agent with no Slack app here reads
|
|
489
|
+
nothing, and another agent's app is never borrowed.
|
|
490
|
+
- The app must be a **member** of the channel, public or private. `/invite`
|
|
491
|
+
it where it should read.
|
|
492
|
+
- **DMs and group DMs are refused, member or not.** What someone says in a
|
|
493
|
+
DM is said to the people in it; a read from elsewhere, a public thread
|
|
494
|
+
above all, would carry it to people who were never in the room.
|
|
495
|
+
|
|
496
|
+
Messages come back as plain text with author ids and, where Slack supplies
|
|
497
|
+
one cheaply, a display name. File contents are not downloaded; their names
|
|
498
|
+
are listed. The tool labels the result `external`, so what an agent
|
|
499
|
+
remembers after reading carries that label.
|
|
500
|
+
|
|
467
501
|
## Speaking first: the outbound seam
|
|
468
502
|
|
|
469
503
|
The adapter also implements the channel contract's `resolveOutbound` — how a
|
package/dist/index.d.ts
CHANGED
|
@@ -45,6 +45,16 @@ export interface SlackAgentConfig {
|
|
|
45
45
|
* a `…` placeholder at once and edits it as the reply is written.
|
|
46
46
|
*/
|
|
47
47
|
replies?: 'final' | 'stream';
|
|
48
|
+
/**
|
|
49
|
+
* Channel ids where a new top-level message from an admitted sender is
|
|
50
|
+
* this agent's to answer without a mention: the channel people come to
|
|
51
|
+
* when they want this agent. A message there that names another agent
|
|
52
|
+
* is that agent's. Threads follow the soul's `listens` as anywhere else.
|
|
53
|
+
* One channel has one home agent: when two in the same workspace list
|
|
54
|
+
* it, neither owns it, both answer there only when mentioned, and the
|
|
55
|
+
* adapter warns at startup.
|
|
56
|
+
*/
|
|
57
|
+
homeChannels?: string[];
|
|
48
58
|
}
|
|
49
59
|
export interface SlackSocketEventArgs {
|
|
50
60
|
ack: (response?: unknown) => Promise<void>;
|
|
@@ -104,6 +114,12 @@ export interface SlackInboundEvent {
|
|
|
104
114
|
text?: string;
|
|
105
115
|
ts: string;
|
|
106
116
|
thread_ts?: string;
|
|
117
|
+
/**
|
|
118
|
+
* Who wrote the message that opened this thread, on a reply in one.
|
|
119
|
+
* Slack sets it on threaded `message` events; an app's own post carries
|
|
120
|
+
* its bot user id here.
|
|
121
|
+
*/
|
|
122
|
+
parent_user_id?: string;
|
|
107
123
|
channel: string;
|
|
108
124
|
channel_type?: string;
|
|
109
125
|
bot_id?: string;
|
|
@@ -118,6 +134,8 @@ export interface SlackInboundEvent {
|
|
|
118
134
|
*/
|
|
119
135
|
files?: SlackInboundFile[];
|
|
120
136
|
}
|
|
137
|
+
/** A message a backfill reads: the shape `message.read` reads too. */
|
|
138
|
+
export type SlackThreadMessage = SlackHistoryMessage;
|
|
121
139
|
/** The slice of Slack's file object the adapter reads. */
|
|
122
140
|
export interface SlackInboundFile {
|
|
123
141
|
id?: string;
|
|
@@ -182,11 +200,53 @@ export interface SlackUploadResult {
|
|
|
182
200
|
};
|
|
183
201
|
}>;
|
|
184
202
|
}
|
|
203
|
+
export interface SlackHistoryArgs {
|
|
204
|
+
channel: string;
|
|
205
|
+
oldest?: string;
|
|
206
|
+
latest?: string;
|
|
207
|
+
inclusive?: boolean;
|
|
208
|
+
limit?: number;
|
|
209
|
+
cursor?: string;
|
|
210
|
+
}
|
|
211
|
+
/** The fields of a Slack message a read returns; everything else is dropped. */
|
|
212
|
+
export interface SlackHistoryMessage {
|
|
213
|
+
ts?: string;
|
|
214
|
+
user?: string;
|
|
215
|
+
bot_id?: string;
|
|
216
|
+
username?: string;
|
|
217
|
+
bot_profile?: {
|
|
218
|
+
name?: string;
|
|
219
|
+
};
|
|
220
|
+
user_profile?: {
|
|
221
|
+
display_name?: string;
|
|
222
|
+
real_name?: string;
|
|
223
|
+
};
|
|
224
|
+
text?: string;
|
|
225
|
+
/** Set on joins, topic changes and the like; a backfill skips them. */
|
|
226
|
+
subtype?: string;
|
|
227
|
+
thread_ts?: string;
|
|
228
|
+
reply_count?: number;
|
|
229
|
+
files?: Array<{
|
|
230
|
+
name?: string;
|
|
231
|
+
title?: string;
|
|
232
|
+
id?: string;
|
|
233
|
+
}>;
|
|
234
|
+
}
|
|
235
|
+
export interface SlackHistoryPage {
|
|
236
|
+
messages?: SlackHistoryMessage[];
|
|
237
|
+
has_more?: boolean;
|
|
238
|
+
response_metadata?: {
|
|
239
|
+
next_cursor?: string;
|
|
240
|
+
};
|
|
241
|
+
}
|
|
185
242
|
export interface SlackWebLike {
|
|
186
243
|
auth: {
|
|
187
244
|
test(): Promise<{
|
|
188
245
|
user_id?: string;
|
|
189
246
|
team_id?: string;
|
|
247
|
+
response_metadata?: {
|
|
248
|
+
scopes?: string[];
|
|
249
|
+
};
|
|
190
250
|
}>;
|
|
191
251
|
};
|
|
192
252
|
chat: {
|
|
@@ -289,6 +349,17 @@ export interface SlackWebLike {
|
|
|
289
349
|
next_cursor?: string;
|
|
290
350
|
};
|
|
291
351
|
}>;
|
|
352
|
+
/**
|
|
353
|
+
* A conversation's top level, newest first, a page at a time — what
|
|
354
|
+
* `message.read` without a thread reads. Needs the history scopes the
|
|
355
|
+
* manifest already asks for. Optional so an older fake still runs; an
|
|
356
|
+
* adapter without it says the conversation cannot be read.
|
|
357
|
+
*/
|
|
358
|
+
history?(args: SlackHistoryArgs): Promise<SlackHistoryPage>;
|
|
359
|
+
/** One thread, root first, a page at a time. Same scopes as `history`. */
|
|
360
|
+
replies?(args: SlackHistoryArgs & {
|
|
361
|
+
ts: string;
|
|
362
|
+
}): Promise<SlackHistoryPage>;
|
|
292
363
|
};
|
|
293
364
|
users: {
|
|
294
365
|
info(args: {
|
|
@@ -358,26 +429,5 @@ export interface SlackAdapterOptions {
|
|
|
358
429
|
* read.
|
|
359
430
|
*/
|
|
360
431
|
export declare const createSlackFileFetcher: (fetchImpl: typeof fetch) => SlackFileFetcher;
|
|
361
|
-
/**
|
|
362
|
-
* The Slack channel adapter. One Slack app per agent — Slack has no way to
|
|
363
|
-
* give a single bot several identities with real avatars, presence, and
|
|
364
|
-
* DMs — so the adapter runs one Socket Mode connection per configured
|
|
365
|
-
* agent and maps each app to its agent id.
|
|
366
|
-
*
|
|
367
|
-
* Session keys are `slack:<agent>:<team>:<channel>:<thread_ts ?? ts>`
|
|
368
|
-
* (DMs: the DM channel id alone), so threads are resumable conversations
|
|
369
|
-
* and two agents sharing a thread keep fully separate sessions. Replies
|
|
370
|
-
* post once, finished, behind Slack's loading status — or, in the `stream`
|
|
371
|
-
* reply mode, stream via placeholder-then-edit, throttled for chat.update
|
|
372
|
-
* limits.
|
|
373
|
-
*
|
|
374
|
-
* A mention starts a thread conversation; inside one, the agent keeps
|
|
375
|
-
* listening without being tagged again — see `couldBeFollowUp` and
|
|
376
|
-
* `answersFollowUp` for exactly whose reply an untagged message is. That
|
|
377
|
-
* needs the app to be subscribed to `message.channels` / `message.groups`
|
|
378
|
-
* / `message.mpim` (the shipped manifest is); an app installed before
|
|
379
|
-
* those were in it receives only `app_mention` and behaves as it always
|
|
380
|
-
* did, which makes the workspace's own grant the switch.
|
|
381
|
-
*/
|
|
382
432
|
export declare const createSlackChannelAdapter: (options: SlackAdapterOptions) => ChannelAdapter;
|
|
383
433
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|