@mono-agent/slack-adapter 0.3.0 β†’ 0.4.1

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.
@@ -1,54 +1,103 @@
1
- import type { AgentMessageStream as AgentMessageStreamBase } from "@mono-agent/agent-contracts";
1
+ import type { AgentMessageStream as AgentMessageStreamBase, AgentStreamEvent, ResilientMessageStreamLogger } from "@mono-agent/agent-contracts";
2
2
  import type { SlackChannelId, SlackMessageTs, SlackWebApi } from "./types.js";
3
3
  export interface AgentMessageStream extends AgentMessageStreamBase {
4
4
  status(text: string): Promise<void>;
5
5
  append(delta: string): Promise<void>;
6
6
  replace(text: string): Promise<void>;
7
+ event(event: AgentStreamEvent): Promise<void>;
7
8
  finish(finalText?: string): Promise<void>;
8
9
  }
10
+ export type SlackMessageStreamLogger = ResilientMessageStreamLogger;
9
11
  export interface SlackMessageStreamOptions {
10
12
  api: SlackWebApi;
11
13
  channelId: SlackChannelId;
12
14
  threadTs?: SlackMessageTs;
15
+ /** Message ts to react to (πŸ‘€ "seen") in final-only mode. */
16
+ reactToTs?: SlackMessageTs;
17
+ /**
18
+ * Deliver only the final answer: suppress interim edits and react πŸ‘€ ("seen")
19
+ * while the agent works. Default false.
20
+ */
21
+ finalOnly?: boolean;
13
22
  initialStatusText?: string;
14
23
  editDebounceMs?: number;
15
24
  maxMessageChars?: number;
25
+ /** Maximum retries for a *final* delivery before giving up. Default 3. */
26
+ maxSendRetries?: number;
27
+ /** Upper bound on any honored `retry-after`/backoff wait, in ms. Default 60000. */
28
+ retryCapMs?: number;
29
+ /** Base delay for exponential backoff between final-delivery retries. Default 500. */
30
+ retryBaseDelayMs?: number;
31
+ /** Render lightweight tool activity hints as the live status. Default true. */
32
+ showHints?: boolean;
33
+ /**
34
+ * Status shown via `assistant.threads.setStatus` ("App is <status>") while the
35
+ * agent works, when this is a Slack AI-assistant thread. Falls back to the πŸ‘€
36
+ * reaction in regular channels/DMs. Default "is thinking…".
37
+ */
38
+ assistantStatusText?: string;
39
+ /** Aborts in-flight retry waits (e.g. on /cancel). */
40
+ abortSignal?: AbortSignal;
16
41
  logger?: SlackMessageStreamLogger;
42
+ /**
43
+ * Notified with each message this stream posts. Used to link a posted message
44
+ * back to the conversation that produced it, so a later in-thread reply can
45
+ * resume that conversation (see `posted-message-index` in agent-app).
46
+ */
47
+ onPosted?: SlackPostedMessageListener;
17
48
  }
18
- export interface SlackMessageStreamLogger {
19
- debug?(message: string, metadata?: Record<string, unknown>): void;
20
- warn?(message: string, metadata?: Record<string, unknown>): void;
21
- error?(message: string, metadata?: Record<string, unknown>): void;
49
+ /** Notified with the channel + ts of a message a stream posted. */
50
+ export type SlackPostedMessageListener = (ref: {
51
+ ts: SlackMessageTs;
52
+ channel: SlackChannelId;
53
+ }) => void;
54
+ /**
55
+ * Raised only when a *final* delivery cannot reach Slack after retries and the
56
+ * last-resort fresh post. The AI request itself already succeeded, so the
57
+ * adapter treats this as a degraded delivery β€” never as an agent failure.
58
+ *
59
+ * Retained as the adapter's public error type; the shared substrate raises a
60
+ * {@link ChannelDeliveryError}, which this class normalizes so callers continue
61
+ * to catch `SlackDeliveryError`.
62
+ */
63
+ export declare class SlackDeliveryError extends Error {
64
+ readonly cause: unknown;
65
+ readonly attempts: number;
66
+ constructor(message: string, details: {
67
+ cause: unknown;
68
+ attempts: number;
69
+ });
22
70
  }
71
+ /** How a failed Slack post/update should be handled. */
72
+ export type SlackSendOutcome = {
73
+ kind: "recreate";
74
+ } | {
75
+ kind: "reformat_plain";
76
+ } | {
77
+ kind: "retry";
78
+ retryAfterMs?: number;
79
+ } | {
80
+ kind: "fatal";
81
+ };
82
+ /**
83
+ * Thin wrapper over the shared {@link ResilientMessageStream}. It builds a
84
+ * {@link SlackChannelTransport} and delegates the streaming/resilience FSM,
85
+ * preserving the adapter's public surface: the `status/append/replace/event/
86
+ * finish` API, friendly tool hints, abort-aware retries, and a Slack-shaped
87
+ * delivery error.
88
+ */
23
89
  export declare class SlackMessageStream implements AgentMessageStream {
24
- private readonly api;
25
- private readonly channelId;
26
- private readonly threadTs;
27
- private readonly initialStatusText;
28
- private readonly editDebounceMs;
29
- private readonly maxMessageChars;
30
- private readonly logger;
31
- private currentText;
32
- private statusText;
33
- private sentMessage;
34
- private sendMessagePromise;
35
- private editTimer;
36
- private inFlightUpdate;
37
- private lastAsyncError;
38
- private finished;
90
+ private readonly inner;
39
91
  constructor(options: SlackMessageStreamOptions);
40
92
  status(text: string): Promise<void>;
41
93
  append(delta: string): Promise<void>;
42
94
  replace(text: string): Promise<void>;
95
+ event(event: AgentStreamEvent): Promise<void>;
43
96
  finish(finalText?: string): Promise<void>;
44
- private ensureMessage;
45
- private withThread;
46
- private scheduleUpdate;
47
- private startInFlightUpdate;
48
- private flushUpdate;
49
- private cancelScheduledUpdate;
50
- private awaitInFlightUpdate;
51
- private throwIfAsyncError;
52
- private assertOpen;
53
97
  }
98
+ /**
99
+ * Classify a Slack post/update failure into a recovery strategy. Pure and
100
+ * exported so the recovery policy can be unit-tested directly.
101
+ */
102
+ export declare function classifySlackError(error: unknown): SlackSendOutcome;
54
103
  //# sourceMappingURL=message-stream.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"message-stream.d.ts","sourceRoot":"","sources":["../src/message-stream.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,kBAAkB,IAAI,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AAEhG,OAAO,KAAK,EACV,cAAc,EAEd,cAAc,EACd,WAAW,EACZ,MAAM,YAAY,CAAC;AAGpB,MAAM,WAAW,kBAAmB,SAAQ,sBAAsB;IAChE,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACpC,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACrC,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACrC,MAAM,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3C;AAED,MAAM,WAAW,yBAAyB;IACxC,GAAG,EAAE,WAAW,CAAC;IACjB,SAAS,EAAE,cAAc,CAAC;IAC1B,QAAQ,CAAC,EAAE,cAAc,CAAC;IAC1B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,MAAM,CAAC,EAAE,wBAAwB,CAAC;CACnC;AAED,MAAM,WAAW,wBAAwB;IACvC,KAAK,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAClE,IAAI,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IACjE,KAAK,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;CACnE;AAMD,qBAAa,kBAAmB,YAAW,kBAAkB;IAC3D,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAc;IAClC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAiB;IAC3C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA6B;IACtD,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAS;IAC3C,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;IACxC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAS;IACzC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAuC;IAE9D,OAAO,CAAC,WAAW,CAAM;IACzB,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,WAAW,CAAyC;IAC5D,OAAO,CAAC,kBAAkB,CAAkD;IAC5E,OAAO,CAAC,SAAS,CAA4C;IAC7D,OAAO,CAAC,cAAc,CAA4B;IAClD,OAAO,CAAC,cAAc,CAAU;IAChC,OAAO,CAAC,QAAQ,CAAS;gBAEb,OAAO,EAAE,yBAAyB;IAqBxC,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAWnC,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAYpC,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQpC,MAAM,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;YAiCjC,aAAa;IAiB3B,OAAO,CAAC,UAAU;IASlB,OAAO,CAAC,cAAc;IAatB,OAAO,CAAC,mBAAmB;YAgBb,WAAW;IAUzB,OAAO,CAAC,qBAAqB;YAOf,mBAAmB;YAOnB,iBAAiB;IAY/B,OAAO,CAAC,UAAU;CAKnB"}
1
+ {"version":3,"file":"message-stream.d.ts","sourceRoot":"","sources":["../src/message-stream.ts"],"names":[],"mappings":"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"}
@@ -1,105 +1,104 @@
1
- import { DEFAULT_EMPTY_FINAL_TEXT, DEFAULT_MAX_MESSAGE_CHARS, buildStreamingTailPreview, normalizeTrailing, splitTextByCodePoints, } from "@mono-agent/agent-contracts";
1
+ import { ChannelDeliveryError, DEFAULT_MAX_MESSAGE_CHARS, ResilientMessageStream, } from "@mono-agent/agent-contracts";
2
+ import { SlackApiError } from "./slack-client.js";
2
3
  import { formatMarkdownForSlack } from "./slack-markdown.js";
4
+ /**
5
+ * Raised only when a *final* delivery cannot reach Slack after retries and the
6
+ * last-resort fresh post. The AI request itself already succeeded, so the
7
+ * adapter treats this as a degraded delivery β€” never as an agent failure.
8
+ *
9
+ * Retained as the adapter's public error type; the shared substrate raises a
10
+ * {@link ChannelDeliveryError}, which this class normalizes so callers continue
11
+ * to catch `SlackDeliveryError`.
12
+ */
13
+ export class SlackDeliveryError extends Error {
14
+ cause;
15
+ attempts;
16
+ constructor(message, details) {
17
+ super(message);
18
+ this.name = "SlackDeliveryError";
19
+ this.cause = details.cause;
20
+ this.attempts = details.attempts;
21
+ }
22
+ }
3
23
  const DEFAULT_INITIAL_STATUS_TEXT = "Thinking...";
4
- const DEFAULT_EDIT_DEBOUNCE_MS = 750;
5
- const EMPTY_FINAL_TEXT = DEFAULT_EMPTY_FINAL_TEXT;
6
- export class SlackMessageStream {
24
+ const DEFAULT_ASSISTANT_STATUS_TEXT = "is thinking…";
25
+ /**
26
+ * Adapts a {@link SlackWebApi} to the transport-agnostic {@link ChannelTransport}
27
+ * the shared {@link ResilientMessageStream} drives. Posts/edits map to
28
+ * chat.postMessage / chat.update (preserving `thread_ts`), failures are mapped
29
+ * through {@link classifySlackError}, and markdown renders via
30
+ * {@link formatMarkdownForSlack}. `mrkdwn` mirrors the substrate's markdown flag
31
+ * so a `reformat_plain` retry drops to plain text.
32
+ */
33
+ class SlackChannelTransport {
34
+ maxMessageChars;
7
35
  api;
8
36
  channelId;
9
37
  threadTs;
10
- initialStatusText;
11
- editDebounceMs;
12
- maxMessageChars;
13
- logger;
14
- currentText = "";
15
- statusText;
16
- sentMessage;
17
- sendMessagePromise;
18
- editTimer;
19
- inFlightUpdate;
20
- lastAsyncError;
21
- finished = false;
38
+ reactToTs;
39
+ assistantStatusText;
40
+ onPosted;
41
+ reacted = false;
42
+ assistantStatusUnavailable = false;
22
43
  constructor(options) {
23
44
  this.api = options.api;
24
45
  this.channelId = options.channelId;
25
46
  this.threadTs = options.threadTs;
26
- this.initialStatusText = normalizeTrailing(options.initialStatusText ?? DEFAULT_INITIAL_STATUS_TEXT, EMPTY_FINAL_TEXT);
27
- this.statusText = this.initialStatusText;
28
- this.editDebounceMs = options.editDebounceMs ?? DEFAULT_EDIT_DEBOUNCE_MS;
29
- this.maxMessageChars = options.maxMessageChars ?? DEFAULT_MAX_MESSAGE_CHARS;
30
- this.logger = options.logger;
31
- if (!Number.isInteger(this.maxMessageChars) || this.maxMessageChars < 32) {
32
- throw new RangeError("maxMessageChars must be an integer of at least 32.");
33
- }
34
- if (!Number.isFinite(this.editDebounceMs) || this.editDebounceMs < 0) {
35
- throw new RangeError("editDebounceMs must be a non-negative number.");
36
- }
47
+ this.reactToTs = options.reactToTs;
48
+ this.assistantStatusText = options.assistantStatusText;
49
+ this.maxMessageChars = options.maxMessageChars;
50
+ this.onPosted = options.onPosted;
37
51
  }
38
- async status(text) {
39
- this.assertOpen();
40
- await this.throwIfAsyncError();
41
- this.statusText = normalizeTrailing(text, EMPTY_FINAL_TEXT);
42
- const hadMessage = this.sentMessage !== undefined;
43
- await this.ensureMessage();
44
- if (hadMessage) {
45
- await this.flushUpdate(this.statusText);
46
- }
47
- }
48
- async append(delta) {
49
- this.assertOpen();
50
- await this.throwIfAsyncError();
51
- if (delta.length === 0) {
52
+ async indicateActivity() {
53
+ // Prefer Slack's official assistant-thread status ("App is <status>"), which
54
+ // Slack auto-clears when the app posts its next message to the thread. It only
55
+ // works inside an AI-assistant thread (needs the assistant:write scope), so if
56
+ // it is unavailable or errors we stop trying for this stream and fall back to
57
+ // the πŸ‘€ reaction used in regular channels/DMs.
58
+ if (!this.assistantStatusUnavailable &&
59
+ this.threadTs !== undefined &&
60
+ this.api.setAssistantStatus !== undefined) {
61
+ try {
62
+ await this.api.setAssistantStatus({
63
+ channelId: this.channelId,
64
+ threadTs: this.threadTs,
65
+ status: this.assistantStatusText,
66
+ });
67
+ return;
68
+ }
69
+ catch {
70
+ // Not an assistant thread (or missing scope): don't retry it this stream.
71
+ this.assistantStatusUnavailable = true;
72
+ }
73
+ }
74
+ // Slack has no bot "typing" indicator, so signal "seen" with a πŸ‘€ reaction on
75
+ // the triggering message β€” added once (Slack rejects duplicates).
76
+ if (this.reacted || this.reactToTs === undefined || this.api.reactionsAdd === undefined) {
52
77
  return;
53
78
  }
54
- this.currentText += delta;
55
- await this.ensureMessage();
56
- this.scheduleUpdate();
79
+ this.reacted = true;
80
+ await this.api.reactionsAdd({ channel: this.channelId, timestamp: this.reactToTs, name: "eyes" });
57
81
  }
58
- async replace(text) {
59
- this.assertOpen();
60
- await this.throwIfAsyncError();
61
- this.currentText = text;
62
- await this.ensureMessage();
63
- this.scheduleUpdate();
82
+ async post(text, options) {
83
+ const sent = await this.api.chatPostMessage(this.withThread({ channel: this.channelId, text, mrkdwn: options.markdown }));
84
+ // Use `sent` (typed SlackChatPostMessageResult) rather than the transport-agnostic
85
+ // MessageRef, whose `channel` widens to `unknown`.
86
+ this.onPosted?.({ ts: sent.ts, channel: sent.channel });
87
+ return slackMessageRef(sent);
64
88
  }
65
- async finish(finalText) {
66
- if (this.finished) {
67
- return;
68
- }
69
- this.finished = true;
70
- if (finalText !== undefined) {
71
- this.currentText = finalText;
72
- }
73
- this.cancelScheduledUpdate();
74
- await this.throwIfAsyncError();
75
- await this.awaitInFlightUpdate();
76
- await this.throwIfAsyncError();
77
- const finalMessageText = normalizeTrailing(this.currentText.length > 0 ? this.currentText : EMPTY_FINAL_TEXT, EMPTY_FINAL_TEXT);
78
- const chunks = splitTextByCodePoints(finalMessageText, this.maxMessageChars);
79
- const [firstChunk, ...remainingChunks] = chunks;
80
- await this.ensureMessage();
81
- await this.flushUpdate(firstChunk ?? EMPTY_FINAL_TEXT);
82
- for (const chunk of remainingChunks) {
83
- await this.api.chatPostMessage(this.withThread({
84
- channel: this.channelId,
85
- text: formatMarkdownForSlack(chunk),
86
- mrkdwn: true,
87
- }));
88
- }
89
+ async edit(ref, text, options) {
90
+ await this.api.chatUpdate({
91
+ channel: this.channelId,
92
+ ts: ref.id,
93
+ text,
94
+ mrkdwn: options.markdown,
95
+ });
89
96
  }
90
- async ensureMessage() {
91
- if (this.sentMessage !== undefined) {
92
- return this.sentMessage;
93
- }
94
- if (this.sendMessagePromise === undefined) {
95
- this.sendMessagePromise = this.api.chatPostMessage(this.withThread({
96
- channel: this.channelId,
97
- text: formatMarkdownForSlack(this.statusText),
98
- mrkdwn: true,
99
- }));
100
- }
101
- this.sentMessage = await this.sendMessagePromise;
102
- return this.sentMessage;
97
+ classifyError(error) {
98
+ return classifySlackError(error);
99
+ }
100
+ renderMarkdown(text) {
101
+ return formatMarkdownForSlack(text);
103
102
  }
104
103
  withThread(params) {
105
104
  if (this.threadTs === undefined) {
@@ -107,63 +106,112 @@ export class SlackMessageStream {
107
106
  }
108
107
  return { ...params, thread_ts: this.threadTs };
109
108
  }
110
- scheduleUpdate() {
111
- this.cancelScheduledUpdate();
112
- if (this.editDebounceMs === 0) {
113
- this.startInFlightUpdate();
114
- return;
115
- }
116
- this.editTimer = setTimeout(() => {
117
- this.editTimer = undefined;
118
- this.startInFlightUpdate();
119
- }, this.editDebounceMs);
120
- }
121
- startInFlightUpdate() {
122
- const text = buildStreamingTailPreview(normalizeTrailing(this.currentText, EMPTY_FINAL_TEXT), this.maxMessageChars, "...\n");
123
- this.inFlightUpdate = this.flushUpdate(text).catch((error) => {
124
- this.lastAsyncError = error;
125
- this.logger?.error?.("Slack stream update failed.", {
126
- error: error instanceof Error ? error.message : String(error),
127
- });
128
- throw error;
109
+ }
110
+ function slackMessageRef(message) {
111
+ return { id: message.ts, channel: message.channel };
112
+ }
113
+ /**
114
+ * Thin wrapper over the shared {@link ResilientMessageStream}. It builds a
115
+ * {@link SlackChannelTransport} and delegates the streaming/resilience FSM,
116
+ * preserving the adapter's public surface: the `status/append/replace/event/
117
+ * finish` API, friendly tool hints, abort-aware retries, and a Slack-shaped
118
+ * delivery error.
119
+ */
120
+ export class SlackMessageStream {
121
+ inner;
122
+ constructor(options) {
123
+ const maxMessageChars = options.maxMessageChars ?? DEFAULT_MAX_MESSAGE_CHARS;
124
+ const transport = new SlackChannelTransport({
125
+ api: options.api,
126
+ channelId: options.channelId,
127
+ ...(options.threadTs === undefined ? {} : { threadTs: options.threadTs }),
128
+ ...(options.reactToTs === undefined ? {} : { reactToTs: options.reactToTs }),
129
+ assistantStatusText: options.assistantStatusText ?? DEFAULT_ASSISTANT_STATUS_TEXT,
130
+ maxMessageChars,
131
+ ...(options.onPosted === undefined ? {} : { onPosted: options.onPosted }),
129
132
  });
130
- void this.inFlightUpdate.catch(() => undefined);
131
- }
132
- async flushUpdate(text) {
133
- const message = await this.ensureMessage();
134
- await this.api.chatUpdate({
135
- channel: this.channelId,
136
- ts: message.ts,
137
- text: formatMarkdownForSlack(normalizeTrailing(text, EMPTY_FINAL_TEXT)),
138
- mrkdwn: true,
133
+ this.inner = new ResilientMessageStream({
134
+ transport,
135
+ initialStatusText: options.initialStatusText ?? DEFAULT_INITIAL_STATUS_TEXT,
136
+ maxMessageChars,
137
+ formatMarkdown: true,
138
+ ...(options.finalOnly === undefined ? {} : { finalOnly: options.finalOnly }),
139
+ ...(options.editDebounceMs === undefined ? {} : { editDebounceMs: options.editDebounceMs }),
140
+ ...(options.maxSendRetries === undefined ? {} : { maxSendRetries: options.maxSendRetries }),
141
+ ...(options.retryCapMs === undefined ? {} : { retryCapMs: options.retryCapMs }),
142
+ ...(options.retryBaseDelayMs === undefined ? {} : { retryBaseDelayMs: options.retryBaseDelayMs }),
143
+ ...(options.showHints === undefined ? {} : { showHints: options.showHints }),
144
+ ...(options.abortSignal === undefined ? {} : { abortSignal: options.abortSignal }),
145
+ ...(options.logger === undefined ? {} : { logger: options.logger }),
139
146
  });
140
147
  }
141
- cancelScheduledUpdate() {
142
- if (this.editTimer !== undefined) {
143
- clearTimeout(this.editTimer);
144
- this.editTimer = undefined;
145
- }
148
+ status(text) {
149
+ return this.inner.status(text);
146
150
  }
147
- async awaitInFlightUpdate() {
148
- if (this.inFlightUpdate !== undefined) {
149
- await this.inFlightUpdate;
150
- this.inFlightUpdate = undefined;
151
- }
151
+ append(delta) {
152
+ return this.inner.append(delta);
152
153
  }
153
- async throwIfAsyncError() {
154
- if (this.inFlightUpdate !== undefined) {
155
- await this.awaitInFlightUpdate();
156
- }
157
- if (this.lastAsyncError !== undefined) {
158
- const error = this.lastAsyncError;
159
- this.lastAsyncError = undefined;
154
+ replace(text) {
155
+ return this.inner.replace(text);
156
+ }
157
+ event(event) {
158
+ return this.inner.event(event);
159
+ }
160
+ async finish(finalText) {
161
+ try {
162
+ await this.inner.finish(finalText);
163
+ }
164
+ catch (error) {
165
+ if (error instanceof ChannelDeliveryError) {
166
+ throw new SlackDeliveryError("Slack final delivery failed.", {
167
+ cause: error.cause,
168
+ attempts: error.attempts,
169
+ });
170
+ }
160
171
  throw error;
161
172
  }
162
173
  }
163
- assertOpen() {
164
- if (this.finished) {
165
- throw new Error("Cannot write to a finished SlackMessageStream.");
166
- }
174
+ }
175
+ /**
176
+ * Classify a Slack post/update failure into a recovery strategy. Pure and
177
+ * exported so the recovery policy can be unit-tested directly.
178
+ */
179
+ export function classifySlackError(error) {
180
+ if (error instanceof SlackApiError) {
181
+ const slackError = (error.slackError ?? "").toLowerCase();
182
+ if (slackError === "message_not_found" ||
183
+ slackError === "cant_update_message" ||
184
+ slackError === "edit_window_closed") {
185
+ return { kind: "recreate" };
186
+ }
187
+ if (slackError === "invalid_blocks" ||
188
+ slackError === "invalid_block_id" ||
189
+ slackError === "msg_blocks_too_long" ||
190
+ slackError === "as_user_not_supported") {
191
+ return { kind: "reformat_plain" };
192
+ }
193
+ if (error.retryAfterMs !== undefined ||
194
+ error.status === 429 ||
195
+ slackError === "ratelimited" ||
196
+ slackError === "rate_limited") {
197
+ if (error.retryAfterMs !== undefined) {
198
+ return { kind: "retry", retryAfterMs: error.retryAfterMs };
199
+ }
200
+ return { kind: "retry" };
201
+ }
202
+ if (error.kind === "network") {
203
+ return { kind: "retry" };
204
+ }
205
+ if (error.kind === "aborted") {
206
+ return { kind: "fatal" };
207
+ }
208
+ if (error.status !== undefined && error.status >= 500) {
209
+ return { kind: "retry" };
210
+ }
211
+ return { kind: "fatal" };
167
212
  }
213
+ // Non-SlackApiError (e.g. a transient transport error or a test stub): retry
214
+ // conservatively rather than surfacing it as a hard failure.
215
+ return { kind: "retry" };
168
216
  }
169
217
  //# sourceMappingURL=message-stream.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"message-stream.js","sourceRoot":"","sources":["../src/message-stream.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"message-stream.js","sourceRoot":"","sources":["../src/message-stream.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import type { SlackAppsConnectionsOpenResult, SlackAuthTestResult, SlackChatPostMessageParams, SlackChatPostMessageResult, SlackChatUpdateParams, SlackChatUpdateResult, SlackRequestOptions, SlackWebApi } from "./types.js";
1
+ import type { SlackAppsConnectionsOpenResult, SlackAuthTestResult, SlackChatPostMessageParams, SlackChatPostMessageResult, SlackChatUpdateParams, SlackChatUpdateResult, SlackDownloadFileParams, SlackReactionsAddParams, SlackRequestOptions, SlackSetAssistantStatusParams, SlackViewsPublishParams, SlackWebApi } from "./types.js";
2
2
  export type SlackApiErrorKind = "http" | "slack" | "malformed" | "network" | "aborted";
3
3
  export interface SlackApiErrorDetails {
4
4
  kind: SlackApiErrorKind;
@@ -8,6 +8,13 @@ export interface SlackApiErrorDetails {
8
8
  needed?: string;
9
9
  provided?: string;
10
10
  warning?: string;
11
+ /**
12
+ * How long to wait before retrying, in milliseconds. Lifted from a Slack
13
+ * `Retry-After` response header (seconds) on a rate-limited (HTTP 429)
14
+ * response. Only the integer is carried β€” never a raw response body β€” so bot
15
+ * tokens cannot leak.
16
+ */
17
+ retryAfterMs?: number;
11
18
  cause?: unknown;
12
19
  }
13
20
  export declare class SlackApiError extends Error {
@@ -18,12 +25,13 @@ export declare class SlackApiError extends Error {
18
25
  readonly needed?: string;
19
26
  readonly provided?: string;
20
27
  readonly warning?: string;
28
+ readonly retryAfterMs?: number;
21
29
  readonly cause?: unknown;
22
30
  constructor(message: string, details: SlackApiErrorDetails);
23
31
  }
24
32
  export interface SlackWebApiClientOptions {
25
33
  botToken: string;
26
- appToken: string;
34
+ appToken?: string;
27
35
  apiBaseUrl?: string;
28
36
  fetchImpl?: typeof fetch;
29
37
  requestTimeoutMs?: number;
@@ -38,7 +46,19 @@ export declare class SlackWebApiClient implements SlackWebApi {
38
46
  authTest(options?: SlackRequestOptions): Promise<SlackAuthTestResult>;
39
47
  appsConnectionsOpen(options?: SlackRequestOptions): Promise<SlackAppsConnectionsOpenResult>;
40
48
  chatPostMessage(params: SlackChatPostMessageParams, options?: SlackRequestOptions): Promise<SlackChatPostMessageResult>;
49
+ private requiredAppToken;
41
50
  chatUpdate(params: SlackChatUpdateParams, options?: SlackRequestOptions): Promise<SlackChatUpdateResult>;
51
+ reactionsAdd(params: SlackReactionsAddParams, options?: SlackRequestOptions): Promise<void>;
52
+ setAssistantStatus(params: SlackSetAssistantStatusParams, options?: SlackRequestOptions): Promise<void>;
53
+ viewsPublish(params: SlackViewsPublishParams, options?: SlackRequestOptions): Promise<void>;
54
+ /**
55
+ * Download a private Slack file. Slack serves `url_private` only with an
56
+ * `Authorization: Bearer <bot token>` header. The download is bounded by the
57
+ * caller's request timeout and any external abort signal, and reads at most
58
+ * `maxBytes` (rejecting once the cap is exceeded) so a hostile or oversized
59
+ * file cannot exhaust memory.
60
+ */
61
+ downloadFile(params: SlackDownloadFileParams, options?: SlackRequestOptions): Promise<Uint8Array>;
42
62
  private request;
43
63
  }
44
64
  //# sourceMappingURL=slack-client.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"slack-client.d.ts","sourceRoot":"","sources":["../src/slack-client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,8BAA8B,EAC9B,mBAAmB,EACnB,0BAA0B,EAC1B,0BAA0B,EAC1B,qBAAqB,EACrB,qBAAqB,EACrB,mBAAmB,EACnB,WAAW,EACZ,MAAM,YAAY,CAAC;AAEpB,MAAM,MAAM,iBAAiB,GACzB,MAAM,GACN,OAAO,GACP,WAAW,GACX,SAAS,GACT,SAAS,CAAC;AAEd,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,iBAAiB,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,qBAAa,aAAc,SAAQ,KAAK;IACtC,QAAQ,CAAC,IAAI,EAAE,iBAAiB,CAAC;IACjC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,SAAkB,KAAK,CAAC,EAAE,OAAO,CAAC;gBAEtB,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,oBAAoB;CAwB3D;AAED,MAAM,WAAW,wBAAwB;IACvC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IACzB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAeD,qBAAa,iBAAkB,YAAW,WAAW;IACnD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAe;IACzC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAS;gBAE9B,OAAO,EAAE,wBAAwB;IAsB7C,QAAQ,CAAC,OAAO,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAIrE,mBAAmB,CAAC,OAAO,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC,8BAA8B,CAAC;IAI3F,eAAe,CACb,MAAM,EAAE,0BAA0B,EAClC,OAAO,CAAC,EAAE,mBAAmB,GAC5B,OAAO,CAAC,0BAA0B,CAAC;IAItC,UAAU,CACR,MAAM,EAAE,qBAAqB,EAC7B,OAAO,CAAC,EAAE,mBAAmB,GAC5B,OAAO,CAAC,qBAAqB,CAAC;YAInB,OAAO;CAwEtB"}
1
+ {"version":3,"file":"slack-client.d.ts","sourceRoot":"","sources":["../src/slack-client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,8BAA8B,EAC9B,mBAAmB,EACnB,0BAA0B,EAC1B,0BAA0B,EAC1B,qBAAqB,EACrB,qBAAqB,EACrB,uBAAuB,EACvB,uBAAuB,EACvB,mBAAmB,EACnB,6BAA6B,EAC7B,uBAAuB,EACvB,WAAW,EACZ,MAAM,YAAY,CAAC;AAEpB,MAAM,MAAM,iBAAiB,GACzB,MAAM,GACN,OAAO,GACP,WAAW,GACX,SAAS,GACT,SAAS,CAAC;AAEd,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,iBAAiB,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;;OAKG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,qBAAa,aAAc,SAAQ,KAAK;IACtC,QAAQ,CAAC,IAAI,EAAE,iBAAiB,CAAC;IACjC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,SAAkB,KAAK,CAAC,EAAE,OAAO,CAAC;gBAEtB,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,oBAAoB;CA2B3D;AAED,MAAM,WAAW,wBAAwB;IACvC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IACzB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAeD,qBAAa,iBAAkB,YAAW,WAAW;IACnD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAqB;IAC9C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAe;IACzC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAS;gBAE9B,OAAO,EAAE,wBAAwB;IAsB7C,QAAQ,CAAC,OAAO,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAI/D,mBAAmB,CAAC,OAAO,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC,8BAA8B,CAAC;IAIjG,eAAe,CACb,MAAM,EAAE,0BAA0B,EAClC,OAAO,CAAC,EAAE,mBAAmB,GAC5B,OAAO,CAAC,0BAA0B,CAAC;IAItC,OAAO,CAAC,gBAAgB;IAOxB,UAAU,CACR,MAAM,EAAE,qBAAqB,EAC7B,OAAO,CAAC,EAAE,mBAAmB,GAC5B,OAAO,CAAC,qBAAqB,CAAC;IAI3B,YAAY,CAChB,MAAM,EAAE,uBAAuB,EAC/B,OAAO,CAAC,EAAE,mBAAmB,GAC5B,OAAO,CAAC,IAAI,CAAC;IAIV,kBAAkB,CACtB,MAAM,EAAE,6BAA6B,EACrC,OAAO,CAAC,EAAE,mBAAmB,GAC5B,OAAO,CAAC,IAAI,CAAC;IASV,YAAY,CAChB,MAAM,EAAE,uBAAuB,EAC/B,OAAO,CAAC,EAAE,mBAAmB,GAC5B,OAAO,CAAC,IAAI,CAAC;IAShB;;;;;;OAMG;IACG,YAAY,CAChB,MAAM,EAAE,uBAAuB,EAC/B,OAAO,CAAC,EAAE,mBAAmB,GAC5B,OAAO,CAAC,UAAU,CAAC;YAiER,OAAO;CA0EtB"}