@cursor/july 0.1.99 → 0.1.100
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/AGENTS.md +4 -2
- package/dist/channels/github/defaults.d.ts.map +1 -1
- package/dist/channels/github/defaults.js +28 -3
- package/dist/channels/github/progress.d.ts +7 -0
- package/dist/channels/github/progress.d.ts.map +1 -1
- package/dist/channels/slack/api.d.ts +16 -7
- package/dist/channels/slack/api.d.ts.map +1 -1
- package/dist/channels/slack/api.js +29 -13
- package/dist/channels/slack/constants.d.ts +6 -0
- package/dist/channels/slack/constants.d.ts.map +1 -1
- package/dist/channels/slack/constants.js +6 -0
- package/dist/channels/slack/defaults.d.ts +9 -4
- package/dist/channels/slack/defaults.d.ts.map +1 -1
- package/dist/channels/slack/defaults.js +154 -76
- package/dist/channels/slack/dispatch.d.ts.map +1 -1
- package/dist/channels/slack/dispatch.js +3 -3
- package/dist/channels/slack/inbound.d.ts +9 -0
- package/dist/channels/slack/inbound.d.ts.map +1 -1
- package/dist/channels/slack/inbound.js +14 -0
- package/dist/channels/slack/index.d.ts +1 -0
- package/dist/channels/slack/index.d.ts.map +1 -1
- package/dist/channels/slack/index.js +1 -0
- package/dist/channels/slack/live-delivery.d.ts +5 -0
- package/dist/channels/slack/live-delivery.d.ts.map +1 -1
- package/dist/channels/slack/live-delivery.js +107 -19
- package/dist/channels/slack/reasoning-card.d.ts +38 -0
- package/dist/channels/slack/reasoning-card.d.ts.map +1 -0
- package/dist/channels/slack/reasoning-card.js +104 -0
- package/dist/channels/slack/redact.d.ts +2 -0
- package/dist/channels/slack/redact.d.ts.map +1 -0
- package/dist/channels/slack/redact.js +5 -0
- package/dist/channels/slack/reply-options.d.ts +40 -0
- package/dist/channels/slack/reply-options.d.ts.map +1 -0
- package/dist/channels/slack/reply-options.js +150 -0
- package/dist/channels/slack/slack-channel.d.ts.map +1 -1
- package/dist/channels/slack/slack-channel.js +8 -4
- package/dist/channels/slack/stream.d.ts +22 -10
- package/dist/channels/slack/stream.d.ts.map +1 -1
- package/dist/channels/slack/stream.js +9 -16
- package/dist/channels/slack/tool-cards.d.ts +22 -0
- package/dist/channels/slack/tool-cards.d.ts.map +1 -0
- package/dist/channels/slack/tool-cards.js +178 -0
- package/dist/channels/slack/types.d.ts +145 -6
- package/dist/channels/slack/types.d.ts.map +1 -1
- package/dist/docs/404.html +2 -2
- package/dist/docs/ab.html +6 -6
- package/dist/docs/ab.md +1 -1
- package/dist/docs/assets/{ab.md.DJo5r4R-.js → ab.md.mlVgqvSk.js} +1 -1
- package/dist/docs/assets/{app.BplEAZ3S.js → app.DZ1e0Ycq.js} +1 -1
- package/dist/docs/assets/{building-with-agents.md.DI4mEzlt.js → building-with-agents.md.CUSWxlP_.js} +2 -2
- package/dist/docs/assets/chunks/@localSearchIndexroot.j70vvPL4.js +1 -0
- package/dist/docs/assets/chunks/{VPLocalSearchBox.CHXyv4wP.js → VPLocalSearchBox.l8omwc6D.js} +1 -1
- package/dist/docs/assets/chunks/{theme.BTcsZmjQ.js → theme.JVcD6gel.js} +2 -2
- package/dist/docs/assets/{evals.md.lfJoEVc8.js → evals.md.CPzDAwoH.js} +1 -1
- package/dist/docs/assets/{guides_github.md.Cnh2mL4a.js → guides_github.md.BtPr9GaP.js} +1 -1
- package/dist/docs/assets/{guides_mcp-oauth.md.CN-6YmTJ.js → guides_mcp-oauth.md.Dp6cDP7f.js} +1 -1
- package/dist/docs/assets/{guides_opentelemetry.md.bmPmkvJu.js → guides_opentelemetry.md.BVTXDCRg.js} +2 -2
- package/dist/docs/assets/{guides_slack.md.VDXQV3ja.js → guides_slack.md.9oHPye9o.js} +19 -3
- package/dist/docs/assets/{guides_slack.md.VDXQV3ja.lean.js → guides_slack.md.9oHPye9o.lean.js} +1 -1
- package/dist/docs/assets/hillclimbing.md.CpTGTCle.js +4 -0
- package/dist/docs/assets/{index.md.CVeRUOeZ.js → index.md.Bb4k8kUm.js} +1 -1
- package/dist/docs/assets/{quickstart.md.Nj_LjW_a.js → quickstart.md.DdQOF7Y8.js} +1 -1
- package/dist/docs/assets/{reference_connections.md.DxldvyIB.js → reference_connections.md.BiGoBAk2.js} +1 -1
- package/dist/docs/assets/scaffolding-agents.md.em43xlY1.js +1 -0
- package/dist/docs/assets/skills_ab.md.CsFNatVx.js +26 -0
- package/dist/docs/assets/skills_ab.md.CsFNatVx.lean.js +1 -0
- package/dist/docs/assets/skills_create-agent.md.BVoWPcan.js +8 -0
- package/dist/docs/assets/skills_create-agent.md.BVoWPcan.lean.js +1 -0
- package/dist/docs/assets/skills_debug.md.CDbPhHfg.js +1 -0
- package/dist/docs/assets/skills_debug.md.CDbPhHfg.lean.js +1 -0
- package/dist/docs/assets/skills_evals.md.723kpUmA.js +25 -0
- package/dist/docs/assets/skills_evals.md.723kpUmA.lean.js +1 -0
- package/dist/docs/assets/skills_framework-map.md.BTi817yv.js +1 -0
- package/dist/docs/assets/skills_framework-map.md.BTi817yv.lean.js +1 -0
- package/dist/docs/assets/skills_github.md.D0JahM8c.js +16 -0
- package/dist/docs/assets/skills_github.md.D0JahM8c.lean.js +1 -0
- package/dist/docs/assets/skills_hillclimb.md.B_zJerxA.js +7 -0
- package/dist/docs/assets/skills_hillclimb.md.B_zJerxA.lean.js +1 -0
- package/dist/docs/assets/skills_index.md.DKwIxzGg.js +1 -0
- package/dist/docs/assets/skills_index.md.DKwIxzGg.lean.js +1 -0
- package/dist/docs/assets/skills_mcp-auth.md.DGvFP3HE.js +18 -0
- package/dist/docs/assets/skills_mcp-auth.md.DGvFP3HE.lean.js +1 -0
- package/dist/docs/assets/skills_otel.md.CgiZryR3.js +8 -0
- package/dist/docs/assets/skills_otel.md.CgiZryR3.lean.js +1 -0
- package/dist/docs/assets/skills_setup-slack.md.BBgx8lUz.js +20 -0
- package/dist/docs/assets/skills_setup-slack.md.BBgx8lUz.lean.js +1 -0
- package/dist/docs/assets/{troubleshooting.md.DCiPBhYs.js → troubleshooting.md.Cus_YZga.js} +1 -1
- package/dist/docs/building-with-agents.html +6 -6
- package/dist/docs/building-with-agents.md +14 -11
- package/dist/docs/concepts.html +4 -4
- package/dist/docs/deployment.html +4 -4
- package/dist/docs/evals.html +6 -6
- package/dist/docs/evals.md +1 -1
- package/dist/docs/guides/agent-to-agent.html +4 -4
- package/dist/docs/guides/cloud-runtime.html +4 -4
- package/dist/docs/guides/convert-automation.html +4 -4
- package/dist/docs/guides/github.html +5 -5
- package/dist/docs/guides/github.md +1 -1
- package/dist/docs/guides/human-in-the-loop.html +4 -4
- package/dist/docs/guides/mcp-oauth.html +5 -5
- package/dist/docs/guides/mcp-oauth.md +1 -1
- package/dist/docs/guides/opentelemetry.html +7 -7
- package/dist/docs/guides/opentelemetry.md +2 -2
- package/dist/docs/guides/slack.html +22 -6
- package/dist/docs/guides/slack.md +80 -1
- package/dist/docs/guides/webhooks.html +5 -5
- package/dist/docs/hashmap.json +1 -1
- package/dist/docs/hillclimbing.html +6 -6
- package/dist/docs/hillclimbing.md +5 -5
- package/dist/docs/index.html +6 -6
- package/dist/docs/index.md +1 -1
- package/dist/docs/llms-full.txt +1041 -30
- package/dist/docs/llms.txt +14 -0
- package/dist/docs/quickstart.html +5 -5
- package/dist/docs/quickstart.md +1 -1
- package/dist/docs/reference/agent-config.html +4 -4
- package/dist/docs/reference/artifacts.html +4 -4
- package/dist/docs/reference/channels.html +4 -4
- package/dist/docs/reference/cli.html +4 -4
- package/dist/docs/reference/connections.html +6 -6
- package/dist/docs/reference/connections.md +1 -1
- package/dist/docs/reference/hooks.html +4 -4
- package/dist/docs/reference/http-api.html +4 -4
- package/dist/docs/reference/instructions.html +4 -4
- package/dist/docs/reference/playground.html +4 -4
- package/dist/docs/reference/project-layout.html +4 -4
- package/dist/docs/reference/prompt.html +4 -4
- package/dist/docs/reference/schedules.html +4 -4
- package/dist/docs/reference/sessions.html +4 -4
- package/dist/docs/reference/skills.html +4 -4
- package/dist/docs/reference/subagents.html +4 -4
- package/dist/docs/reference/tools.html +4 -4
- package/dist/docs/scaffolding-agents.html +5 -5
- package/dist/docs/scaffolding-agents.md +3 -3
- package/dist/docs/skills/ab.html +52 -0
- package/dist/docs/skills/ab.md +50 -0
- package/dist/docs/skills/create-agent.html +34 -0
- package/dist/docs/skills/create-agent.md +160 -0
- package/dist/docs/skills/debug.html +27 -0
- package/dist/docs/skills/debug.md +36 -0
- package/dist/docs/skills/evals.html +51 -0
- package/dist/docs/skills/evals.md +99 -0
- package/dist/docs/skills/framework-map.html +27 -0
- package/dist/docs/skills/framework-map.md +95 -0
- package/dist/docs/skills/github.html +42 -0
- package/dist/docs/skills/github.md +93 -0
- package/dist/docs/skills/hillclimb.html +33 -0
- package/dist/docs/skills/hillclimb.md +55 -0
- package/dist/docs/skills/index.html +27 -0
- package/dist/docs/skills/index.md +21 -0
- package/dist/docs/skills/mcp-auth.html +44 -0
- package/dist/docs/skills/mcp-auth.md +76 -0
- package/dist/docs/skills/otel.html +34 -0
- package/dist/docs/skills/otel.md +48 -0
- package/dist/docs/skills/setup-slack.html +46 -0
- package/dist/docs/skills/setup-slack.md +141 -0
- package/dist/docs/storage.html +4 -4
- package/dist/docs/templates/agentic-owners.html +4 -4
- package/dist/docs/templates/agents-md.html +4 -4
- package/dist/docs/templates/code-wiki.html +4 -4
- package/dist/docs/templates/demo.html +4 -4
- package/dist/docs/templates/pr-autofixer.html +4 -4
- package/dist/docs/templates/security-help.html +4 -4
- package/dist/docs/templates/security-reviewer.html +4 -4
- package/dist/docs/templates/triage.html +4 -4
- package/dist/docs/troubleshooting.html +5 -5
- package/dist/docs/troubleshooting.md +1 -1
- package/dist/files-backends/cursor-hosted.d.ts +6 -0
- package/dist/files-backends/cursor-hosted.d.ts.map +1 -1
- package/dist/files-backends/cursor-hosted.js +6 -9
- package/dist/internal/cli-deploy.js +2 -2
- package/dist/internal/conversation-mirror.d.ts.map +1 -1
- package/dist/internal/conversation-mirror.js +3 -4
- package/dist/internal/cursor/hosted-store-secrets.d.ts +15 -0
- package/dist/internal/cursor/hosted-store-secrets.d.ts.map +1 -0
- package/dist/internal/cursor/hosted-store-secrets.js +48 -0
- package/dist/internal/deploy-client.d.ts +6 -6
- package/dist/internal/deploy-client.js +7 -7
- package/dist/internal/discovery.d.ts.map +1 -1
- package/dist/internal/discovery.js +11 -1
- package/dist/internal/framework-file-storage.d.ts +12 -5
- package/dist/internal/framework-file-storage.d.ts.map +1 -1
- package/dist/internal/framework-file-storage.js +36 -5
- package/dist/internal/framework-storage-selection.d.ts +12 -12
- package/dist/internal/framework-storage-selection.d.ts.map +1 -1
- package/dist/internal/framework-storage-selection.js +33 -39
- package/dist/internal/session-run-log.d.ts +3 -3
- package/dist/internal/session-run-log.d.ts.map +1 -1
- package/dist/internal/session-run-log.js +6 -7
- package/dist/internal/storage-coordinator.d.ts +0 -6
- package/dist/internal/storage-coordinator.d.ts.map +1 -1
- package/dist/internal/storage-coordinator.js +1 -9
- package/dist/playground/assets/index-BszoQDc6.css +1 -0
- package/dist/playground/assets/{index-jzNbJENa.js → index-DVs98vPL.js} +1 -1
- package/dist/playground/index.html +2 -2
- package/dist/storage-backends/cursor-hosted-v2.d.ts +83 -0
- package/dist/storage-backends/cursor-hosted-v2.d.ts.map +1 -0
- package/dist/storage-backends/cursor-hosted-v2.js +164 -0
- package/dist/storage-backends/cursor-hosted.d.ts +6 -0
- package/dist/storage-backends/cursor-hosted.d.ts.map +1 -1
- package/dist/storage-backends/cursor-hosted.js +6 -1
- package/dist/types.d.ts +5 -0
- package/dist/types.d.ts.map +1 -1
- package/docs/README.md +1 -1
- package/docs/ab.md +1 -1
- package/docs/building-with-agents.md +14 -11
- package/docs/evals.md +1 -1
- package/docs/guides/github.md +1 -1
- package/docs/guides/mcp-oauth.md +1 -1
- package/docs/guides/opentelemetry.md +2 -2
- package/docs/guides/slack.md +80 -1
- package/docs/hillclimbing.md +5 -5
- package/docs/quickstart.md +1 -1
- package/docs/reference/connections.md +1 -1
- package/docs/scaffolding-agents.md +3 -3
- package/docs/skills/index.md +26 -0
- package/docs/troubleshooting.md +1 -1
- package/package.json +1 -1
- package/src/channels/github/defaults.ts +36 -3
- package/src/channels/github/progress.ts +7 -0
- package/src/channels/slack/api.ts +35 -17
- package/src/channels/slack/constants.ts +6 -0
- package/src/channels/slack/defaults.ts +173 -92
- package/src/channels/slack/dispatch.ts +8 -1
- package/src/channels/slack/inbound.ts +17 -0
- package/src/channels/slack/index.ts +1 -0
- package/src/channels/slack/live-delivery.ts +131 -20
- package/src/channels/slack/reasoning-card.ts +140 -0
- package/src/channels/slack/redact.ts +6 -0
- package/src/channels/slack/reply-options.ts +229 -0
- package/src/channels/slack/slack-channel.ts +7 -2
- package/src/channels/slack/stream.ts +31 -24
- package/src/channels/slack/tool-cards.ts +221 -0
- package/src/channels/slack/types.ts +159 -6
- package/src/files-backends/cursor-hosted.ts +15 -5
- package/src/internal/cli-deploy.ts +2 -2
- package/src/internal/conversation-mirror.ts +3 -8
- package/src/internal/cursor/hosted-store-secrets.ts +72 -0
- package/src/internal/deploy-client.ts +10 -10
- package/src/internal/discovery.ts +9 -1
- package/src/internal/framework-file-storage.ts +41 -5
- package/src/internal/framework-storage-selection.ts +31 -44
- package/src/internal/session-run-log.ts +6 -11
- package/src/internal/storage-coordinator.ts +1 -11
- package/src/storage-backends/cursor-hosted-v2.ts +219 -0
- package/src/storage-backends/cursor-hosted.ts +6 -1
- package/src/types.ts +5 -0
- package/dist/docs/assets/chunks/@localSearchIndexroot.DpuI4i7Z.js +0 -1
- package/dist/docs/assets/hillclimbing.md.DhESf3OO.js +0 -4
- package/dist/docs/assets/scaffolding-agents.md.D7UUkWw0.js +0 -1
- package/dist/internal/null-kv-storage.d.ts +0 -48
- package/dist/internal/null-kv-storage.d.ts.map +0 -1
- package/dist/internal/null-kv-storage.js +0 -58
- package/dist/playground/assets/index-D7rGZNjy.css +0 -1
- package/src/internal/null-kv-storage.ts +0 -74
- /package/dist/docs/assets/{ab.md.DJo5r4R-.lean.js → ab.md.mlVgqvSk.lean.js} +0 -0
- /package/dist/docs/assets/{building-with-agents.md.DI4mEzlt.lean.js → building-with-agents.md.CUSWxlP_.lean.js} +0 -0
- /package/dist/docs/assets/{evals.md.lfJoEVc8.lean.js → evals.md.CPzDAwoH.lean.js} +0 -0
- /package/dist/docs/assets/{guides_github.md.Cnh2mL4a.lean.js → guides_github.md.BtPr9GaP.lean.js} +0 -0
- /package/dist/docs/assets/{guides_mcp-oauth.md.CN-6YmTJ.lean.js → guides_mcp-oauth.md.Dp6cDP7f.lean.js} +0 -0
- /package/dist/docs/assets/{guides_opentelemetry.md.bmPmkvJu.lean.js → guides_opentelemetry.md.BVTXDCRg.lean.js} +0 -0
- /package/dist/docs/assets/{hillclimbing.md.DhESf3OO.lean.js → hillclimbing.md.CpTGTCle.lean.js} +0 -0
- /package/dist/docs/assets/{index.md.CVeRUOeZ.lean.js → index.md.Bb4k8kUm.lean.js} +0 -0
- /package/dist/docs/assets/{quickstart.md.Nj_LjW_a.lean.js → quickstart.md.DdQOF7Y8.lean.js} +0 -0
- /package/dist/docs/assets/{reference_connections.md.DxldvyIB.lean.js → reference_connections.md.BiGoBAk2.lean.js} +0 -0
- /package/dist/docs/assets/{scaffolding-agents.md.D7UUkWw0.lean.js → scaffolding-agents.md.em43xlY1.lean.js} +0 -0
- /package/dist/docs/assets/{troubleshooting.md.DCiPBhYs.lean.js → troubleshooting.md.Cus_YZga.lean.js} +0 -0
|
@@ -8,12 +8,28 @@
|
|
|
8
8
|
* Assistant-pane threads only render stream APIs. Start lazily with the
|
|
9
9
|
* first real markdown/chunks plus recipient ids — empty startStream is
|
|
10
10
|
* rejected or never attaches.
|
|
11
|
+
*
|
|
12
|
+
* Every call speaks `chunks`. Slack pins a stream's mode at start: text
|
|
13
|
+
* opened as bare `markdown_text` rejects later `task_update` appends with
|
|
14
|
+
* `streaming_mode_mismatch`, so assistant text goes out as `markdown_text`
|
|
15
|
+
* chunks and tool steps can land in the same message.
|
|
11
16
|
*/
|
|
12
17
|
|
|
13
18
|
import type { ChannelEventContext } from "../../types.js";
|
|
14
|
-
import {
|
|
19
|
+
import {
|
|
20
|
+
appendChatStream,
|
|
21
|
+
postMessage,
|
|
22
|
+
startChatStream,
|
|
23
|
+
stopChatStream,
|
|
24
|
+
} from "./api.js";
|
|
25
|
+
import { SLACK_MARKDOWN_TEXT_MAX_LEN } from "./constants.js";
|
|
15
26
|
import type { SlackLog } from "./log.js";
|
|
16
|
-
import {
|
|
27
|
+
import {
|
|
28
|
+
computeStreamAppend,
|
|
29
|
+
markdownChunk,
|
|
30
|
+
type StreamChunk,
|
|
31
|
+
type StreamTaskChunk,
|
|
32
|
+
} from "./stream.js";
|
|
17
33
|
import type { SlackBotToken, SlackChannelState } from "./types.js";
|
|
18
34
|
|
|
19
35
|
type SlackChannel = ChannelEventContext<SlackChannelState>;
|
|
@@ -98,9 +114,13 @@ export function createStreamDeliveryStrategy(
|
|
|
98
114
|
if (activeStreamTs(channel) !== null) {
|
|
99
115
|
return true;
|
|
100
116
|
}
|
|
101
|
-
const
|
|
102
|
-
const
|
|
103
|
-
if (
|
|
117
|
+
const openingText = markdown_text ?? "";
|
|
118
|
+
const opening: StreamChunk[] = [];
|
|
119
|
+
if (openingText !== "") {
|
|
120
|
+
opening.push(markdownChunk(openingText));
|
|
121
|
+
}
|
|
122
|
+
opening.push(...(chunks ?? []));
|
|
123
|
+
if (opening.length === 0) {
|
|
104
124
|
return false;
|
|
105
125
|
}
|
|
106
126
|
const log = getLog();
|
|
@@ -108,8 +128,7 @@ export function createStreamDeliveryStrategy(
|
|
|
108
128
|
botToken,
|
|
109
129
|
channel: channelId,
|
|
110
130
|
thread_ts: threadTs,
|
|
111
|
-
|
|
112
|
-
chunks: hasChunks ? chunks : undefined,
|
|
131
|
+
chunks: opening,
|
|
113
132
|
...streamRecipients(channel),
|
|
114
133
|
});
|
|
115
134
|
if (!started.ok) {
|
|
@@ -126,8 +145,9 @@ export function createStreamDeliveryStrategy(
|
|
|
126
145
|
}
|
|
127
146
|
channel.state.streamTs = started.ts;
|
|
128
147
|
channel.state.streamChannelId = started.channel;
|
|
129
|
-
channel.state.
|
|
130
|
-
channel.state.
|
|
148
|
+
channel.state.streamFull = false;
|
|
149
|
+
channel.state.lastPostedText = openingText;
|
|
150
|
+
channel.state.streamBlockText = openingText;
|
|
131
151
|
log.info("chat.startStream ok", {
|
|
132
152
|
channel: started.channel,
|
|
133
153
|
stream_ts: started.ts,
|
|
@@ -175,7 +195,7 @@ export function createStreamDeliveryStrategy(
|
|
|
175
195
|
botToken,
|
|
176
196
|
channel: args.channelId,
|
|
177
197
|
ts: args.ts,
|
|
178
|
-
|
|
198
|
+
chunks: appendText === "" ? undefined : [markdownChunk(appendText)],
|
|
179
199
|
});
|
|
180
200
|
args.channel.state.streamTs = null;
|
|
181
201
|
if (stopped.ok) {
|
|
@@ -199,11 +219,77 @@ export function createStreamDeliveryStrategy(
|
|
|
199
219
|
channel.state.streamTs = null;
|
|
200
220
|
};
|
|
201
221
|
|
|
222
|
+
/**
|
|
223
|
+
* `msg_too_long` means the message is full: every further append would
|
|
224
|
+
* fail the same way, so appends stop until `finalize` continues the reply
|
|
225
|
+
* in a new message.
|
|
226
|
+
*/
|
|
227
|
+
const noteAppendFailure = (
|
|
228
|
+
channel: SlackChannel,
|
|
229
|
+
result: { error?: string; unsupported?: boolean }
|
|
230
|
+
): void => {
|
|
231
|
+
if (result.unsupported === true) {
|
|
232
|
+
channel.state.streamingUnavailable = true;
|
|
233
|
+
}
|
|
234
|
+
if (result.error === "msg_too_long") {
|
|
235
|
+
channel.state.streamFull = true;
|
|
236
|
+
}
|
|
237
|
+
};
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* The streamed message is full. Close it as it stands so it stops spinning
|
|
241
|
+
* and post the rest as a new thread message. Most of the answer is on Slack
|
|
242
|
+
* either way, so the reply counts as delivered even if that post fails: a
|
|
243
|
+
* duplicate would be worse than a lost tail.
|
|
244
|
+
*/
|
|
245
|
+
const continueOverflow = async (args: {
|
|
246
|
+
channel: SlackChannel;
|
|
247
|
+
channelId: string;
|
|
248
|
+
ts: string;
|
|
249
|
+
remainder: string;
|
|
250
|
+
sessionId: string;
|
|
251
|
+
}): Promise<void> => {
|
|
252
|
+
const { channel, channelId, ts, remainder, sessionId } = args;
|
|
253
|
+
const log = getLog();
|
|
254
|
+
await stopChatStream({ botToken, channel: channelId, ts });
|
|
255
|
+
channel.state.streamTs = null;
|
|
256
|
+
const threadTs = channel.state.threadTs;
|
|
257
|
+
if (remainder === "" || threadTs === null || threadTs === "") {
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
try {
|
|
261
|
+
const posted = await postMessage({
|
|
262
|
+
botToken,
|
|
263
|
+
channel: channelId,
|
|
264
|
+
text: remainder,
|
|
265
|
+
threadTs,
|
|
266
|
+
plainText: remainder.length >= SLACK_MARKDOWN_TEXT_MAX_LEN,
|
|
267
|
+
});
|
|
268
|
+
channel.state.lastBotMessageTs = posted.ts;
|
|
269
|
+
log.info("reply overflowed the stream; continued in a new message", {
|
|
270
|
+
channel: channelId,
|
|
271
|
+
stream_ts: ts,
|
|
272
|
+
session: sessionId,
|
|
273
|
+
continued_chars: remainder.length,
|
|
274
|
+
});
|
|
275
|
+
} catch (error) {
|
|
276
|
+
log.warn("stream overflow continuation failed", {
|
|
277
|
+
error: error instanceof Error ? error.message : String(error),
|
|
278
|
+
channel: channelId,
|
|
279
|
+
stream_ts: ts,
|
|
280
|
+
session: sessionId,
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
};
|
|
284
|
+
|
|
202
285
|
return {
|
|
203
286
|
inlineToolSteps: true,
|
|
204
287
|
open,
|
|
205
288
|
|
|
206
289
|
async append({ channel, channelId, text, sessionId }) {
|
|
290
|
+
if (channel.state.streamFull === true) {
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
207
293
|
const ts = await ensureOpen({
|
|
208
294
|
channel,
|
|
209
295
|
channelId,
|
|
@@ -224,7 +310,7 @@ export function createStreamDeliveryStrategy(
|
|
|
224
310
|
botToken,
|
|
225
311
|
channel: channelId,
|
|
226
312
|
ts,
|
|
227
|
-
|
|
313
|
+
chunks: [markdownChunk(appendText)],
|
|
228
314
|
});
|
|
229
315
|
if (!result.ok) {
|
|
230
316
|
getLog().warn("appendStream failed", {
|
|
@@ -233,9 +319,7 @@ export function createStreamDeliveryStrategy(
|
|
|
233
319
|
stream_ts: ts,
|
|
234
320
|
session: sessionId,
|
|
235
321
|
});
|
|
236
|
-
|
|
237
|
-
channel.state.streamingUnavailable = true;
|
|
238
|
-
}
|
|
322
|
+
noteAppendFailure(channel, result);
|
|
239
323
|
return;
|
|
240
324
|
}
|
|
241
325
|
channel.state.lastPostedText = text;
|
|
@@ -243,6 +327,9 @@ export function createStreamDeliveryStrategy(
|
|
|
243
327
|
},
|
|
244
328
|
|
|
245
329
|
async appendChunks({ channel, channelId, chunks, sessionId }) {
|
|
330
|
+
if (channel.state.streamFull === true) {
|
|
331
|
+
return false;
|
|
332
|
+
}
|
|
246
333
|
const hadStream = activeStreamTs(channel) !== null;
|
|
247
334
|
const ts = await ensureOpen({
|
|
248
335
|
channel,
|
|
@@ -262,6 +349,16 @@ export function createStreamDeliveryStrategy(
|
|
|
262
349
|
ts,
|
|
263
350
|
chunks,
|
|
264
351
|
});
|
|
352
|
+
if (!result.ok) {
|
|
353
|
+
getLog().warn("appendStream chunks failed", {
|
|
354
|
+
error: result.error,
|
|
355
|
+
channel: channelId,
|
|
356
|
+
stream_ts: ts,
|
|
357
|
+
session: sessionId,
|
|
358
|
+
chunks: chunks.length,
|
|
359
|
+
});
|
|
360
|
+
noteAppendFailure(channel, result);
|
|
361
|
+
}
|
|
265
362
|
return result.ok;
|
|
266
363
|
},
|
|
267
364
|
|
|
@@ -276,12 +373,15 @@ export function createStreamDeliveryStrategy(
|
|
|
276
373
|
if (ts === null) {
|
|
277
374
|
return { delivered: false };
|
|
278
375
|
}
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
376
|
+
// Measured before the stop attempt mutates stream state.
|
|
377
|
+
const remainder = computeStreamAppend(
|
|
378
|
+
channel.state.streamBlockText,
|
|
379
|
+
text
|
|
380
|
+
);
|
|
381
|
+
const stopped =
|
|
382
|
+
channel.state.streamFull === true
|
|
383
|
+
? { ok: false, error: "msg_too_long" }
|
|
384
|
+
: await stopWithSuffix({ channel, channelId, ts, text });
|
|
285
385
|
if (stopped.ok) {
|
|
286
386
|
log.info("reply delivered via stream", {
|
|
287
387
|
channel: channelId,
|
|
@@ -291,6 +391,17 @@ export function createStreamDeliveryStrategy(
|
|
|
291
391
|
});
|
|
292
392
|
return { delivered: true };
|
|
293
393
|
}
|
|
394
|
+
if (stopped.error === "msg_too_long") {
|
|
395
|
+
await continueOverflow({
|
|
396
|
+
channel,
|
|
397
|
+
channelId,
|
|
398
|
+
ts,
|
|
399
|
+
remainder,
|
|
400
|
+
sessionId,
|
|
401
|
+
});
|
|
402
|
+
channel.state.lastPostedText = text;
|
|
403
|
+
return { delivered: true };
|
|
404
|
+
}
|
|
294
405
|
log.warn("chat.stopStream failed; falling back to postMessage", {
|
|
295
406
|
error: stopped.error,
|
|
296
407
|
channel: channelId,
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The "Thinking" task card that receives the model's reasoning as it streams.
|
|
3
|
+
* Slack appends a card's `details` across updates, so the card is fed
|
|
4
|
+
* deltas: the part of the current reasoning block already on Slack, plus a
|
|
5
|
+
* buffer of what has not gone out yet.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { ChannelEventContext } from "../../types.js";
|
|
9
|
+
import type { ResolvedSlackReasoningCard } from "./reply-options.js";
|
|
10
|
+
import { type StreamTaskChunk, truncateCardText } from "./stream.js";
|
|
11
|
+
import type { ReasoningCardState, SlackChannelState } from "./types.js";
|
|
12
|
+
|
|
13
|
+
const FLUSH_MS = 1_000;
|
|
14
|
+
const FLUSH_CHARS = 160;
|
|
15
|
+
const CARD_ID = "reasoning";
|
|
16
|
+
const BLOCK_SEPARATOR = "\n\n";
|
|
17
|
+
|
|
18
|
+
type Channel = ChannelEventContext<SlackChannelState>;
|
|
19
|
+
type CardStatus = "in_progress" | "complete";
|
|
20
|
+
|
|
21
|
+
export interface ReasoningCard {
|
|
22
|
+
/** Buffer the current reasoning block's cumulative text; flushes when due. */
|
|
23
|
+
append(args: {
|
|
24
|
+
channel: Channel;
|
|
25
|
+
sessionId: string;
|
|
26
|
+
text: string;
|
|
27
|
+
}): Promise<void>;
|
|
28
|
+
/** Send buffered text and set the card status. */
|
|
29
|
+
flush(args: {
|
|
30
|
+
channel: Channel;
|
|
31
|
+
sessionId: string;
|
|
32
|
+
status: CardStatus;
|
|
33
|
+
}): Promise<void>;
|
|
34
|
+
/** The next reasoning block appends after a blank line. */
|
|
35
|
+
endBlock(channel: Channel): void;
|
|
36
|
+
inProgress(channel: Channel): boolean;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** Delivers one chunk into the reply stream; `false` when nothing went out. */
|
|
40
|
+
export type SendCardChunk = (args: {
|
|
41
|
+
channel: Channel;
|
|
42
|
+
sessionId: string;
|
|
43
|
+
chunk: StreamTaskChunk;
|
|
44
|
+
}) => Promise<boolean>;
|
|
45
|
+
|
|
46
|
+
function cardState(state: SlackChannelState): ReasoningCardState {
|
|
47
|
+
if (state.reasoningCard === undefined) {
|
|
48
|
+
state.reasoningCard = {
|
|
49
|
+
status: null,
|
|
50
|
+
blockSent: null,
|
|
51
|
+
pending: "",
|
|
52
|
+
lastFlushMs: null,
|
|
53
|
+
chars: 0,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
return state.reasoningCard;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function createReasoningCard(
|
|
60
|
+
card: ResolvedSlackReasoningCard,
|
|
61
|
+
send: SendCardChunk
|
|
62
|
+
): ReasoningCard {
|
|
63
|
+
const flush: ReasoningCard["flush"] = async ({
|
|
64
|
+
channel,
|
|
65
|
+
sessionId,
|
|
66
|
+
status,
|
|
67
|
+
}) => {
|
|
68
|
+
const state = cardState(channel.state);
|
|
69
|
+
if (
|
|
70
|
+
state.pending === "" &&
|
|
71
|
+
(state.status === status || state.status === null)
|
|
72
|
+
) {
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
const chunk: StreamTaskChunk = {
|
|
76
|
+
type: "task_update",
|
|
77
|
+
id: CARD_ID,
|
|
78
|
+
title: card.title,
|
|
79
|
+
status,
|
|
80
|
+
};
|
|
81
|
+
if (state.pending !== "") {
|
|
82
|
+
chunk.details = state.pending;
|
|
83
|
+
}
|
|
84
|
+
// Stamped on the attempt, so a failing stream is retried at most once
|
|
85
|
+
// per flush window instead of once per token.
|
|
86
|
+
state.lastFlushMs = Date.now();
|
|
87
|
+
if (!(await send({ channel, sessionId, chunk }))) {
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
state.chars += state.pending.length;
|
|
91
|
+
state.pending = "";
|
|
92
|
+
state.status = status;
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
return {
|
|
96
|
+
flush,
|
|
97
|
+
|
|
98
|
+
async append({ channel, sessionId, text }) {
|
|
99
|
+
const state = cardState(channel.state);
|
|
100
|
+
if (state.chars >= card.maxChars) {
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
const sent = state.blockSent ?? 0;
|
|
104
|
+
let delta: string;
|
|
105
|
+
if (sent > 0 && text.length >= sent) {
|
|
106
|
+
delta = text.slice(sent);
|
|
107
|
+
} else {
|
|
108
|
+
const hasText = state.chars + state.pending.length > 0;
|
|
109
|
+
delta = `${hasText ? BLOCK_SEPARATOR : ""}${text}`;
|
|
110
|
+
}
|
|
111
|
+
state.blockSent = text.length;
|
|
112
|
+
if (delta === "") {
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
let pending = `${state.pending}${delta}`;
|
|
116
|
+
const room = card.maxChars - state.chars;
|
|
117
|
+
if (pending.length > room) {
|
|
118
|
+
pending = truncateCardText(pending, room);
|
|
119
|
+
state.chars = card.maxChars - pending.length;
|
|
120
|
+
}
|
|
121
|
+
state.pending = pending;
|
|
122
|
+
|
|
123
|
+
const due =
|
|
124
|
+
state.lastFlushMs === null ||
|
|
125
|
+
Date.now() - state.lastFlushMs >= FLUSH_MS ||
|
|
126
|
+
pending.length >= FLUSH_CHARS;
|
|
127
|
+
if (due) {
|
|
128
|
+
await flush({ channel, sessionId, status: "in_progress" });
|
|
129
|
+
}
|
|
130
|
+
},
|
|
131
|
+
|
|
132
|
+
endBlock(channel) {
|
|
133
|
+
cardState(channel.state).blockSent = null;
|
|
134
|
+
},
|
|
135
|
+
|
|
136
|
+
inProgress(channel) {
|
|
137
|
+
return channel.state.reasoningCard?.status === "in_progress";
|
|
138
|
+
},
|
|
139
|
+
};
|
|
140
|
+
}
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve `slackChannel({ reply, toolLabels })` — and the deprecated
|
|
3
|
+
* `streaming` / `thinkingSteps` / `loadingMessages` flags — into one config
|
|
4
|
+
* the default event handlers read.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { SLACK_DEFAULT_LOADING_MESSAGES } from "./constants.js";
|
|
8
|
+
import { defaultToolCardDetails } from "./tool-cards.js";
|
|
9
|
+
import type {
|
|
10
|
+
SlackChannelOptions,
|
|
11
|
+
SlackReasoningCardOptions,
|
|
12
|
+
SlackReplyOptions,
|
|
13
|
+
SlackToolCall,
|
|
14
|
+
SlackToolCardGroup,
|
|
15
|
+
SlackToolLabels,
|
|
16
|
+
SlackToolResult,
|
|
17
|
+
} from "./types.js";
|
|
18
|
+
|
|
19
|
+
export type SlackReplyMode = "post" | "stream";
|
|
20
|
+
|
|
21
|
+
export interface ResolvedSlackStatus {
|
|
22
|
+
reasoning: boolean;
|
|
23
|
+
/** `false`, or the line to show when tool calls start. */
|
|
24
|
+
tools: false | ((calls: readonly SlackToolCall[]) => string);
|
|
25
|
+
idle: string[];
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface ResolvedSlackToolCards {
|
|
29
|
+
group: SlackToolCardGroup;
|
|
30
|
+
details?: (call: SlackToolCall) => string | undefined;
|
|
31
|
+
output?: (result: SlackToolResult) => string | undefined;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface ResolvedSlackReasoningCard {
|
|
35
|
+
title: string;
|
|
36
|
+
maxChars: number;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface ResolvedSlackReply {
|
|
40
|
+
mode: SlackReplyMode;
|
|
41
|
+
status: ResolvedSlackStatus;
|
|
42
|
+
toolCards: false | ResolvedSlackToolCards;
|
|
43
|
+
reasoningCard: false | ResolvedSlackReasoningCard;
|
|
44
|
+
toolLabel: (toolName: string) => string;
|
|
45
|
+
/** Author-facing notices about deprecated options that were honored. */
|
|
46
|
+
deprecations: string[];
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export const DEFAULT_REASONING_CARD_TITLE = "Thinking";
|
|
50
|
+
/** A modest share of `SLACK_MARKDOWN_TEXT_MAX_LEN`, which the whole streamed message shares. */
|
|
51
|
+
export const DEFAULT_REASONING_CARD_MAX_CHARS = 1500;
|
|
52
|
+
|
|
53
|
+
type ReplyInputs = Pick<
|
|
54
|
+
SlackChannelOptions,
|
|
55
|
+
"reply" | "toolLabels" | "streaming" | "thinkingSteps"
|
|
56
|
+
> & { loadingMessages?: readonly string[] };
|
|
57
|
+
|
|
58
|
+
function resolveToolLabel(
|
|
59
|
+
labels: SlackToolLabels | undefined
|
|
60
|
+
): (toolName: string) => string {
|
|
61
|
+
if (labels === undefined) {
|
|
62
|
+
return (toolName) => toolName;
|
|
63
|
+
}
|
|
64
|
+
const lookup =
|
|
65
|
+
typeof labels === "function" ? labels : (name: string) => labels[name];
|
|
66
|
+
return (toolName) => {
|
|
67
|
+
const label = lookup(toolName);
|
|
68
|
+
return label === undefined || label === "" ? toolName : label;
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function defaultToolStatusLine(
|
|
73
|
+
toolLabel: (toolName: string) => string
|
|
74
|
+
): (calls: readonly SlackToolCall[]) => string {
|
|
75
|
+
return (calls) => {
|
|
76
|
+
const names = [...new Set(calls.map((call) => toolLabel(call.toolName)))];
|
|
77
|
+
return `Running ${names.join(", ")}…`;
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function resolveIdle(idle: readonly string[] | undefined): string[] {
|
|
82
|
+
const cleaned = (idle ?? []).filter((line) => line.trim() !== "");
|
|
83
|
+
return cleaned.length > 0 ? cleaned : [...SLACK_DEFAULT_LOADING_MESSAGES];
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function resolveReasoningCard(
|
|
87
|
+
option: boolean | SlackReasoningCardOptions | undefined
|
|
88
|
+
): false | ResolvedSlackReasoningCard {
|
|
89
|
+
if (option === undefined || option === false) {
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
const options = option === true ? {} : option;
|
|
93
|
+
const title = options.title?.trim();
|
|
94
|
+
return {
|
|
95
|
+
title:
|
|
96
|
+
title === undefined || title === ""
|
|
97
|
+
? DEFAULT_REASONING_CARD_TITLE
|
|
98
|
+
: title,
|
|
99
|
+
maxChars:
|
|
100
|
+
options.maxChars !== undefined && options.maxChars > 0
|
|
101
|
+
? options.maxChars
|
|
102
|
+
: DEFAULT_REASONING_CARD_MAX_CHARS,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function resolveToolCards(
|
|
107
|
+
option: SlackReplyOptions & { mode: "stream" }
|
|
108
|
+
): false | ResolvedSlackToolCards {
|
|
109
|
+
const cards = option.toolCards;
|
|
110
|
+
if (cards === undefined || cards === false) {
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
if (cards === true) {
|
|
114
|
+
return { group: "per-tool", details: defaultToolCardDetails };
|
|
115
|
+
}
|
|
116
|
+
const group = cards.group ?? "per-tool";
|
|
117
|
+
if (cards.collapsible === false) {
|
|
118
|
+
return { group };
|
|
119
|
+
}
|
|
120
|
+
return {
|
|
121
|
+
group,
|
|
122
|
+
details: cards.details ?? defaultToolCardDetails,
|
|
123
|
+
output: cards.output,
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Map the deprecated flags onto a `reply` shape with their old defaults
|
|
129
|
+
* (streaming on, per-call cards on), so a config that only sets these keeps
|
|
130
|
+
* behaving as it did. `null` when none of them is set.
|
|
131
|
+
*/
|
|
132
|
+
function legacyReplyOptions(
|
|
133
|
+
options: ReplyInputs
|
|
134
|
+
): { reply: SlackReplyOptions; deprecations: string[] } | null {
|
|
135
|
+
const idle = options.loadingMessages;
|
|
136
|
+
if (
|
|
137
|
+
options.streaming === undefined &&
|
|
138
|
+
options.thinkingSteps === undefined &&
|
|
139
|
+
idle === undefined
|
|
140
|
+
) {
|
|
141
|
+
return null;
|
|
142
|
+
}
|
|
143
|
+
const deprecations: string[] = [];
|
|
144
|
+
const mode: SlackReplyMode = options.streaming === false ? "post" : "stream";
|
|
145
|
+
// What legacy streaming showed: one title-only card per call.
|
|
146
|
+
const cards = options.thinkingSteps === false ? false : LEGACY_CARDS;
|
|
147
|
+
const replacement =
|
|
148
|
+
mode === "post"
|
|
149
|
+
? 'reply: { mode: "post" }'
|
|
150
|
+
: cards === false
|
|
151
|
+
? 'reply: { mode: "stream" }'
|
|
152
|
+
: 'reply: { mode: "stream", toolCards: { group: "per-call", collapsible: false } }';
|
|
153
|
+
if (idle !== undefined) {
|
|
154
|
+
deprecations.push(
|
|
155
|
+
`slackChannel({ loadingMessages }) is deprecated; use reply: { mode: "${mode}", status: { idle: [...] } }.`
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
if (options.streaming !== undefined) {
|
|
159
|
+
deprecations.push(
|
|
160
|
+
`slackChannel({ streaming: ${String(options.streaming)} }) is deprecated; use ${replacement}.`
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
if (options.thinkingSteps !== undefined) {
|
|
164
|
+
deprecations.push(
|
|
165
|
+
mode === "post"
|
|
166
|
+
? "slackChannel({ thinkingSteps }) has no effect in post mode; remove it."
|
|
167
|
+
: `slackChannel({ thinkingSteps: ${String(options.thinkingSteps)} }) is deprecated; use ${replacement}.`
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
const status = { idle };
|
|
171
|
+
if (mode === "post") {
|
|
172
|
+
return { reply: { mode, status }, deprecations };
|
|
173
|
+
}
|
|
174
|
+
return { reply: { mode, status, toolCards: cards }, deprecations };
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
const LEGACY_CARDS = { group: "per-call", collapsible: false } as const;
|
|
178
|
+
|
|
179
|
+
export function resolveSlackReply(options: ReplyInputs): ResolvedSlackReply {
|
|
180
|
+
const deprecations: string[] = [];
|
|
181
|
+
let reply: SlackReplyOptions = { mode: "post" };
|
|
182
|
+
const legacy = legacyReplyOptions(options);
|
|
183
|
+
if (options.reply !== undefined) {
|
|
184
|
+
reply = options.reply;
|
|
185
|
+
if (legacy !== null) {
|
|
186
|
+
const ignored = (
|
|
187
|
+
["streaming", "thinkingSteps", "loadingMessages"] as const
|
|
188
|
+
).filter((key) => options[key] !== undefined);
|
|
189
|
+
deprecations.push(
|
|
190
|
+
`slackChannel({ ${ignored.join(", ")} }) is ignored because reply is set; remove the deprecated option${ignored.length === 1 ? "" : "s"}.`
|
|
191
|
+
);
|
|
192
|
+
}
|
|
193
|
+
} else if (legacy !== null) {
|
|
194
|
+
reply = legacy.reply;
|
|
195
|
+
deprecations.push(...legacy.deprecations);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
const toolLabel = resolveToolLabel(options.toolLabels);
|
|
199
|
+
const statusInput = reply.status ?? {};
|
|
200
|
+
const status: ResolvedSlackStatus = {
|
|
201
|
+
reasoning: statusInput.reasoning !== false,
|
|
202
|
+
tools:
|
|
203
|
+
statusInput.tools === false
|
|
204
|
+
? false
|
|
205
|
+
: typeof statusInput.tools === "function"
|
|
206
|
+
? statusInput.tools
|
|
207
|
+
: defaultToolStatusLine(toolLabel),
|
|
208
|
+
idle: resolveIdle(statusInput.idle),
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
if (reply.mode === "post") {
|
|
212
|
+
return {
|
|
213
|
+
mode: "post",
|
|
214
|
+
status,
|
|
215
|
+
toolCards: false,
|
|
216
|
+
reasoningCard: false,
|
|
217
|
+
toolLabel,
|
|
218
|
+
deprecations,
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
return {
|
|
222
|
+
mode: "stream",
|
|
223
|
+
status,
|
|
224
|
+
toolCards: resolveToolCards(reply),
|
|
225
|
+
reasoningCard: resolveReasoningCard(reply.reasoningCard),
|
|
226
|
+
toolLabel,
|
|
227
|
+
deprecations,
|
|
228
|
+
};
|
|
229
|
+
}
|
|
@@ -57,6 +57,7 @@ import {
|
|
|
57
57
|
dispatchInteractiveFromPayload,
|
|
58
58
|
} from "./interactive.js";
|
|
59
59
|
import { createSlackLogger, type SlackLog } from "./log.js";
|
|
60
|
+
import { resolveSlackReply } from "./reply-options.js";
|
|
60
61
|
import {
|
|
61
62
|
type SlackSocketModeHandle,
|
|
62
63
|
type SlackSocketModeOptions,
|
|
@@ -128,7 +129,8 @@ export function slackChannel(
|
|
|
128
129
|
const credentials =
|
|
129
130
|
options.credentials ?? credentialsFromEnv(options.envPrefix);
|
|
130
131
|
const envKeys = slackEnvKeys(options.envPrefix);
|
|
131
|
-
const
|
|
132
|
+
const reply = resolveSlackReply(options);
|
|
133
|
+
const loadingMessages = reply.status.idle;
|
|
132
134
|
const policy = options.policy;
|
|
133
135
|
const blockExternals = resolveSlackBlockExternals(policy);
|
|
134
136
|
const defaultInbound = createDefaultOnInbound(loadingMessages, policy);
|
|
@@ -174,11 +176,13 @@ export function slackChannel(
|
|
|
174
176
|
events,
|
|
175
177
|
buildDefaultEvents({
|
|
176
178
|
credentials,
|
|
179
|
+
reply: options.reply,
|
|
180
|
+
toolLabels: options.toolLabels,
|
|
177
181
|
streaming: options.streaming,
|
|
178
182
|
thinkingSteps: options.thinkingSteps,
|
|
183
|
+
loadingMessages: options.loadingMessages,
|
|
179
184
|
suggestedPrompts: options.suggestedPrompts,
|
|
180
185
|
suggestedPromptsTitle: options.suggestedPromptsTitle,
|
|
181
|
-
loadingMessages,
|
|
182
186
|
getLog,
|
|
183
187
|
})
|
|
184
188
|
);
|
|
@@ -252,6 +256,7 @@ export function slackChannel(
|
|
|
252
256
|
...(channelPosts === undefined
|
|
253
257
|
? {}
|
|
254
258
|
: { slackChannelPosts: [...channelPosts.allow] }),
|
|
259
|
+
deprecations: reply.deprecations,
|
|
255
260
|
},
|
|
256
261
|
async receive(input: ReceiveInput, { send }) {
|
|
257
262
|
const target = input.target ?? {};
|