@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.
Files changed (267) hide show
  1. package/AGENTS.md +4 -2
  2. package/dist/channels/github/defaults.d.ts.map +1 -1
  3. package/dist/channels/github/defaults.js +28 -3
  4. package/dist/channels/github/progress.d.ts +7 -0
  5. package/dist/channels/github/progress.d.ts.map +1 -1
  6. package/dist/channels/slack/api.d.ts +16 -7
  7. package/dist/channels/slack/api.d.ts.map +1 -1
  8. package/dist/channels/slack/api.js +29 -13
  9. package/dist/channels/slack/constants.d.ts +6 -0
  10. package/dist/channels/slack/constants.d.ts.map +1 -1
  11. package/dist/channels/slack/constants.js +6 -0
  12. package/dist/channels/slack/defaults.d.ts +9 -4
  13. package/dist/channels/slack/defaults.d.ts.map +1 -1
  14. package/dist/channels/slack/defaults.js +154 -76
  15. package/dist/channels/slack/dispatch.d.ts.map +1 -1
  16. package/dist/channels/slack/dispatch.js +3 -3
  17. package/dist/channels/slack/inbound.d.ts +9 -0
  18. package/dist/channels/slack/inbound.d.ts.map +1 -1
  19. package/dist/channels/slack/inbound.js +14 -0
  20. package/dist/channels/slack/index.d.ts +1 -0
  21. package/dist/channels/slack/index.d.ts.map +1 -1
  22. package/dist/channels/slack/index.js +1 -0
  23. package/dist/channels/slack/live-delivery.d.ts +5 -0
  24. package/dist/channels/slack/live-delivery.d.ts.map +1 -1
  25. package/dist/channels/slack/live-delivery.js +107 -19
  26. package/dist/channels/slack/reasoning-card.d.ts +38 -0
  27. package/dist/channels/slack/reasoning-card.d.ts.map +1 -0
  28. package/dist/channels/slack/reasoning-card.js +104 -0
  29. package/dist/channels/slack/redact.d.ts +2 -0
  30. package/dist/channels/slack/redact.d.ts.map +1 -0
  31. package/dist/channels/slack/redact.js +5 -0
  32. package/dist/channels/slack/reply-options.d.ts +40 -0
  33. package/dist/channels/slack/reply-options.d.ts.map +1 -0
  34. package/dist/channels/slack/reply-options.js +150 -0
  35. package/dist/channels/slack/slack-channel.d.ts.map +1 -1
  36. package/dist/channels/slack/slack-channel.js +8 -4
  37. package/dist/channels/slack/stream.d.ts +22 -10
  38. package/dist/channels/slack/stream.d.ts.map +1 -1
  39. package/dist/channels/slack/stream.js +9 -16
  40. package/dist/channels/slack/tool-cards.d.ts +22 -0
  41. package/dist/channels/slack/tool-cards.d.ts.map +1 -0
  42. package/dist/channels/slack/tool-cards.js +178 -0
  43. package/dist/channels/slack/types.d.ts +145 -6
  44. package/dist/channels/slack/types.d.ts.map +1 -1
  45. package/dist/docs/404.html +2 -2
  46. package/dist/docs/ab.html +6 -6
  47. package/dist/docs/ab.md +1 -1
  48. package/dist/docs/assets/{ab.md.DJo5r4R-.js → ab.md.mlVgqvSk.js} +1 -1
  49. package/dist/docs/assets/{app.BplEAZ3S.js → app.DZ1e0Ycq.js} +1 -1
  50. package/dist/docs/assets/{building-with-agents.md.DI4mEzlt.js → building-with-agents.md.CUSWxlP_.js} +2 -2
  51. package/dist/docs/assets/chunks/@localSearchIndexroot.j70vvPL4.js +1 -0
  52. package/dist/docs/assets/chunks/{VPLocalSearchBox.CHXyv4wP.js → VPLocalSearchBox.l8omwc6D.js} +1 -1
  53. package/dist/docs/assets/chunks/{theme.BTcsZmjQ.js → theme.JVcD6gel.js} +2 -2
  54. package/dist/docs/assets/{evals.md.lfJoEVc8.js → evals.md.CPzDAwoH.js} +1 -1
  55. package/dist/docs/assets/{guides_github.md.Cnh2mL4a.js → guides_github.md.BtPr9GaP.js} +1 -1
  56. package/dist/docs/assets/{guides_mcp-oauth.md.CN-6YmTJ.js → guides_mcp-oauth.md.Dp6cDP7f.js} +1 -1
  57. package/dist/docs/assets/{guides_opentelemetry.md.bmPmkvJu.js → guides_opentelemetry.md.BVTXDCRg.js} +2 -2
  58. package/dist/docs/assets/{guides_slack.md.VDXQV3ja.js → guides_slack.md.9oHPye9o.js} +19 -3
  59. package/dist/docs/assets/{guides_slack.md.VDXQV3ja.lean.js → guides_slack.md.9oHPye9o.lean.js} +1 -1
  60. package/dist/docs/assets/hillclimbing.md.CpTGTCle.js +4 -0
  61. package/dist/docs/assets/{index.md.CVeRUOeZ.js → index.md.Bb4k8kUm.js} +1 -1
  62. package/dist/docs/assets/{quickstart.md.Nj_LjW_a.js → quickstart.md.DdQOF7Y8.js} +1 -1
  63. package/dist/docs/assets/{reference_connections.md.DxldvyIB.js → reference_connections.md.BiGoBAk2.js} +1 -1
  64. package/dist/docs/assets/scaffolding-agents.md.em43xlY1.js +1 -0
  65. package/dist/docs/assets/skills_ab.md.CsFNatVx.js +26 -0
  66. package/dist/docs/assets/skills_ab.md.CsFNatVx.lean.js +1 -0
  67. package/dist/docs/assets/skills_create-agent.md.BVoWPcan.js +8 -0
  68. package/dist/docs/assets/skills_create-agent.md.BVoWPcan.lean.js +1 -0
  69. package/dist/docs/assets/skills_debug.md.CDbPhHfg.js +1 -0
  70. package/dist/docs/assets/skills_debug.md.CDbPhHfg.lean.js +1 -0
  71. package/dist/docs/assets/skills_evals.md.723kpUmA.js +25 -0
  72. package/dist/docs/assets/skills_evals.md.723kpUmA.lean.js +1 -0
  73. package/dist/docs/assets/skills_framework-map.md.BTi817yv.js +1 -0
  74. package/dist/docs/assets/skills_framework-map.md.BTi817yv.lean.js +1 -0
  75. package/dist/docs/assets/skills_github.md.D0JahM8c.js +16 -0
  76. package/dist/docs/assets/skills_github.md.D0JahM8c.lean.js +1 -0
  77. package/dist/docs/assets/skills_hillclimb.md.B_zJerxA.js +7 -0
  78. package/dist/docs/assets/skills_hillclimb.md.B_zJerxA.lean.js +1 -0
  79. package/dist/docs/assets/skills_index.md.DKwIxzGg.js +1 -0
  80. package/dist/docs/assets/skills_index.md.DKwIxzGg.lean.js +1 -0
  81. package/dist/docs/assets/skills_mcp-auth.md.DGvFP3HE.js +18 -0
  82. package/dist/docs/assets/skills_mcp-auth.md.DGvFP3HE.lean.js +1 -0
  83. package/dist/docs/assets/skills_otel.md.CgiZryR3.js +8 -0
  84. package/dist/docs/assets/skills_otel.md.CgiZryR3.lean.js +1 -0
  85. package/dist/docs/assets/skills_setup-slack.md.BBgx8lUz.js +20 -0
  86. package/dist/docs/assets/skills_setup-slack.md.BBgx8lUz.lean.js +1 -0
  87. package/dist/docs/assets/{troubleshooting.md.DCiPBhYs.js → troubleshooting.md.Cus_YZga.js} +1 -1
  88. package/dist/docs/building-with-agents.html +6 -6
  89. package/dist/docs/building-with-agents.md +14 -11
  90. package/dist/docs/concepts.html +4 -4
  91. package/dist/docs/deployment.html +4 -4
  92. package/dist/docs/evals.html +6 -6
  93. package/dist/docs/evals.md +1 -1
  94. package/dist/docs/guides/agent-to-agent.html +4 -4
  95. package/dist/docs/guides/cloud-runtime.html +4 -4
  96. package/dist/docs/guides/convert-automation.html +4 -4
  97. package/dist/docs/guides/github.html +5 -5
  98. package/dist/docs/guides/github.md +1 -1
  99. package/dist/docs/guides/human-in-the-loop.html +4 -4
  100. package/dist/docs/guides/mcp-oauth.html +5 -5
  101. package/dist/docs/guides/mcp-oauth.md +1 -1
  102. package/dist/docs/guides/opentelemetry.html +7 -7
  103. package/dist/docs/guides/opentelemetry.md +2 -2
  104. package/dist/docs/guides/slack.html +22 -6
  105. package/dist/docs/guides/slack.md +80 -1
  106. package/dist/docs/guides/webhooks.html +5 -5
  107. package/dist/docs/hashmap.json +1 -1
  108. package/dist/docs/hillclimbing.html +6 -6
  109. package/dist/docs/hillclimbing.md +5 -5
  110. package/dist/docs/index.html +6 -6
  111. package/dist/docs/index.md +1 -1
  112. package/dist/docs/llms-full.txt +1041 -30
  113. package/dist/docs/llms.txt +14 -0
  114. package/dist/docs/quickstart.html +5 -5
  115. package/dist/docs/quickstart.md +1 -1
  116. package/dist/docs/reference/agent-config.html +4 -4
  117. package/dist/docs/reference/artifacts.html +4 -4
  118. package/dist/docs/reference/channels.html +4 -4
  119. package/dist/docs/reference/cli.html +4 -4
  120. package/dist/docs/reference/connections.html +6 -6
  121. package/dist/docs/reference/connections.md +1 -1
  122. package/dist/docs/reference/hooks.html +4 -4
  123. package/dist/docs/reference/http-api.html +4 -4
  124. package/dist/docs/reference/instructions.html +4 -4
  125. package/dist/docs/reference/playground.html +4 -4
  126. package/dist/docs/reference/project-layout.html +4 -4
  127. package/dist/docs/reference/prompt.html +4 -4
  128. package/dist/docs/reference/schedules.html +4 -4
  129. package/dist/docs/reference/sessions.html +4 -4
  130. package/dist/docs/reference/skills.html +4 -4
  131. package/dist/docs/reference/subagents.html +4 -4
  132. package/dist/docs/reference/tools.html +4 -4
  133. package/dist/docs/scaffolding-agents.html +5 -5
  134. package/dist/docs/scaffolding-agents.md +3 -3
  135. package/dist/docs/skills/ab.html +52 -0
  136. package/dist/docs/skills/ab.md +50 -0
  137. package/dist/docs/skills/create-agent.html +34 -0
  138. package/dist/docs/skills/create-agent.md +160 -0
  139. package/dist/docs/skills/debug.html +27 -0
  140. package/dist/docs/skills/debug.md +36 -0
  141. package/dist/docs/skills/evals.html +51 -0
  142. package/dist/docs/skills/evals.md +99 -0
  143. package/dist/docs/skills/framework-map.html +27 -0
  144. package/dist/docs/skills/framework-map.md +95 -0
  145. package/dist/docs/skills/github.html +42 -0
  146. package/dist/docs/skills/github.md +93 -0
  147. package/dist/docs/skills/hillclimb.html +33 -0
  148. package/dist/docs/skills/hillclimb.md +55 -0
  149. package/dist/docs/skills/index.html +27 -0
  150. package/dist/docs/skills/index.md +21 -0
  151. package/dist/docs/skills/mcp-auth.html +44 -0
  152. package/dist/docs/skills/mcp-auth.md +76 -0
  153. package/dist/docs/skills/otel.html +34 -0
  154. package/dist/docs/skills/otel.md +48 -0
  155. package/dist/docs/skills/setup-slack.html +46 -0
  156. package/dist/docs/skills/setup-slack.md +141 -0
  157. package/dist/docs/storage.html +4 -4
  158. package/dist/docs/templates/agentic-owners.html +4 -4
  159. package/dist/docs/templates/agents-md.html +4 -4
  160. package/dist/docs/templates/code-wiki.html +4 -4
  161. package/dist/docs/templates/demo.html +4 -4
  162. package/dist/docs/templates/pr-autofixer.html +4 -4
  163. package/dist/docs/templates/security-help.html +4 -4
  164. package/dist/docs/templates/security-reviewer.html +4 -4
  165. package/dist/docs/templates/triage.html +4 -4
  166. package/dist/docs/troubleshooting.html +5 -5
  167. package/dist/docs/troubleshooting.md +1 -1
  168. package/dist/files-backends/cursor-hosted.d.ts +6 -0
  169. package/dist/files-backends/cursor-hosted.d.ts.map +1 -1
  170. package/dist/files-backends/cursor-hosted.js +6 -9
  171. package/dist/internal/cli-deploy.js +2 -2
  172. package/dist/internal/conversation-mirror.d.ts.map +1 -1
  173. package/dist/internal/conversation-mirror.js +3 -4
  174. package/dist/internal/cursor/hosted-store-secrets.d.ts +15 -0
  175. package/dist/internal/cursor/hosted-store-secrets.d.ts.map +1 -0
  176. package/dist/internal/cursor/hosted-store-secrets.js +48 -0
  177. package/dist/internal/deploy-client.d.ts +6 -6
  178. package/dist/internal/deploy-client.js +7 -7
  179. package/dist/internal/discovery.d.ts.map +1 -1
  180. package/dist/internal/discovery.js +11 -1
  181. package/dist/internal/framework-file-storage.d.ts +12 -5
  182. package/dist/internal/framework-file-storage.d.ts.map +1 -1
  183. package/dist/internal/framework-file-storage.js +36 -5
  184. package/dist/internal/framework-storage-selection.d.ts +12 -12
  185. package/dist/internal/framework-storage-selection.d.ts.map +1 -1
  186. package/dist/internal/framework-storage-selection.js +33 -39
  187. package/dist/internal/session-run-log.d.ts +3 -3
  188. package/dist/internal/session-run-log.d.ts.map +1 -1
  189. package/dist/internal/session-run-log.js +6 -7
  190. package/dist/internal/storage-coordinator.d.ts +0 -6
  191. package/dist/internal/storage-coordinator.d.ts.map +1 -1
  192. package/dist/internal/storage-coordinator.js +1 -9
  193. package/dist/playground/assets/index-BszoQDc6.css +1 -0
  194. package/dist/playground/assets/{index-jzNbJENa.js → index-DVs98vPL.js} +1 -1
  195. package/dist/playground/index.html +2 -2
  196. package/dist/storage-backends/cursor-hosted-v2.d.ts +83 -0
  197. package/dist/storage-backends/cursor-hosted-v2.d.ts.map +1 -0
  198. package/dist/storage-backends/cursor-hosted-v2.js +164 -0
  199. package/dist/storage-backends/cursor-hosted.d.ts +6 -0
  200. package/dist/storage-backends/cursor-hosted.d.ts.map +1 -1
  201. package/dist/storage-backends/cursor-hosted.js +6 -1
  202. package/dist/types.d.ts +5 -0
  203. package/dist/types.d.ts.map +1 -1
  204. package/docs/README.md +1 -1
  205. package/docs/ab.md +1 -1
  206. package/docs/building-with-agents.md +14 -11
  207. package/docs/evals.md +1 -1
  208. package/docs/guides/github.md +1 -1
  209. package/docs/guides/mcp-oauth.md +1 -1
  210. package/docs/guides/opentelemetry.md +2 -2
  211. package/docs/guides/slack.md +80 -1
  212. package/docs/hillclimbing.md +5 -5
  213. package/docs/quickstart.md +1 -1
  214. package/docs/reference/connections.md +1 -1
  215. package/docs/scaffolding-agents.md +3 -3
  216. package/docs/skills/index.md +26 -0
  217. package/docs/troubleshooting.md +1 -1
  218. package/package.json +1 -1
  219. package/src/channels/github/defaults.ts +36 -3
  220. package/src/channels/github/progress.ts +7 -0
  221. package/src/channels/slack/api.ts +35 -17
  222. package/src/channels/slack/constants.ts +6 -0
  223. package/src/channels/slack/defaults.ts +173 -92
  224. package/src/channels/slack/dispatch.ts +8 -1
  225. package/src/channels/slack/inbound.ts +17 -0
  226. package/src/channels/slack/index.ts +1 -0
  227. package/src/channels/slack/live-delivery.ts +131 -20
  228. package/src/channels/slack/reasoning-card.ts +140 -0
  229. package/src/channels/slack/redact.ts +6 -0
  230. package/src/channels/slack/reply-options.ts +229 -0
  231. package/src/channels/slack/slack-channel.ts +7 -2
  232. package/src/channels/slack/stream.ts +31 -24
  233. package/src/channels/slack/tool-cards.ts +221 -0
  234. package/src/channels/slack/types.ts +159 -6
  235. package/src/files-backends/cursor-hosted.ts +15 -5
  236. package/src/internal/cli-deploy.ts +2 -2
  237. package/src/internal/conversation-mirror.ts +3 -8
  238. package/src/internal/cursor/hosted-store-secrets.ts +72 -0
  239. package/src/internal/deploy-client.ts +10 -10
  240. package/src/internal/discovery.ts +9 -1
  241. package/src/internal/framework-file-storage.ts +41 -5
  242. package/src/internal/framework-storage-selection.ts +31 -44
  243. package/src/internal/session-run-log.ts +6 -11
  244. package/src/internal/storage-coordinator.ts +1 -11
  245. package/src/storage-backends/cursor-hosted-v2.ts +219 -0
  246. package/src/storage-backends/cursor-hosted.ts +6 -1
  247. package/src/types.ts +5 -0
  248. package/dist/docs/assets/chunks/@localSearchIndexroot.DpuI4i7Z.js +0 -1
  249. package/dist/docs/assets/hillclimbing.md.DhESf3OO.js +0 -4
  250. package/dist/docs/assets/scaffolding-agents.md.D7UUkWw0.js +0 -1
  251. package/dist/internal/null-kv-storage.d.ts +0 -48
  252. package/dist/internal/null-kv-storage.d.ts.map +0 -1
  253. package/dist/internal/null-kv-storage.js +0 -58
  254. package/dist/playground/assets/index-D7rGZNjy.css +0 -1
  255. package/src/internal/null-kv-storage.ts +0 -74
  256. /package/dist/docs/assets/{ab.md.DJo5r4R-.lean.js → ab.md.mlVgqvSk.lean.js} +0 -0
  257. /package/dist/docs/assets/{building-with-agents.md.DI4mEzlt.lean.js → building-with-agents.md.CUSWxlP_.lean.js} +0 -0
  258. /package/dist/docs/assets/{evals.md.lfJoEVc8.lean.js → evals.md.CPzDAwoH.lean.js} +0 -0
  259. /package/dist/docs/assets/{guides_github.md.Cnh2mL4a.lean.js → guides_github.md.BtPr9GaP.lean.js} +0 -0
  260. /package/dist/docs/assets/{guides_mcp-oauth.md.CN-6YmTJ.lean.js → guides_mcp-oauth.md.Dp6cDP7f.lean.js} +0 -0
  261. /package/dist/docs/assets/{guides_opentelemetry.md.bmPmkvJu.lean.js → guides_opentelemetry.md.BVTXDCRg.lean.js} +0 -0
  262. /package/dist/docs/assets/{hillclimbing.md.DhESf3OO.lean.js → hillclimbing.md.CpTGTCle.lean.js} +0 -0
  263. /package/dist/docs/assets/{index.md.CVeRUOeZ.lean.js → index.md.Bb4k8kUm.lean.js} +0 -0
  264. /package/dist/docs/assets/{quickstart.md.Nj_LjW_a.lean.js → quickstart.md.DdQOF7Y8.lean.js} +0 -0
  265. /package/dist/docs/assets/{reference_connections.md.DxldvyIB.lean.js → reference_connections.md.BiGoBAk2.lean.js} +0 -0
  266. /package/dist/docs/assets/{scaffolding-agents.md.D7UUkWw0.lean.js → scaffolding-agents.md.em43xlY1.lean.js} +0 -0
  267. /package/dist/docs/assets/{troubleshooting.md.DCiPBhYs.lean.js → troubleshooting.md.Cus_YZga.lean.js} +0 -0
@@ -3,12 +3,7 @@
3
3
  */
4
4
 
5
5
  import type { ChannelEventContext, ChannelEventHandlers } from "../../types.js";
6
- import {
7
- appendChatStream,
8
- postMessage,
9
- setThreadStatus,
10
- truncateTypingStatus,
11
- } from "./api.js";
6
+ import { postMessage, setThreadStatus, truncateTypingStatus } from "./api.js";
12
7
  import { firstNonEmptyLine, maybeSetSuggestedPrompts } from "./assistant.js";
13
8
  import { defaultSlackAuth } from "./auth.js";
14
9
  import {
@@ -19,14 +14,20 @@ import {
19
14
  import { createStreamDeliveryStrategy } from "./live-delivery.js";
20
15
  import { defaultSlackLog, type SlackLog } from "./log.js";
21
16
  import { createProgressDelivery } from "./progress-delivery.js";
22
- import { buildTaskChunkForResult, buildTaskChunksForCalls } from "./stream.js";
17
+ import { createReasoningCard, type ReasoningCard } from "./reasoning-card.js";
18
+ import { redactSecretTokens } from "./redact.js";
19
+ import { resolveSlackReply } from "./reply-options.js";
20
+ import type { StreamTaskChunk } from "./stream.js";
21
+ import { createToolCards, type ToolCards } from "./tool-cards.js";
23
22
  import type {
24
23
  SlackAccessPolicy,
25
24
  SlackChannelState,
26
25
  SlackCredentials,
27
26
  SlackMessageHandler,
27
+ SlackReplyOptions,
28
28
  SlackRespondTo,
29
29
  SlackSuggestedPrompt,
30
+ SlackToolLabels,
30
31
  } from "./types.js";
31
32
 
32
33
  const SLACK_TURN_FAILURE_FALLBACK =
@@ -59,9 +60,8 @@ export function formatSlackTurnFailureMessage(raw: string | undefined): string {
59
60
  }
60
61
 
61
62
  function scrubSlackErrorDetail(message: string): string {
62
- const scrubbed = message
63
+ const scrubbed = redactSecretTokens(message)
63
64
  .replace(/https?:\/\/\S+/gi, "[url]")
64
- .replace(/\b(crsr_|xox[baprs]-|sk-|Bearer\s+)\S+/gi, "[redacted]")
65
65
  .replace(/\/(?:home|Users|var\/folders)\/\S+/g, "[path]")
66
66
  .replace(/\b[A-Za-z]:(?:\\|\/)[^\s]+/g, "[path]")
67
67
  .replace(/\\\\[^\s]+/g, "[path]")
@@ -126,19 +126,24 @@ export const defaultOnChannelPost: SlackMessageHandler =
126
126
 
127
127
  export interface BuildDefaultEventsOptions {
128
128
  credentials?: SlackCredentials;
129
+ /** Same shape as `slackChannel({ reply })`; see {@link SlackReplyOptions}. */
130
+ reply?: SlackReplyOptions;
131
+ /** Same as `slackChannel({ toolLabels })`. */
132
+ toolLabels?: SlackToolLabels;
133
+ /** @deprecated Use `reply`. */
129
134
  streaming?: boolean;
135
+ /** @deprecated Use `reply`. */
130
136
  thinkingSteps?: boolean;
137
+ /** @deprecated Use `reply.status.idle`. */
138
+ loadingMessages?: readonly string[];
131
139
  suggestedPrompts?: SlackSuggestedPrompt[];
132
140
  suggestedPromptsTitle?: string;
133
- /** Rotating assistant status lines; defaults to pack constants. */
134
- loadingMessages?: readonly string[];
135
141
  /** Resolved per-call so channel onStart can rebind the server logger. */
136
142
  getLog?: () => SlackLog;
137
143
  }
138
144
 
139
145
  /**
140
146
  * Build default stream-event handlers (typing, streaming, replies).
141
- * Streaming / thinking default to ON.
142
147
  *
143
148
  * Tool-approval cards are a separate primitive — compose with
144
149
  * `buildToolApprovalEvents` or set `toolApprovals: true` on `slackChannel`.
@@ -147,11 +152,17 @@ export function buildDefaultEvents(
147
152
  options: BuildDefaultEventsOptions = {}
148
153
  ): ChannelEventHandlers<SlackChannelState> {
149
154
  const credentials = options.credentials;
150
- const streaming = options.streaming !== false;
151
- const thinkingSteps = options.thinkingSteps !== false;
155
+ const reply = resolveSlackReply({
156
+ reply: options.reply,
157
+ toolLabels: options.toolLabels,
158
+ streaming: options.streaming,
159
+ thinkingSteps: options.thinkingSteps,
160
+ loadingMessages: options.loadingMessages,
161
+ });
162
+ const streaming = reply.mode === "stream";
152
163
  const suggestedPrompts = options.suggestedPrompts ?? [];
153
164
  const suggestedPromptsTitle = options.suggestedPromptsTitle;
154
- const loadingMessages = resolveLoadingMessages(options.loadingMessages);
165
+ const loadingMessages = reply.status.idle;
155
166
  const botToken = credentials?.botToken;
156
167
  const getLog = options.getLog ?? (() => defaultSlackLog);
157
168
  const strategy = createStreamDeliveryStrategy({ botToken, getLog });
@@ -160,6 +171,59 @@ export function buildDefaultEvents(
160
171
  const streamLive = (state: SlackChannelState): boolean =>
161
172
  streaming && !state.streamingUnavailable;
162
173
 
174
+ const streamTarget = (
175
+ channel: ChannelEventContext<SlackChannelState>
176
+ ): string | null => {
177
+ const channelId = channel.state.streamChannelId ?? channel.state.channelId;
178
+ if (
179
+ channelId === null ||
180
+ channelId === "" ||
181
+ channel.state.threadTs === null
182
+ ) {
183
+ return null;
184
+ }
185
+ return channelId;
186
+ };
187
+
188
+ const sendCards = async (args: {
189
+ channel: ChannelEventContext<SlackChannelState>;
190
+ sessionId: string;
191
+ chunks: StreamTaskChunk[];
192
+ }): Promise<boolean> => {
193
+ if (!streamLive(args.channel.state)) {
194
+ return false;
195
+ }
196
+ const channelId = streamTarget(args.channel);
197
+ if (channelId === null) {
198
+ return false;
199
+ }
200
+ return strategy.appendChunks({ ...args, channelId });
201
+ };
202
+
203
+ const reasoning: ReasoningCard | null =
204
+ reply.reasoningCard === false
205
+ ? null
206
+ : createReasoningCard(reply.reasoningCard, ({ chunk, ...rest }) =>
207
+ sendCards({ ...rest, chunks: [chunk] })
208
+ );
209
+ const toolCards: ToolCards | null =
210
+ reply.toolCards === false
211
+ ? null
212
+ : createToolCards(reply.toolCards, reply.toolLabel);
213
+
214
+ const completeReasoning = async (
215
+ channel: ChannelEventContext<SlackChannelState>,
216
+ sessionId: string
217
+ ): Promise<void> => {
218
+ if (reasoning?.inProgress(channel)) {
219
+ await reasoning.flush({ channel, sessionId, status: "complete" });
220
+ }
221
+ };
222
+
223
+ /** Subagent events carry `parentCallId`; cards and the reply are the parent's. */
224
+ const nested = (event: { data: { parentCallId?: string } }): boolean =>
225
+ event.data.parentCallId !== undefined;
226
+
163
227
  const clearWorkingStatus = async (
164
228
  channelId: string,
165
229
  threadTs: string
@@ -297,8 +361,11 @@ export function buildDefaultEvents(
297
361
  channel.state.lastReasoningTypingStatus = null;
298
362
  channel.state.streamTs = null;
299
363
  channel.state.streamChannelId = null;
364
+ channel.state.streamFull = false;
300
365
  channel.state.lastPostedText = null;
301
366
  channel.state.streamBlockText = null;
367
+ channel.state.reasoningCard = undefined;
368
+ channel.state.toolCardCounts = {};
302
369
  // Keep lastBotMessageTs across turns — warm delta watermark.
303
370
  channel.state.approvalMessageByCallId = {};
304
371
 
@@ -324,16 +391,16 @@ export function buildDefaultEvents(
324
391
  },
325
392
 
326
393
  async "message.appended"(event, channel) {
327
- if (!streamLive(channel.state)) {
394
+ // Nested (subagent) text is not the reply.
395
+ if (nested(event) || !streamLive(channel.state)) {
328
396
  return;
329
397
  }
330
- const channelId =
331
- channel.state.streamChannelId ?? channel.state.channelId;
332
- const threadTs = channel.state.threadTs;
333
- if (channelId === null || channelId === "" || threadTs === null) {
398
+ const channelId = streamTarget(channel);
399
+ if (channelId === null) {
334
400
  return;
335
401
  }
336
402
 
403
+ await completeReasoning(channel, event.sessionId);
337
404
  await strategy.append({
338
405
  channel,
339
406
  channelId,
@@ -343,6 +410,18 @@ export function buildDefaultEvents(
343
410
  },
344
411
 
345
412
  async "reasoning.appended"(event, channel) {
413
+ if (!nested(event)) {
414
+ await reasoning?.append({
415
+ channel,
416
+ sessionId: event.sessionId,
417
+ text: event.data.text,
418
+ });
419
+ }
420
+
421
+ // The chip is hidden while a stream is open.
422
+ if (!reply.status.reasoning || channel.state.streamTs !== null) {
423
+ return;
424
+ }
346
425
  const line = firstNonEmptyLine(event.data.text);
347
426
  if (line === undefined) {
348
427
  return;
@@ -366,113 +445,111 @@ export function buildDefaultEvents(
366
445
  if (channel.state.channelId === null || channel.state.threadTs === null) {
367
446
  return;
368
447
  }
448
+ // One entry: Slack cycles `loading_messages` every couple of seconds,
449
+ // so padding an informative line with the rotation makes the chip
450
+ // flip between the reasoning and filler until the next update.
369
451
  await setThreadStatus({
370
452
  botToken,
371
453
  channelId: channel.state.channelId,
372
454
  threadTs: channel.state.threadTs,
373
455
  status,
374
- loadingMessages: [
375
- status,
376
- ...loadingMessages.filter((message) => message !== status),
377
- ],
456
+ loadingMessages: [status],
378
457
  });
379
458
  channel.state.lastReasoningTypingAtMs = now;
380
459
  channel.state.lastReasoningTypingStatus = status;
381
460
  },
382
461
 
462
+ async "reasoning.completed"(event, channel) {
463
+ if (reasoning === null || nested(event)) {
464
+ return;
465
+ }
466
+ reasoning.endBlock(channel);
467
+ await reasoning.flush({
468
+ channel,
469
+ sessionId: event.sessionId,
470
+ status: "in_progress",
471
+ });
472
+ },
473
+
383
474
  async "actions.requested"(event, channel) {
384
475
  const pending = channel.state.pendingToolCallMessage;
385
476
  channel.state.pendingToolCallMessage = null;
386
- const names = event.data.calls.map((call) => call.toolName);
477
+ const calls = event.data.calls;
387
478
 
479
+ if (toolCards !== null && strategy.inlineToolSteps && !nested(event)) {
480
+ // Card order: the thinking that led to these tools goes first.
481
+ await reasoning?.flush({
482
+ channel,
483
+ sessionId: event.sessionId,
484
+ status: "in_progress",
485
+ });
486
+ const streamed = await sendCards({
487
+ channel,
488
+ sessionId: event.sessionId,
489
+ chunks: toolCards.forCalls(channel.state, calls),
490
+ });
491
+ // An open stream hides the chip; skip the status write.
492
+ if (streamed) {
493
+ return;
494
+ }
495
+ }
496
+
497
+ if (reply.status.tools === false) {
498
+ return;
499
+ }
388
500
  const statusText =
389
501
  pending !== null
390
502
  ? truncateTypingStatus(pending)
391
- : truncateTypingStatus(`Running ${names.join(", ")}…`);
392
-
503
+ : truncateTypingStatus(reply.status.tools(calls));
504
+ if (channel.state.channelId === null || channel.state.threadTs === null) {
505
+ return;
506
+ }
507
+ // Hold the tool line steady; see reasoning.appended.
508
+ await setThreadStatus({
509
+ botToken,
510
+ channelId: channel.state.channelId,
511
+ threadTs: channel.state.threadTs,
512
+ status: statusText,
513
+ loadingMessages: [statusText],
514
+ });
393
515
  if (
394
- strategy.inlineToolSteps &&
395
- thinkingSteps &&
396
- streamLive(channel.state)
516
+ toolCards !== null &&
517
+ channel.state.streamingUnavailable === true &&
518
+ (channel.state.streamTs === null || channel.state.streamTs === "")
397
519
  ) {
398
- const channelId =
399
- channel.state.streamChannelId ?? channel.state.channelId;
400
- const threadTs = channel.state.threadTs;
401
- if (channelId !== null && channelId !== "" && threadTs !== null) {
402
- const chunks = buildTaskChunksForCalls(
403
- event.data.calls,
404
- "in_progress"
405
- );
406
- const streamed = await strategy.appendChunks({
407
- channel,
408
- channelId,
409
- chunks,
410
- sessionId: event.sessionId,
411
- });
412
- if (streamed) {
413
- if (
414
- channel.state.channelId !== null &&
415
- channel.state.threadTs !== null
416
- ) {
417
- await setThreadStatus({
418
- botToken,
419
- channelId: channel.state.channelId,
420
- threadTs: channel.state.threadTs,
421
- status: statusText,
422
- });
423
- }
424
- return;
425
- }
426
- }
427
- }
428
-
429
- if (channel.state.channelId !== null && channel.state.threadTs !== null) {
430
- await setThreadStatus({
431
- botToken,
432
- channelId: channel.state.channelId,
433
- threadTs: channel.state.threadTs,
434
- status: statusText,
435
- });
436
- if (
437
- thinkingSteps &&
438
- channel.state.streamingUnavailable === true &&
439
- (channel.state.streamTs === null || channel.state.streamTs === "")
440
- ) {
441
- await progress.upsert({ channel, text: statusText });
442
- }
520
+ await progress.upsert({ channel, text: statusText });
443
521
  }
444
522
  },
445
523
 
446
524
  async "action.result"(event, channel) {
447
525
  const streamTs = channel.state.streamTs;
448
526
  if (
527
+ toolCards === null ||
449
528
  !strategy.inlineToolSteps ||
450
- !thinkingSteps ||
451
- !streamLive(channel.state) ||
529
+ nested(event) ||
452
530
  streamTs === null ||
453
531
  streamTs === ""
454
532
  ) {
455
533
  return;
456
534
  }
457
- const channelId =
458
- channel.state.streamChannelId ?? channel.state.channelId;
459
- if (channelId === null || channelId === "") {
460
- return;
461
- }
462
- const chunk = buildTaskChunkForResult({
463
- callId: event.data.callId,
464
- toolName: event.data.toolName,
465
- isError: event.data.isError,
466
- });
467
- await appendChatStream({
468
- botToken,
469
- channel: channelId,
470
- ts: streamTs,
471
- chunks: [chunk],
535
+ await sendCards({
536
+ channel,
537
+ sessionId: event.sessionId,
538
+ chunks: [
539
+ toolCards.forResult(channel.state, {
540
+ callId: event.data.callId,
541
+ toolName: event.data.toolName,
542
+ output: event.data.output,
543
+ isError: event.data.isError,
544
+ }),
545
+ ],
472
546
  });
473
547
  },
474
548
 
475
549
  async "message.completed"(event, channel) {
550
+ if (nested(event)) {
551
+ return;
552
+ }
476
553
  if (event.data.finishReason === "tool_call") {
477
554
  channel.state.pendingToolCallMessage =
478
555
  firstNonEmptyLine(event.data.text) ?? null;
@@ -488,6 +565,8 @@ export function buildDefaultEvents(
488
565
  return;
489
566
  }
490
567
 
568
+ await completeReasoning(channel, event.sessionId);
569
+
491
570
  // Empty final text: still close any open stream / clear the skeleton
492
571
  // and clear typing.
493
572
  if (event.data.text === "") {
@@ -523,6 +602,7 @@ export function buildDefaultEvents(
523
602
  typeof result === "string" &&
524
603
  result !== "" &&
525
604
  result !== channel.state.lastPostedText;
605
+ await completeReasoning(channel, event.sessionId);
526
606
  if (unpublished) {
527
607
  await deliverReplyText({
528
608
  channel,
@@ -582,6 +662,7 @@ export function buildDefaultEvents(
582
662
 
583
663
  let delivered = false;
584
664
  if (streamLive(state)) {
665
+ await completeReasoning(channel, event.sessionId);
585
666
  ({ delivered } = await strategy.fail({
586
667
  channel,
587
668
  channelId: state.streamChannelId ?? state.channelId,
@@ -36,6 +36,7 @@ import {
36
36
  import type { EventIdDedupe } from "./event-id-dedupe.js";
37
37
  import { isExternalSlackSender } from "./external-policy.js";
38
38
  import {
39
+ describeSlackEventShape,
39
40
  formatSlackContextBlock,
40
41
  parseAppMentionEvent,
41
42
  parseAssistantThreadStarted,
@@ -129,8 +130,11 @@ export function emptySlackChannelState(
129
130
  streamBlockText: null,
130
131
  lastBotMessageTs: null,
131
132
  streamingUnavailable: false,
133
+ streamFull: false,
132
134
  progressTs: null,
133
135
  approvalMessageByCallId: {},
136
+ reasoningCard: undefined,
137
+ toolCardCounts: {},
134
138
  ...patch,
135
139
  };
136
140
  }
@@ -797,6 +801,9 @@ export function dispatchInboundFromEventBody(
797
801
  }
798
802
  }
799
803
 
800
- log.debug("inbound ignored (unhandled event shape)", { event_id: eventId });
804
+ log.debug("inbound ignored (unhandled event shape)", {
805
+ ...describeSlackEventShape(body),
806
+ event_id: eventId,
807
+ });
801
808
  return false;
802
809
  }
@@ -20,6 +20,23 @@ function asString(value: unknown): string | undefined {
20
20
  return typeof value === "string" ? value : undefined;
21
21
  }
22
22
 
23
+ /**
24
+ * `type` / `subtype` of an Events API body's inner event, for log lines about
25
+ * payloads no parser claimed (own-bot echoes, `message_changed`, pane
26
+ * context changes). Never throws on odd shapes.
27
+ */
28
+ export function describeSlackEventShape(body: unknown): {
29
+ event_type: string;
30
+ event_subtype?: string;
31
+ } {
32
+ const root = asRecord(body);
33
+ const event = asRecord(root?.event);
34
+ return {
35
+ event_type: asString(event?.type) ?? asString(root?.type) ?? "unknown",
36
+ event_subtype: asString(event?.subtype),
37
+ };
38
+ }
39
+
23
40
  /** Strip common Slack mention tokens for a cleaner model prompt. */
24
41
  export function slackTextToMarkdown(text: string): string {
25
42
  return text
@@ -46,4 +46,5 @@ export * from "./stop.js";
46
46
  export * from "./stream.js";
47
47
  export * from "./thread-context.js";
48
48
  export * from "./tool-approval-events.js";
49
+ export { defaultToolCardDetails } from "./tool-cards.js";
49
50
  export * from "./types.js";