@cursor/july 0.1.97 → 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 +5 -3
- package/dist/bin/agent-serve.js +6 -7
- package/dist/channels/github/defaults.d.ts.map +1 -1
- package/dist/channels/github/defaults.js +28 -3
- package/dist/channels/github/github-channel.d.ts.map +1 -1
- package/dist/channels/github/github-channel.js +16 -0
- package/dist/channels/github/progress.d.ts +7 -0
- package/dist/channels/github/progress.d.ts.map +1 -1
- package/dist/channels/origin/origin-channel.d.ts +2 -0
- package/dist/channels/origin/origin-channel.d.ts.map +1 -1
- package/dist/channels/origin/origin-channel.js +37 -4
- 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 +221 -122
- 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 +6 -1
- package/dist/channels/slack/live-delivery.d.ts.map +1 -1
- package/dist/channels/slack/live-delivery.js +110 -20
- package/dist/channels/slack/progress-delivery.d.ts +28 -0
- package/dist/channels/slack/progress-delivery.d.ts.map +1 -0
- package/dist/channels/slack/progress-delivery.js +115 -0
- 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 +154 -7
- 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.B3rWNYE1.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.C1lhqJJR.js → VPLocalSearchBox.l8omwc6D.js} +1 -1
- package/dist/docs/assets/chunks/{theme.B40_SXuv.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_cli.md.RyZf5OTE.js → reference_cli.md.DfoeyvL0.js} +4 -4
- package/dist/docs/assets/{reference_cli.md.RyZf5OTE.lean.js → reference_cli.md.DfoeyvL0.lean.js} +1 -1
- package/dist/docs/assets/{reference_connections.md.DxldvyIB.js → reference_connections.md.BiGoBAk2.js} +1 -1
- package/dist/docs/assets/{reference_http-api.md.5zOAbV86.js → reference_http-api.md.BEJx9XVj.js} +1 -1
- package/dist/docs/assets/{reference_tools.md.B84gw9Ii.js → reference_tools.md.CvAHsdSp.js} +10 -2
- package/dist/docs/assets/{reference_tools.md.B84gw9Ii.lean.js → reference_tools.md.CvAHsdSp.lean.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/design/runtime-abstraction.md +1757 -0
- 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 +2830 -37
- package/dist/docs/llms.txt +15 -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 +7 -7
- package/dist/docs/reference/cli.md +1 -7
- 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 +6 -6
- package/dist/docs/reference/http-api.md +1 -0
- 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 +14 -6
- package/dist/docs/reference/tools.md +25 -0
- 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 +9 -2
- package/dist/files-backends/cursor-hosted.d.ts.map +1 -1
- package/dist/files-backends/cursor-hosted.js +9 -11
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/internal/as-of.d.ts +19 -0
- package/dist/internal/as-of.d.ts.map +1 -0
- package/dist/internal/as-of.js +82 -0
- package/dist/internal/cli-deploy.d.ts +2 -1
- package/dist/internal/cli-deploy.d.ts.map +1 -1
- package/dist/internal/cli-deploy.js +102 -7
- 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/cursor-event-relay.d.ts.map +1 -1
- package/dist/internal/cursor-event-relay.js +5 -6
- 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 +5 -4
- package/dist/internal/framework-file-storage.d.ts.map +1 -1
- package/dist/internal/framework-file-storage.js +6 -4
- package/dist/internal/framework-storage-selection.d.ts +13 -11
- package/dist/internal/framework-storage-selection.d.ts.map +1 -1
- package/dist/internal/framework-storage-selection.js +28 -23
- package/dist/internal/hosted-admission-adapter.d.ts +28 -0
- package/dist/internal/hosted-admission-adapter.d.ts.map +1 -0
- package/dist/internal/hosted-admission-adapter.js +7 -0
- package/dist/internal/hosted-delivery-protocol.d.ts +6 -1
- package/dist/internal/hosted-delivery-protocol.d.ts.map +1 -1
- package/dist/internal/hosted-delivery-protocol.js +1 -1
- package/dist/internal/hosted-delivery.d.ts +15 -1
- package/dist/internal/hosted-delivery.d.ts.map +1 -1
- package/dist/internal/hosted-delivery.js +47 -21
- package/dist/internal/hosted-execution-diag.d.ts +11 -0
- package/dist/internal/hosted-execution-diag.d.ts.map +1 -1
- package/dist/internal/hosted-execution-diag.js +39 -2
- package/dist/internal/http-channel.d.ts.map +1 -1
- package/dist/internal/http-channel.js +4 -1
- package/dist/internal/server.d.ts +3 -0
- package/dist/internal/server.d.ts.map +1 -1
- package/dist/internal/server.js +82 -19
- package/dist/internal/session-engine.d.ts.map +1 -1
- package/dist/internal/session-engine.js +24 -4
- package/dist/internal/session-run-log.d.ts +120 -0
- package/dist/internal/session-run-log.d.ts.map +1 -0
- package/dist/internal/session-run-log.js +358 -0
- package/dist/internal/tool-policy.d.ts +20 -8
- package/dist/internal/tool-policy.d.ts.map +1 -1
- package/dist/internal/tool-policy.js +11 -0
- package/dist/playground/assets/index-BszoQDc6.css +1 -0
- package/dist/playground/assets/index-DVs98vPL.js +69 -0
- 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/storage-protocol.d.ts +8 -0
- package/dist/storage-protocol.d.ts.map +1 -1
- package/dist/storage-protocol.js +8 -0
- package/dist/tools.d.ts +12 -2
- package/dist/tools.d.ts.map +1 -1
- package/dist/types.d.ts +30 -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/design/runtime-abstraction.md +1757 -0
- 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/cli.md +1 -7
- package/docs/reference/connections.md +1 -1
- package/docs/reference/http-api.md +1 -0
- package/docs/reference/tools.md +25 -0
- 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/bin/agent-serve.ts +6 -7
- package/src/channels/github/defaults.ts +36 -3
- package/src/channels/github/github-channel.ts +17 -0
- package/src/channels/github/progress.ts +7 -0
- package/src/channels/origin/origin-channel.ts +74 -10
- package/src/channels/slack/api.ts +35 -17
- package/src/channels/slack/constants.ts +6 -0
- package/src/channels/slack/defaults.ts +253 -144
- package/src/channels/slack/dispatch.ts +10 -1
- package/src/channels/slack/inbound.ts +17 -0
- package/src/channels/slack/index.ts +1 -0
- package/src/channels/slack/live-delivery.ts +135 -22
- package/src/channels/slack/progress-delivery.ts +133 -0
- 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 +168 -7
- package/src/files-backends/cursor-hosted.ts +18 -7
- package/src/index.ts +4 -0
- package/src/internal/as-of.ts +107 -0
- package/src/internal/cli-deploy.ts +130 -10
- package/src/internal/conversation-mirror.ts +3 -8
- package/src/internal/cursor/hosted-store-secrets.ts +72 -0
- package/src/internal/cursor-event-relay.ts +5 -6
- package/src/internal/deploy-client.ts +10 -10
- package/src/internal/discovery.ts +9 -1
- package/src/internal/framework-file-storage.ts +6 -4
- package/src/internal/framework-storage-selection.ts +28 -25
- package/src/internal/hosted-admission-adapter.ts +42 -0
- package/src/internal/hosted-delivery-protocol.ts +7 -2
- package/src/internal/hosted-delivery.ts +88 -36
- package/src/internal/hosted-execution-diag.ts +45 -0
- package/src/internal/http-channel.ts +8 -0
- package/src/internal/server.ts +100 -2
- package/src/internal/session-engine.ts +32 -1
- package/src/internal/session-run-log.ts +579 -0
- package/src/internal/tool-policy.ts +31 -9
- package/src/storage-backends/cursor-hosted-v2.ts +219 -0
- package/src/storage-backends/cursor-hosted.ts +6 -1
- package/src/storage-protocol.ts +10 -0
- package/src/tools.ts +12 -2
- package/src/types.ts +30 -0
- package/dist/docs/assets/chunks/@localSearchIndexroot.BU9nHdnQ.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/playground/assets/index-DrkI6y5O.js +0 -88
- package/dist/playground/assets/index-DzNGwm7q.css +0 -1
- /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/{reference_http-api.md.5zOAbV86.lean.js → reference_http-api.md.BEJx9XVj.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
|
@@ -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 {
|
|
@@ -18,14 +13,21 @@ import {
|
|
|
18
13
|
} from "./constants.js";
|
|
19
14
|
import { createStreamDeliveryStrategy } from "./live-delivery.js";
|
|
20
15
|
import { defaultSlackLog, type SlackLog } from "./log.js";
|
|
21
|
-
import {
|
|
16
|
+
import { createProgressDelivery } from "./progress-delivery.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";
|
|
22
22
|
import type {
|
|
23
23
|
SlackAccessPolicy,
|
|
24
24
|
SlackChannelState,
|
|
25
25
|
SlackCredentials,
|
|
26
26
|
SlackMessageHandler,
|
|
27
|
+
SlackReplyOptions,
|
|
27
28
|
SlackRespondTo,
|
|
28
29
|
SlackSuggestedPrompt,
|
|
30
|
+
SlackToolLabels,
|
|
29
31
|
} from "./types.js";
|
|
30
32
|
|
|
31
33
|
const SLACK_TURN_FAILURE_FALLBACK =
|
|
@@ -58,9 +60,8 @@ export function formatSlackTurnFailureMessage(raw: string | undefined): string {
|
|
|
58
60
|
}
|
|
59
61
|
|
|
60
62
|
function scrubSlackErrorDetail(message: string): string {
|
|
61
|
-
const scrubbed = message
|
|
63
|
+
const scrubbed = redactSecretTokens(message)
|
|
62
64
|
.replace(/https?:\/\/\S+/gi, "[url]")
|
|
63
|
-
.replace(/\b(crsr_|xox[baprs]-|sk-|Bearer\s+)\S+/gi, "[redacted]")
|
|
64
65
|
.replace(/\/(?:home|Users|var\/folders)\/\S+/g, "[path]")
|
|
65
66
|
.replace(/\b[A-Za-z]:(?:\\|\/)[^\s]+/g, "[path]")
|
|
66
67
|
.replace(/\\\\[^\s]+/g, "[path]")
|
|
@@ -125,19 +126,24 @@ export const defaultOnChannelPost: SlackMessageHandler =
|
|
|
125
126
|
|
|
126
127
|
export interface BuildDefaultEventsOptions {
|
|
127
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`. */
|
|
128
134
|
streaming?: boolean;
|
|
135
|
+
/** @deprecated Use `reply`. */
|
|
129
136
|
thinkingSteps?: boolean;
|
|
137
|
+
/** @deprecated Use `reply.status.idle`. */
|
|
138
|
+
loadingMessages?: readonly string[];
|
|
130
139
|
suggestedPrompts?: SlackSuggestedPrompt[];
|
|
131
140
|
suggestedPromptsTitle?: string;
|
|
132
|
-
/** Rotating assistant status lines; defaults to pack constants. */
|
|
133
|
-
loadingMessages?: readonly string[];
|
|
134
141
|
/** Resolved per-call so channel onStart can rebind the server logger. */
|
|
135
142
|
getLog?: () => SlackLog;
|
|
136
143
|
}
|
|
137
144
|
|
|
138
145
|
/**
|
|
139
146
|
* Build default stream-event handlers (typing, streaming, replies).
|
|
140
|
-
* Streaming / thinking default to ON.
|
|
141
147
|
*
|
|
142
148
|
* Tool-approval cards are a separate primitive — compose with
|
|
143
149
|
* `buildToolApprovalEvents` or set `toolApprovals: true` on `slackChannel`.
|
|
@@ -146,14 +152,77 @@ export function buildDefaultEvents(
|
|
|
146
152
|
options: BuildDefaultEventsOptions = {}
|
|
147
153
|
): ChannelEventHandlers<SlackChannelState> {
|
|
148
154
|
const credentials = options.credentials;
|
|
149
|
-
const
|
|
150
|
-
|
|
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";
|
|
151
163
|
const suggestedPrompts = options.suggestedPrompts ?? [];
|
|
152
164
|
const suggestedPromptsTitle = options.suggestedPromptsTitle;
|
|
153
|
-
const loadingMessages =
|
|
165
|
+
const loadingMessages = reply.status.idle;
|
|
154
166
|
const botToken = credentials?.botToken;
|
|
155
167
|
const getLog = options.getLog ?? (() => defaultSlackLog);
|
|
156
168
|
const strategy = createStreamDeliveryStrategy({ botToken, getLog });
|
|
169
|
+
const progress = createProgressDelivery({ botToken, getLog });
|
|
170
|
+
|
|
171
|
+
const streamLive = (state: SlackChannelState): boolean =>
|
|
172
|
+
streaming && !state.streamingUnavailable;
|
|
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;
|
|
157
226
|
|
|
158
227
|
const clearWorkingStatus = async (
|
|
159
228
|
channelId: string,
|
|
@@ -174,6 +243,62 @@ export function buildDefaultEvents(
|
|
|
174
243
|
}
|
|
175
244
|
};
|
|
176
245
|
|
|
246
|
+
const finishProgress = async (args: {
|
|
247
|
+
channel: ChannelEventContext<SlackChannelState>;
|
|
248
|
+
text: string;
|
|
249
|
+
sessionId: string;
|
|
250
|
+
}): Promise<boolean> => {
|
|
251
|
+
const log = getLog();
|
|
252
|
+
const state = args.channel.state;
|
|
253
|
+
if (
|
|
254
|
+
state.channelId === null ||
|
|
255
|
+
state.threadTs === null ||
|
|
256
|
+
args.text === ""
|
|
257
|
+
) {
|
|
258
|
+
return false;
|
|
259
|
+
}
|
|
260
|
+
if (await progress.replace({ channel: args.channel, text: args.text })) {
|
|
261
|
+
log.info("reply delivered via progress update", {
|
|
262
|
+
channel: state.channelId,
|
|
263
|
+
thread_ts: state.threadTs,
|
|
264
|
+
session: args.sessionId,
|
|
265
|
+
chars: args.text.length,
|
|
266
|
+
});
|
|
267
|
+
return true;
|
|
268
|
+
}
|
|
269
|
+
await progress.clear({ channel: args.channel });
|
|
270
|
+
try {
|
|
271
|
+
const posted = await postMessage({
|
|
272
|
+
botToken,
|
|
273
|
+
channel: state.channelId,
|
|
274
|
+
text: args.text,
|
|
275
|
+
threadTs: state.threadTs,
|
|
276
|
+
});
|
|
277
|
+
state.lastPostedText = args.text;
|
|
278
|
+
state.lastBotMessageTs = posted.ts;
|
|
279
|
+
log.info("reply delivered via postMessage", {
|
|
280
|
+
channel: state.channelId,
|
|
281
|
+
thread_ts: state.threadTs,
|
|
282
|
+
message_ts: posted.ts,
|
|
283
|
+
session: args.sessionId,
|
|
284
|
+
chars: args.text.length,
|
|
285
|
+
});
|
|
286
|
+
return true;
|
|
287
|
+
} catch (error) {
|
|
288
|
+
log.error(
|
|
289
|
+
`postMessage failed: ${
|
|
290
|
+
error instanceof Error ? error.message : String(error)
|
|
291
|
+
}`,
|
|
292
|
+
{
|
|
293
|
+
channel: state.channelId,
|
|
294
|
+
thread_ts: state.threadTs,
|
|
295
|
+
session: args.sessionId,
|
|
296
|
+
}
|
|
297
|
+
);
|
|
298
|
+
return false;
|
|
299
|
+
}
|
|
300
|
+
};
|
|
301
|
+
|
|
177
302
|
/**
|
|
178
303
|
* Deliver assistant text to the bound Slack thread. Used by a stop-reason
|
|
179
304
|
* `message.completed` and by `turn.completed` when the last assistant
|
|
@@ -185,7 +310,6 @@ export function buildDefaultEvents(
|
|
|
185
310
|
text: string;
|
|
186
311
|
sessionId: string;
|
|
187
312
|
}): Promise<boolean> => {
|
|
188
|
-
const log = getLog();
|
|
189
313
|
const state = args.channel.state;
|
|
190
314
|
if (
|
|
191
315
|
state.channelId === null ||
|
|
@@ -199,8 +323,7 @@ export function buildDefaultEvents(
|
|
|
199
323
|
// pending. Treat a match as "already on Slack", not "already finalized".
|
|
200
324
|
const streamTs = state.streamTs;
|
|
201
325
|
if (streamTs !== null && streamTs !== "") {
|
|
202
|
-
|
|
203
|
-
if (canStream) {
|
|
326
|
+
if (streamLive(state)) {
|
|
204
327
|
await strategy.finalize({
|
|
205
328
|
channel: args.channel,
|
|
206
329
|
channelId: state.streamChannelId ?? state.channelId,
|
|
@@ -214,8 +337,7 @@ export function buildDefaultEvents(
|
|
|
214
337
|
return true;
|
|
215
338
|
}
|
|
216
339
|
|
|
217
|
-
|
|
218
|
-
if (canStream) {
|
|
340
|
+
if (streamLive(state)) {
|
|
219
341
|
const { delivered } = await strategy.finalize({
|
|
220
342
|
channel: args.channel,
|
|
221
343
|
channelId: state.streamChannelId ?? state.channelId,
|
|
@@ -227,47 +349,23 @@ export function buildDefaultEvents(
|
|
|
227
349
|
}
|
|
228
350
|
}
|
|
229
351
|
|
|
230
|
-
|
|
231
|
-
const posted = await postMessage({
|
|
232
|
-
botToken,
|
|
233
|
-
channel: state.channelId,
|
|
234
|
-
text: args.text,
|
|
235
|
-
threadTs: state.threadTs,
|
|
236
|
-
});
|
|
237
|
-
state.lastPostedText = args.text;
|
|
238
|
-
state.lastBotMessageTs = posted.ts;
|
|
239
|
-
log.info("reply delivered via postMessage", {
|
|
240
|
-
channel: state.channelId,
|
|
241
|
-
thread_ts: state.threadTs,
|
|
242
|
-
message_ts: posted.ts,
|
|
243
|
-
session: args.sessionId,
|
|
244
|
-
chars: args.text.length,
|
|
245
|
-
});
|
|
246
|
-
return true;
|
|
247
|
-
} catch (error) {
|
|
248
|
-
log.error(
|
|
249
|
-
`postMessage failed: ${
|
|
250
|
-
error instanceof Error ? error.message : String(error)
|
|
251
|
-
}`,
|
|
252
|
-
{
|
|
253
|
-
channel: state.channelId,
|
|
254
|
-
thread_ts: state.threadTs,
|
|
255
|
-
session: args.sessionId,
|
|
256
|
-
}
|
|
257
|
-
);
|
|
258
|
-
return false;
|
|
259
|
-
}
|
|
352
|
+
return finishProgress(args);
|
|
260
353
|
};
|
|
261
354
|
|
|
262
355
|
return {
|
|
263
356
|
async "turn.started"(event, channel) {
|
|
264
357
|
const log = getLog();
|
|
358
|
+
await progress.clear({ channel });
|
|
265
359
|
channel.state.pendingToolCallMessage = null;
|
|
266
360
|
channel.state.lastReasoningTypingAtMs = null;
|
|
267
361
|
channel.state.lastReasoningTypingStatus = null;
|
|
268
362
|
channel.state.streamTs = null;
|
|
269
363
|
channel.state.streamChannelId = null;
|
|
364
|
+
channel.state.streamFull = false;
|
|
270
365
|
channel.state.lastPostedText = null;
|
|
366
|
+
channel.state.streamBlockText = null;
|
|
367
|
+
channel.state.reasoningCard = undefined;
|
|
368
|
+
channel.state.toolCardCounts = {};
|
|
271
369
|
// Keep lastBotMessageTs across turns — warm delta watermark.
|
|
272
370
|
channel.state.approvalMessageByCallId = {};
|
|
273
371
|
|
|
@@ -293,16 +391,16 @@ export function buildDefaultEvents(
|
|
|
293
391
|
},
|
|
294
392
|
|
|
295
393
|
async "message.appended"(event, channel) {
|
|
296
|
-
|
|
394
|
+
// Nested (subagent) text is not the reply.
|
|
395
|
+
if (nested(event) || !streamLive(channel.state)) {
|
|
297
396
|
return;
|
|
298
397
|
}
|
|
299
|
-
const channelId =
|
|
300
|
-
|
|
301
|
-
const threadTs = channel.state.threadTs;
|
|
302
|
-
if (channelId === null || channelId === "" || threadTs === null) {
|
|
398
|
+
const channelId = streamTarget(channel);
|
|
399
|
+
if (channelId === null) {
|
|
303
400
|
return;
|
|
304
401
|
}
|
|
305
402
|
|
|
403
|
+
await completeReasoning(channel, event.sessionId);
|
|
306
404
|
await strategy.append({
|
|
307
405
|
channel,
|
|
308
406
|
channelId,
|
|
@@ -312,6 +410,18 @@ export function buildDefaultEvents(
|
|
|
312
410
|
},
|
|
313
411
|
|
|
314
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
|
+
}
|
|
315
425
|
const line = firstNonEmptyLine(event.data.text);
|
|
316
426
|
if (line === undefined) {
|
|
317
427
|
return;
|
|
@@ -335,110 +445,117 @@ export function buildDefaultEvents(
|
|
|
335
445
|
if (channel.state.channelId === null || channel.state.threadTs === null) {
|
|
336
446
|
return;
|
|
337
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.
|
|
338
451
|
await setThreadStatus({
|
|
339
452
|
botToken,
|
|
340
453
|
channelId: channel.state.channelId,
|
|
341
454
|
threadTs: channel.state.threadTs,
|
|
342
455
|
status,
|
|
343
|
-
loadingMessages: [
|
|
344
|
-
status,
|
|
345
|
-
...loadingMessages.filter((message) => message !== status),
|
|
346
|
-
],
|
|
456
|
+
loadingMessages: [status],
|
|
347
457
|
});
|
|
348
458
|
channel.state.lastReasoningTypingAtMs = now;
|
|
349
459
|
channel.state.lastReasoningTypingStatus = status;
|
|
350
460
|
},
|
|
351
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
|
+
|
|
352
474
|
async "actions.requested"(event, channel) {
|
|
353
475
|
const pending = channel.state.pendingToolCallMessage;
|
|
354
476
|
channel.state.pendingToolCallMessage = null;
|
|
355
|
-
const
|
|
477
|
+
const calls = event.data.calls;
|
|
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
|
+
}
|
|
356
496
|
|
|
497
|
+
if (reply.status.tools === false) {
|
|
498
|
+
return;
|
|
499
|
+
}
|
|
357
500
|
const statusText =
|
|
358
501
|
pending !== null
|
|
359
502
|
? truncateTypingStatus(pending)
|
|
360
|
-
: truncateTypingStatus(
|
|
361
|
-
|
|
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
|
+
});
|
|
362
515
|
if (
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
channel.state.streamingUnavailable !== true
|
|
516
|
+
toolCards !== null &&
|
|
517
|
+
channel.state.streamingUnavailable === true &&
|
|
518
|
+
(channel.state.streamTs === null || channel.state.streamTs === "")
|
|
367
519
|
) {
|
|
368
|
-
|
|
369
|
-
channel.state.streamChannelId ?? channel.state.channelId;
|
|
370
|
-
const threadTs = channel.state.threadTs;
|
|
371
|
-
if (channelId !== null && channelId !== "" && threadTs !== null) {
|
|
372
|
-
const chunks = buildTaskChunksForCalls(
|
|
373
|
-
event.data.calls,
|
|
374
|
-
"in_progress"
|
|
375
|
-
);
|
|
376
|
-
const streamed = await strategy.appendChunks({
|
|
377
|
-
channel,
|
|
378
|
-
channelId,
|
|
379
|
-
chunks,
|
|
380
|
-
sessionId: event.sessionId,
|
|
381
|
-
});
|
|
382
|
-
if (streamed) {
|
|
383
|
-
if (
|
|
384
|
-
channel.state.channelId !== null &&
|
|
385
|
-
channel.state.threadTs !== null
|
|
386
|
-
) {
|
|
387
|
-
await setThreadStatus({
|
|
388
|
-
botToken,
|
|
389
|
-
channelId: channel.state.channelId,
|
|
390
|
-
threadTs: channel.state.threadTs,
|
|
391
|
-
status: statusText,
|
|
392
|
-
});
|
|
393
|
-
}
|
|
394
|
-
return;
|
|
395
|
-
}
|
|
396
|
-
}
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
if (channel.state.channelId !== null && channel.state.threadTs !== null) {
|
|
400
|
-
await setThreadStatus({
|
|
401
|
-
botToken,
|
|
402
|
-
channelId: channel.state.channelId,
|
|
403
|
-
threadTs: channel.state.threadTs,
|
|
404
|
-
status: statusText,
|
|
405
|
-
});
|
|
520
|
+
await progress.upsert({ channel, text: statusText });
|
|
406
521
|
}
|
|
407
522
|
},
|
|
408
523
|
|
|
409
524
|
async "action.result"(event, channel) {
|
|
525
|
+
const streamTs = channel.state.streamTs;
|
|
410
526
|
if (
|
|
527
|
+
toolCards === null ||
|
|
411
528
|
!strategy.inlineToolSteps ||
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
channel.state.streamTs === null ||
|
|
416
|
-
channel.state.streamTs === ""
|
|
529
|
+
nested(event) ||
|
|
530
|
+
streamTs === null ||
|
|
531
|
+
streamTs === ""
|
|
417
532
|
) {
|
|
418
533
|
return;
|
|
419
534
|
}
|
|
420
|
-
|
|
421
|
-
channel
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
botToken,
|
|
432
|
-
channel: channelId,
|
|
433
|
-
ts: channel.state.streamTs,
|
|
434
|
-
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
|
+
],
|
|
435
546
|
});
|
|
436
547
|
},
|
|
437
548
|
|
|
438
549
|
async "message.completed"(event, channel) {
|
|
550
|
+
if (nested(event)) {
|
|
551
|
+
return;
|
|
552
|
+
}
|
|
439
553
|
if (event.data.finishReason === "tool_call") {
|
|
440
554
|
channel.state.pendingToolCallMessage =
|
|
441
555
|
firstNonEmptyLine(event.data.text) ?? null;
|
|
556
|
+
// The harness restarts its cumulative text after a tool call, so the
|
|
557
|
+
// next block appends in full instead of diffing against this one.
|
|
558
|
+
channel.state.streamBlockText = null;
|
|
442
559
|
return;
|
|
443
560
|
}
|
|
444
561
|
channel.state.pendingToolCallMessage = null;
|
|
@@ -448,10 +565,13 @@ export function buildDefaultEvents(
|
|
|
448
565
|
return;
|
|
449
566
|
}
|
|
450
567
|
|
|
568
|
+
await completeReasoning(channel, event.sessionId);
|
|
569
|
+
|
|
451
570
|
// Empty final text: still close any open stream / clear the skeleton
|
|
452
571
|
// and clear typing.
|
|
453
572
|
if (event.data.text === "") {
|
|
454
573
|
await strategy.finalizeEmpty({ channel });
|
|
574
|
+
await progress.clear({ channel });
|
|
455
575
|
await clearWorkingStatus(state.channelId, state.threadTs);
|
|
456
576
|
return;
|
|
457
577
|
}
|
|
@@ -482,6 +602,7 @@ export function buildDefaultEvents(
|
|
|
482
602
|
typeof result === "string" &&
|
|
483
603
|
result !== "" &&
|
|
484
604
|
result !== channel.state.lastPostedText;
|
|
605
|
+
await completeReasoning(channel, event.sessionId);
|
|
485
606
|
if (unpublished) {
|
|
486
607
|
await deliverReplyText({
|
|
487
608
|
channel,
|
|
@@ -492,6 +613,7 @@ export function buildDefaultEvents(
|
|
|
492
613
|
// Always close leftovers. deliverReplyText may fall through to
|
|
493
614
|
// postMessage when streaming is unavailable and leave streamTs open.
|
|
494
615
|
await strategy.cleanupOrphan({ channel });
|
|
616
|
+
await progress.clear({ channel });
|
|
495
617
|
|
|
496
618
|
// Always drop the assistant chip. message.completed already clears
|
|
497
619
|
// after a normal reply, but a tool-call-only finish (or a missed
|
|
@@ -539,7 +661,8 @@ export function buildDefaultEvents(
|
|
|
539
661
|
const errorText = formatSlackTurnFailureMessage(event.data.message);
|
|
540
662
|
|
|
541
663
|
let delivered = false;
|
|
542
|
-
if (
|
|
664
|
+
if (streamLive(state)) {
|
|
665
|
+
await completeReasoning(channel, event.sessionId);
|
|
543
666
|
({ delivered } = await strategy.fail({
|
|
544
667
|
channel,
|
|
545
668
|
channelId: state.streamChannelId ?? state.channelId,
|
|
@@ -548,25 +671,11 @@ export function buildDefaultEvents(
|
|
|
548
671
|
}));
|
|
549
672
|
}
|
|
550
673
|
if (!delivered) {
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
threadTs: state.threadTs,
|
|
557
|
-
});
|
|
558
|
-
} catch (error) {
|
|
559
|
-
log.error(
|
|
560
|
-
`turn.failed postMessage failed: ${
|
|
561
|
-
error instanceof Error ? error.message : String(error)
|
|
562
|
-
}`,
|
|
563
|
-
{
|
|
564
|
-
channel: state.channelId,
|
|
565
|
-
thread_ts: state.threadTs,
|
|
566
|
-
session: event.sessionId,
|
|
567
|
-
}
|
|
568
|
-
);
|
|
569
|
-
}
|
|
674
|
+
await finishProgress({
|
|
675
|
+
channel,
|
|
676
|
+
text: errorText,
|
|
677
|
+
sessionId: event.sessionId,
|
|
678
|
+
});
|
|
570
679
|
}
|
|
571
680
|
await clearWorkingStatus(state.channelId, state.threadTs);
|
|
572
681
|
},
|
|
@@ -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,
|
|
@@ -126,9 +127,14 @@ export function emptySlackChannelState(
|
|
|
126
127
|
streamTs: null,
|
|
127
128
|
streamChannelId: null,
|
|
128
129
|
lastPostedText: null,
|
|
130
|
+
streamBlockText: null,
|
|
129
131
|
lastBotMessageTs: null,
|
|
130
132
|
streamingUnavailable: false,
|
|
133
|
+
streamFull: false,
|
|
134
|
+
progressTs: null,
|
|
131
135
|
approvalMessageByCallId: {},
|
|
136
|
+
reasoningCard: undefined,
|
|
137
|
+
toolCardCounts: {},
|
|
132
138
|
...patch,
|
|
133
139
|
};
|
|
134
140
|
}
|
|
@@ -795,6 +801,9 @@ export function dispatchInboundFromEventBody(
|
|
|
795
801
|
}
|
|
796
802
|
}
|
|
797
803
|
|
|
798
|
-
log.debug("inbound ignored (unhandled event shape)", {
|
|
804
|
+
log.debug("inbound ignored (unhandled event shape)", {
|
|
805
|
+
...describeSlackEventShape(body),
|
|
806
|
+
event_id: eventId,
|
|
807
|
+
});
|
|
799
808
|
return false;
|
|
800
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
|