@desplega.ai/agent-swarm 2.7.2 → 2.7.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -0
- package/dist/{acp-adapter-624yge7a.js → acp-adapter-pdzw76ja.js} +1 -1
- package/dist/{actions-rd9xn281.js → actions-a90cfpca.js} +21 -21
- package/dist/{amp-adapter-k27hc00p.js → amp-adapter-4vtywcjk.js} +2 -2
- package/dist/{app-sjm3xc7g.js → app-8k68gygk.js} +3 -3
- package/dist/{assistant-6jbzs8wa.js → assistant-ck01q2yg.js} +32 -21
- package/dist/{boot-reembed-e2348eqc.js → boot-reembed-33spavpd.js} +1 -1
- package/dist/{boot-reembed-w53pd5xt.js → boot-reembed-xzge83a2.js} +1 -1
- package/dist/{boot-scrub-sweep-cpy4yg97.js → boot-scrub-sweep-mxvb8dr3.js} +3 -3
- package/dist/{boot-seeds-f6j4t6k6.js → boot-seeds-rpm8bb5r.js} +4 -4
- package/dist/{claude-adapter-v3ac8esd.js → claude-adapter-q12bcfj9.js} +3 -3
- package/dist/{claude-managed-setup-yyrkqvtm.js → claude-managed-setup-11vb6q89.js} +1 -1
- package/dist/{claude-sdk-session-85j69v6d.js → claude-sdk-session-gkv1107j.js} +10325 -10243
- package/dist/{cli-rs59z1qx.js → cli-07pcqwaj.js} +1 -1
- package/dist/{cli-6vq3ymqm.js → cli-0tkm519n.js} +1 -1
- package/dist/{cli-s7cm1927.js → cli-0xzbk52h.js} +4 -4
- package/dist/{cli-g0zc1b40.js → cli-0zae6bs6.js} +2 -2
- package/dist/{cli-p8yrsmfn.js → cli-10kjx0dm.js} +1 -1
- package/dist/{cli-7xsq63pe.js → cli-157ykn37.js} +10 -9
- package/dist/{cli-vjcj9k2p.js → cli-2h0rfmqk.js} +1 -1
- package/dist/{cli-9wasax9f.js → cli-35nzvqaf.js} +1 -1
- package/dist/{cli-e1p7dqe1.js → cli-4aydmmdy.js} +24 -3
- package/dist/{cli-942pp3bc.js → cli-54ax65rn.js} +3 -3
- package/dist/{cli-10cp92df.js → cli-5ke7gxwr.js} +6 -6
- package/dist/{cli-femw4q81.js → cli-6151a7dr.js} +2 -2
- package/dist/{cli-3cywb44q.js → cli-77eq8txs.js} +85 -3
- package/dist/{cli-atpfk4yd.js → cli-7cwrwb5x.js} +5 -5
- package/dist/{cli-bfbpvccx.js → cli-8a1k6mat.js} +61 -49
- package/dist/{cli-c18941tx.js → cli-8ch3b2r7.js} +3 -3
- package/dist/{cli-rs2s1t05.js → cli-9fk56y8c.js} +4 -4
- package/dist/{cli-0wx63vvw.js → cli-9km88w11.js} +1 -1
- package/dist/{cli-qy0z3mfj.js → cli-9vttw9nz.js} +56 -46
- package/dist/{cli-mzgppb7q.js → cli-a0w50zw9.js} +4 -4
- package/dist/{cli-z8a4mfz1.js → cli-aqp59jmv.js} +4 -4
- package/dist/{cli-5d8wd50e.js → cli-bs0fwb23.js} +1 -1
- package/dist/{cli-fa4kxxx3.js → cli-ct5920jb.js} +2 -2
- package/dist/{cli-0awbtmv2.js → cli-dek8hqjc.js} +10 -10
- package/dist/{cli-qp6adcmw.js → cli-e24w2mvk.js} +1 -1
- package/dist/{cli-t3npd8hm.js → cli-ghfhn1qc.js} +1 -1
- package/dist/{cli-jmcf8cnz.js → cli-ja369zab.js} +1 -1
- package/dist/{cli-wtjg6je3.js → cli-jhh7tbx6.js} +1 -1
- package/dist/{cli-e19bgatr.js → cli-jmk31131.js} +2 -2
- package/dist/{cli-2cj8fqv1.js → cli-kjcdzea8.js} +1 -1
- package/dist/{cli-1xpr5992.js → cli-kjha1q9k.js} +3 -3
- package/dist/{cli-9jfty8px.js → cli-ktcdczth.js} +538 -30
- package/dist/{cli-exd52qn4.js → cli-mcmpbpcc.js} +2 -2
- package/dist/{cli-2m2p3snc.js → cli-mmf43vcp.js} +6 -6
- package/dist/{cli-b2rhbaty.js → cli-pnm99spe.js} +10 -10
- package/dist/{cli-9jn9cj0q.js → cli-v9jk2k63.js} +1 -1
- package/dist/{cli-mt7bxjfd.js → cli-vhgcwppn.js} +1 -1
- package/dist/{cli-qa4hgda3.js → cli-vvz64zc5.js} +14 -13
- package/dist/{cli-txr0z97c.js → cli-wmhajw68.js} +171 -32
- package/dist/{cli-hzrmv8pg.js → cli-x38rmhap.js} +3 -3
- package/dist/{cli-hq9hd4hp.js → cli-xz6qjdqj.js} +1 -1
- package/dist/{cli-g9ypd5en.js → cli-z52gq55b.js} +4 -0
- package/dist/{cli-2qbmjfta.js → cli-z6219sd3.js} +4 -4
- package/dist/cli.js +19 -19
- package/dist/{codex-adapter-zm1bkdde.js → codex-adapter-46kbvvkx.js} +1 -1
- package/dist/{codex-hook-tkag7fxq.js → codex-hook-tm9ecrd5.js} +1 -1
- package/dist/{codex-session-runner-8k02mqw2.js → codex-session-runner-qy93hdrv.js} +1 -1
- package/dist/{commands-nw1dn4av.js → commands-hwdhacfx.js} +2 -2
- package/dist/{controller-3kkkmps0.js → controller-hjza5p1f.js} +3 -3
- package/dist/{controllers-connect-n2c4167r.js → controllers-connect-7m25cay2.js} +20 -20
- package/dist/{cursor-adapter-h5028emw.js → cursor-adapter-1qh7ps8w.js} +1 -1
- package/dist/{db-76y2msnf.js → db-w23k9301.js} +2 -2
- package/dist/{db-8rk0p8j1.js → db-wm8by383.js} +3 -3
- package/dist/{dispatcher-xp4wsx30.js → dispatcher-en25ebgc.js} +18 -18
- package/dist/{dsh-adapter-vyrr31bn.js → dsh-adapter-zkme32vd.js} +1 -1
- package/dist/{e2b-eesfj689.js → e2b-9z9mvt2p.js} +1 -1
- package/dist/{e2b-03nha1wz.js → e2b-yhvn70es.js} +1 -1
- package/dist/{embedding-space-ejefyep1.js → embedding-space-rgf4aypt.js} +6 -6
- package/dist/{embeddings-w297xaw0.js → embeddings-z9cmxhx1.js} +1 -1
- package/dist/{external-channel-mf9vp1fe.js → external-channel-g6vv85zv.js} +2 -2
- package/dist/{grok-adapter-mpzyyprz.js → grok-adapter-f6n1tpq3.js} +2 -2
- package/dist/handlers-ss5948rq.js +42 -0
- package/dist/{heartbeat-qnaycjzs.js → heartbeat-5xcdzz45.js} +21 -21
- package/dist/{hook-h6sqfzxr.js → hook-6423rme3.js} +2 -2
- package/dist/{hook-4zqdgea4.js → hook-8dk1csdd.js} +4 -4
- package/dist/{http-65ts210h.js → http-6mfh2ww9.js} +255 -60
- package/dist/{index-sqe7f6mj.js → index-0js6bgff.js} +1 -1
- package/dist/{index-farm1zsn.js → index-0ng1dd1t.js} +10937 -9527
- package/dist/{index-k3ewf1jg.js → index-5eyn1wc5.js} +18 -18
- package/dist/{index-vp4wa3qn.js → index-71gnebsn.js} +18 -18
- package/dist/{index-hdfad00b.js → index-q5gzpjdd.js} +12 -10
- package/dist/index-z3b1vfjx.js +44 -0
- package/dist/{keepalive-52k6skha.js → keepalive-cymckeg6.js} +3 -3
- package/dist/{lead-y9rj0gr1.js → lead-baknj2dh.js} +29 -29
- package/dist/{maintenance-f86wqfq6.js → maintenance-dfrnsx3n.js} +1 -1
- package/dist/{oauth-refresh-sweep-vddv9ky7.js → oauth-refresh-sweep-5dztk8x6.js} +2 -2
- package/dist/{onboard-8z2qk6gq.js → onboard-h36vja6y.js} +11 -6
- package/dist/{otel-impl-epet9j18.js → otel-impl-jerq8vz8.js} +1 -1
- package/dist/{pricing-refresh-6wm42a51.js → pricing-refresh-t3nx5krn.js} +3 -3
- package/dist/{rbac-roles-2kfcs1sc.js → rbac-roles-dw1awawd.js} +2 -2
- package/dist/{rbac-roles-13a0vj6d.js → rbac-roles-km0fc3e8.js} +1 -1
- package/dist/{registry-ajhexe44.js → registry-hzfh268v.js} +1 -1
- package/dist/{render-v2-cy8zsfsf.js → render-v2-65x4ayj8.js} +3 -3
- package/dist/{resume-c783qe6b.js → resume-61znk3hj.js} +6 -6
- package/dist/{session-access-s4tv0az8.js → session-access-4yc9htrg.js} +4 -4
- package/dist/{session-source-backfill-qzapz0ne.js → session-source-backfill-kr5bdjtp.js} +2 -2
- package/dist/{setup-st7htx1k.js → setup-9h61yr2p.js} +1 -1
- package/dist/{work-objects-ftj4zw70.js → work-objects-x7rb53qn.js} +27 -22
- package/dist/{worker-859fk25k.js → worker-7f3khgn0.js} +29 -29
- package/openapi.json +134 -3
- package/package.json +5 -5
- package/src/be/db/agents.ts +16 -1
- package/src/be/db/runtime.ts +25 -15
- package/src/be/db/session-summaries.ts +120 -0
- package/src/be/db/tasks/read.ts +7 -4
- package/src/be/db/tasks/search-index.ts +159 -0
- package/src/be/db/tasks/write.ts +3 -0
- package/src/be/db-queries/slack-inbound.ts +77 -0
- package/src/be/db.ts +27 -8
- package/src/be/mcp-overflow-sweep.ts +39 -0
- package/src/be/migrations/253_session_summaries.sql +300 -0
- package/src/be/migrations/254_query_audit_indexes.sql +25 -0
- package/src/be/migrations/256_agent_slack_icon.sql +2 -0
- package/src/be/migrations/257_agent_tasks_fts.sql +55 -0
- package/src/comb/config.ts +6 -2
- package/src/comb/requester.ts +69 -0
- package/src/comb/review-batch.ts +24 -2
- package/src/commands/onboard/agent-fs-version.ts +1 -1
- package/src/commands/onboard/compose-generator.ts +7 -2
- package/src/commands/onboard/env-generator.ts +8 -3
- package/src/commands/runner.ts +41 -24
- package/src/fs/agent-fs-provider.ts +9 -0
- package/src/heartbeat/heartbeat.ts +13 -6
- package/src/http/agents.ts +10 -2
- package/src/http/index.ts +15 -0
- package/src/http/integrations.ts +20 -0
- package/src/http/list-total-cache.ts +62 -0
- package/src/http/sessions.ts +9 -2
- package/src/http/slack-inbound.ts +1 -0
- package/src/http/status.ts +4 -1
- package/src/http/tasks.ts +12 -2
- package/src/providers/amp-adapter.ts +1 -1
- package/src/providers/cursor-adapter.ts +1 -1
- package/src/providers/dsh-adapter.ts +1 -1
- package/src/queue-stall-alarm.ts +4 -1
- package/src/slack/actions.ts +2 -2
- package/src/slack/app-icon.ts +50 -0
- package/src/slack/app.ts +13 -1
- package/src/slack/assistant.ts +22 -1
- package/src/slack/event-dedup.test.ts +11 -0
- package/src/slack/event-dedup.ts +8 -4
- package/src/slack/inbound-dispatch.ts +58 -0
- package/src/slack/render-v2.ts +7 -8
- package/src/slack/responses.ts +21 -8
- package/src/slack/socket-ack.ts +237 -0
- package/src/slack/thread-buffer.ts +3 -5
- package/src/slack/watcher.ts +2 -2
- package/src/slack/work-objects.ts +5 -1
- package/src/tests/agent-fs-release-notes.test.ts +40 -0
- package/src/tests/agent-slack-icon.test.ts +85 -0
- package/src/tests/approval-cancellation-migration.test.ts +2 -0
- package/src/tests/asset-key-migration.test.ts +26 -0
- package/src/tests/comb-default.test.ts +159 -0
- package/src/tests/comb-review-batch.test.ts +192 -4
- package/src/tests/comb-status.test.ts +65 -2
- package/src/tests/db-agents.test.ts +13 -0
- package/src/tests/db-tasks-read.test.ts +10 -15
- package/src/tests/deploy-one-box.test.ts +161 -0
- package/src/tests/deploy-stubs.ts +68 -0
- package/src/tests/docs-index-footprint.test.js +3 -3
- package/src/tests/dsh-adapter.test.ts +1 -1
- package/src/tests/e2e-codex-auth-chain.test.ts +18 -1
- package/src/tests/fixtures/deploy-stubs/bun +3 -0
- package/src/tests/fixtures/deploy-stubs/bunx +27 -0
- package/src/tests/fixtures/deploy-stubs/curl +26 -0
- package/src/tests/fixtures/deploy-stubs/docker +122 -0
- package/src/tests/fixtures/onboard/content.compose.yml.txt +5 -5
- package/src/tests/fixtures/onboard/dev.compose.yml.txt +4 -4
- package/src/tests/fixtures/onboard/full-all.compose.yml.txt +12 -12
- package/src/tests/fixtures/onboard/full.compose.yml.txt +12 -12
- package/src/tests/fixtures/onboard/research.compose.yml.txt +4 -4
- package/src/tests/fixtures/onboard/solo.compose.yml.txt +2 -2
- package/src/tests/heartbeat-expiry.test.ts +151 -25
- package/src/tests/http-api-integration.test.ts +31 -0
- package/src/tests/human-free-reclassify.test.ts +6 -0
- package/src/tests/install-sh-bind.test.ts +242 -0
- package/src/tests/install-sh-tunnel.test.ts +89 -0
- package/src/tests/kv-storage.test.ts +28 -0
- package/src/tests/list-endpoint-slimming.test.ts +3 -0
- package/src/tests/list-total-cache.test.ts +63 -0
- package/src/tests/mcp-overflow-sweep.test.ts +84 -0
- package/src/tests/onboard-compose.test.ts +17 -3
- package/src/tests/onboard-env.test.ts +13 -0
- package/src/tests/onboarding.test.ts +1 -1
- package/src/tests/preload.ts +1 -0
- package/src/tests/query-audit-plans.test.ts +314 -0
- package/src/tests/script-connections.test.ts +6 -0
- package/src/tests/session-summaries.test.ts +384 -0
- package/src/tests/sessions-tree.test.ts +5 -1
- package/src/tests/slack-app-icon.test.ts +90 -0
- package/src/tests/slack-external-channel-egress.test.ts +1 -1
- package/src/tests/slack-inbound-receipts.test.ts +34 -0
- package/src/tests/slack-inline-output.test.ts +29 -2
- package/src/tests/slack-render-v2-query-plans.test.ts +3 -2
- package/src/tests/slack-render-v2.test.ts +35 -0
- package/src/tests/slack-socket-ack.test.ts +553 -0
- package/src/tests/task-lineage.test.ts +3 -0
- package/src/tests/task-search-filter.test.ts +4 -4
- package/src/tests/task-search-fts.test.ts +320 -0
- package/src/tests/update-profile-auth.test.ts +28 -0
- package/src/tools/get-swarm.ts +1 -0
- package/src/tools/get-tasks.ts +6 -1
- package/src/tools/join-swarm.ts +1 -0
- package/src/tools/my-agent-info.ts +1 -0
- package/src/tools/slack-post.ts +2 -2
- package/src/tools/slack-reply.ts +2 -2
- package/src/tools/slack-start-thread.ts +2 -2
- package/src/tools/slack-update.ts +1 -1
- package/src/tools/update-profile.ts +20 -4
- package/src/tools/utils.ts +3 -4
- package/src/types.ts +47 -0
- package/src/utils/constants.ts +127 -5
- package/templates/official/lead/HEARTBEAT.md +4 -2
- package/templates/official/lead/config.json +2 -2
- package/templates/skills/swarm-docs/content.md +2 -0
- package/dist/handlers-7x8sywgr.js +0 -42
- package/dist/index-mc30r1hs.js +0 -44
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
slackContextKey,
|
|
3
3
|
init_context_key,
|
|
4
|
+
encryptSecret,
|
|
5
|
+
decryptSecret,
|
|
6
|
+
getEncryptionKey,
|
|
4
7
|
init_crypto,
|
|
5
8
|
getDbClient2,
|
|
6
9
|
getAgentById2,
|
|
@@ -47,10 +50,10 @@ import {
|
|
|
47
50
|
checkDependencies2,
|
|
48
51
|
emitBuiltInIntegrationConnectedOnce2,
|
|
49
52
|
init_db3
|
|
50
|
-
} from "./cli-
|
|
53
|
+
} from "./cli-wmhajw68.js";
|
|
51
54
|
import {
|
|
52
55
|
getChannelBlockReason2
|
|
53
|
-
} from "./cli-
|
|
56
|
+
} from "./cli-0tkm519n.js";
|
|
54
57
|
import {
|
|
55
58
|
require_dist5,
|
|
56
59
|
require_axios,
|
|
@@ -67,11 +70,11 @@ import {
|
|
|
67
70
|
import {
|
|
68
71
|
isTerminalTaskStatus,
|
|
69
72
|
init_types2
|
|
70
|
-
} from "./cli-
|
|
73
|
+
} from "./cli-4aydmmdy.js";
|
|
71
74
|
import {
|
|
72
75
|
taskAttachmentDisplayUrl,
|
|
73
76
|
init_task_attachment_links
|
|
74
|
-
} from "./cli-
|
|
77
|
+
} from "./cli-9km88w11.js";
|
|
75
78
|
import {
|
|
76
79
|
getSlackConfiguration,
|
|
77
80
|
init_config
|
|
@@ -93,7 +96,7 @@ import {
|
|
|
93
96
|
import {
|
|
94
97
|
getAppUrl,
|
|
95
98
|
init_constants2
|
|
96
|
-
} from "./cli-
|
|
99
|
+
} from "./cli-77eq8txs.js";
|
|
97
100
|
import {
|
|
98
101
|
isEnvFlagEnabled,
|
|
99
102
|
init_env_flag
|
|
@@ -6005,8 +6008,9 @@ function installSlackExternalChannelGuard() {
|
|
|
6005
6008
|
}
|
|
6006
6009
|
|
|
6007
6010
|
// src/slack/inbound-dispatch.ts
|
|
6008
|
-
import { AsyncLocalStorage } from "node:async_hooks";
|
|
6009
6011
|
init_crypto();
|
|
6012
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
6013
|
+
import { createHash } from "node:crypto";
|
|
6010
6014
|
|
|
6011
6015
|
// src/be/db-queries/slack-inbound.ts
|
|
6012
6016
|
init_db3();
|
|
@@ -6026,6 +6030,176 @@ var SLACK_INBOUND_LIMITS = {
|
|
|
6026
6030
|
maxAttempts: 3,
|
|
6027
6031
|
retryBackoffMs: 30000
|
|
6028
6032
|
};
|
|
6033
|
+
function toReceipt(row) {
|
|
6034
|
+
return {
|
|
6035
|
+
id: row.id,
|
|
6036
|
+
dedupKey: row.dedup_key,
|
|
6037
|
+
transport: row.transport,
|
|
6038
|
+
kind: row.kind,
|
|
6039
|
+
payloadType: row.payload_type,
|
|
6040
|
+
apiAppId: row.api_app_id,
|
|
6041
|
+
eventId: row.event_id,
|
|
6042
|
+
payloadCiphertext: row.payload_ciphertext,
|
|
6043
|
+
payloadBytes: row.payload_bytes,
|
|
6044
|
+
retryNum: row.retry_num,
|
|
6045
|
+
retryReason: row.retry_reason,
|
|
6046
|
+
state: row.state,
|
|
6047
|
+
attempts: row.attempts,
|
|
6048
|
+
duplicateCount: row.duplicate_count,
|
|
6049
|
+
outcomeCode: row.outcome_code,
|
|
6050
|
+
errorCode: row.error_code,
|
|
6051
|
+
receivedAt: row.received_at,
|
|
6052
|
+
availableAt: row.available_at,
|
|
6053
|
+
claimedAt: row.claimed_at,
|
|
6054
|
+
completedAt: row.completed_at,
|
|
6055
|
+
lastDuplicateAt: row.last_duplicate_at,
|
|
6056
|
+
payloadErasedAt: row.payload_erased_at
|
|
6057
|
+
};
|
|
6058
|
+
}
|
|
6059
|
+
async function admitSlackInboundReceipt(input, now = new Date, limits = SLACK_INBOUND_LIMITS) {
|
|
6060
|
+
const nowIso = now.toISOString();
|
|
6061
|
+
return getDbClient2().transaction(async (tx) => {
|
|
6062
|
+
const duplicate = await tx.get(`UPDATE slack_inbound_receipts
|
|
6063
|
+
SET duplicate_count = duplicate_count + 1, last_duplicate_at = ?, updated_at = ?
|
|
6064
|
+
WHERE dedup_key = ?
|
|
6065
|
+
RETURNING *`, [nowIso, nowIso, input.dedupKey]);
|
|
6066
|
+
if (duplicate)
|
|
6067
|
+
return { status: "duplicate", receipt: toReceipt(duplicate) };
|
|
6068
|
+
if (input.payloadBytes > limits.maxPayloadBytes) {
|
|
6069
|
+
return { status: "rejected", reason: "payload_too_large" };
|
|
6070
|
+
}
|
|
6071
|
+
const backlog = await tx.get(`SELECT COUNT(*) AS receipts, SUM(payload_bytes) AS bytes
|
|
6072
|
+
FROM slack_inbound_receipts
|
|
6073
|
+
WHERE state IN ('pending', 'processing')`);
|
|
6074
|
+
const receipts = backlog?.receipts ?? 0;
|
|
6075
|
+
const bytes = backlog?.bytes ?? 0;
|
|
6076
|
+
if (receipts >= limits.maxBacklogReceipts || bytes + input.payloadBytes > limits.maxBacklogBytes) {
|
|
6077
|
+
return { status: "rejected", reason: "backlog_full" };
|
|
6078
|
+
}
|
|
6079
|
+
const inserted = await tx.get(`INSERT INTO slack_inbound_receipts (
|
|
6080
|
+
id, dedup_key, transport, kind, payload_type, api_app_id, event_id,
|
|
6081
|
+
payload_ciphertext, payload_bytes, retry_num, retry_reason,
|
|
6082
|
+
received_at, available_at, created_at, updated_at
|
|
6083
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
6084
|
+
ON CONFLICT(dedup_key) DO NOTHING
|
|
6085
|
+
RETURNING *`, [
|
|
6086
|
+
crypto.randomUUID(),
|
|
6087
|
+
input.dedupKey,
|
|
6088
|
+
input.transport,
|
|
6089
|
+
input.kind,
|
|
6090
|
+
input.payloadType,
|
|
6091
|
+
input.apiAppId ?? null,
|
|
6092
|
+
input.eventId ?? null,
|
|
6093
|
+
input.payloadCiphertext,
|
|
6094
|
+
input.payloadBytes,
|
|
6095
|
+
input.retryNum ?? null,
|
|
6096
|
+
input.retryReason ?? null,
|
|
6097
|
+
nowIso,
|
|
6098
|
+
nowIso,
|
|
6099
|
+
nowIso,
|
|
6100
|
+
nowIso
|
|
6101
|
+
]);
|
|
6102
|
+
if (inserted)
|
|
6103
|
+
return { status: "admitted", receipt: toReceipt(inserted) };
|
|
6104
|
+
const winner = await tx.get("SELECT * FROM slack_inbound_receipts WHERE dedup_key = ?", [input.dedupKey]);
|
|
6105
|
+
if (!winner)
|
|
6106
|
+
throw new Error("Slack inbound receipt vanished during admission");
|
|
6107
|
+
return { status: "duplicate", receipt: toReceipt(winner) };
|
|
6108
|
+
});
|
|
6109
|
+
}
|
|
6110
|
+
async function recordSlackInboundInline(input, now = new Date) {
|
|
6111
|
+
const nowIso = now.toISOString();
|
|
6112
|
+
const inserted = await getDbClient2().get(`INSERT INTO slack_inbound_receipts (
|
|
6113
|
+
id, dedup_key, transport, kind, payload_type, api_app_id, event_id,
|
|
6114
|
+
payload_bytes, retry_num, retry_reason, state, attempts, outcome_code,
|
|
6115
|
+
received_at, available_at, completed_at, payload_erased_at, created_at, updated_at
|
|
6116
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, 0, ?, ?, 'processed', 1, 'ran_inline', ?, ?, ?, ?, ?, ?)
|
|
6117
|
+
ON CONFLICT(dedup_key) DO NOTHING
|
|
6118
|
+
RETURNING id`, [
|
|
6119
|
+
crypto.randomUUID(),
|
|
6120
|
+
input.dedupKey,
|
|
6121
|
+
input.transport,
|
|
6122
|
+
input.kind,
|
|
6123
|
+
input.payloadType,
|
|
6124
|
+
input.apiAppId ?? null,
|
|
6125
|
+
input.eventId ?? null,
|
|
6126
|
+
input.retryNum ?? null,
|
|
6127
|
+
input.retryReason ?? null,
|
|
6128
|
+
nowIso,
|
|
6129
|
+
nowIso,
|
|
6130
|
+
nowIso,
|
|
6131
|
+
nowIso,
|
|
6132
|
+
nowIso,
|
|
6133
|
+
nowIso
|
|
6134
|
+
]);
|
|
6135
|
+
if (inserted)
|
|
6136
|
+
return "recorded";
|
|
6137
|
+
await touchSlackInboundDuplicate(input.dedupKey, now);
|
|
6138
|
+
return "duplicate";
|
|
6139
|
+
}
|
|
6140
|
+
async function touchSlackInboundDuplicate(dedupKey, now = new Date) {
|
|
6141
|
+
const nowIso = now.toISOString();
|
|
6142
|
+
const row = await getDbClient2().get(`UPDATE slack_inbound_receipts
|
|
6143
|
+
SET duplicate_count = duplicate_count + 1, last_duplicate_at = ?, updated_at = ?
|
|
6144
|
+
WHERE dedup_key = ?
|
|
6145
|
+
RETURNING id`, [nowIso, nowIso, dedupKey]);
|
|
6146
|
+
return row !== null && row !== undefined;
|
|
6147
|
+
}
|
|
6148
|
+
async function claimSlackInboundReceipt(now = new Date, id) {
|
|
6149
|
+
const nowIso = now.toISOString();
|
|
6150
|
+
const row = id ? await getDbClient2().get(`UPDATE slack_inbound_receipts
|
|
6151
|
+
SET state = 'processing', attempts = attempts + 1, claimed_at = ?, updated_at = ?
|
|
6152
|
+
WHERE id = ? AND state = 'pending' AND available_at <= ?
|
|
6153
|
+
RETURNING *`, [nowIso, nowIso, id, nowIso]) : await getDbClient2().get(`UPDATE slack_inbound_receipts
|
|
6154
|
+
SET state = 'processing', attempts = attempts + 1, claimed_at = ?, updated_at = ?
|
|
6155
|
+
WHERE id = (
|
|
6156
|
+
SELECT id FROM slack_inbound_receipts
|
|
6157
|
+
WHERE state = 'pending' AND available_at <= ?
|
|
6158
|
+
ORDER BY received_at, id
|
|
6159
|
+
LIMIT 1
|
|
6160
|
+
)
|
|
6161
|
+
AND state = 'pending'
|
|
6162
|
+
RETURNING *`, [nowIso, nowIso, nowIso]);
|
|
6163
|
+
return row ? toReceipt(row) : null;
|
|
6164
|
+
}
|
|
6165
|
+
async function completeSlackInboundReceipt(id, outcome, now = new Date) {
|
|
6166
|
+
const nowIso = now.toISOString();
|
|
6167
|
+
const erase = outcome.state === "processed" || outcome.state === "ignored";
|
|
6168
|
+
const { changes } = await getDbClient2().run(`UPDATE slack_inbound_receipts
|
|
6169
|
+
SET state = ?, outcome_code = ?, error_code = ?, completed_at = ?, updated_at = ?,
|
|
6170
|
+
payload_ciphertext = CASE WHEN ? THEN NULL ELSE payload_ciphertext END,
|
|
6171
|
+
payload_erased_at = CASE WHEN ? THEN ? ELSE payload_erased_at END
|
|
6172
|
+
WHERE id = ? AND state = 'processing'`, [
|
|
6173
|
+
outcome.state,
|
|
6174
|
+
outcome.outcomeCode ?? null,
|
|
6175
|
+
outcome.errorCode ?? null,
|
|
6176
|
+
outcome.state === "uncertain" ? null : nowIso,
|
|
6177
|
+
nowIso,
|
|
6178
|
+
erase ? 1 : 0,
|
|
6179
|
+
erase ? 1 : 0,
|
|
6180
|
+
nowIso,
|
|
6181
|
+
id
|
|
6182
|
+
]);
|
|
6183
|
+
return changes > 0;
|
|
6184
|
+
}
|
|
6185
|
+
async function releaseSlackInboundReceipt(id, errorCode, availableAt, now = new Date) {
|
|
6186
|
+
const nowIso = now.toISOString();
|
|
6187
|
+
const { changes } = await getDbClient2().run(`UPDATE slack_inbound_receipts
|
|
6188
|
+
SET state = 'pending', error_code = ?, available_at = ?, claimed_at = NULL, updated_at = ?
|
|
6189
|
+
WHERE id = ? AND state = 'processing'`, [errorCode, availableAt.toISOString(), nowIso, id]);
|
|
6190
|
+
return changes > 0;
|
|
6191
|
+
}
|
|
6192
|
+
async function getNextSlackInboundAvailableAt() {
|
|
6193
|
+
const row = await getDbClient2().get(`SELECT MIN(available_at) AS next FROM slack_inbound_receipts WHERE state = 'pending'`);
|
|
6194
|
+
return row?.next ? new Date(row.next) : null;
|
|
6195
|
+
}
|
|
6196
|
+
async function markInterruptedSlackInboundReceiptsUncertain(now = new Date) {
|
|
6197
|
+
const nowIso = now.toISOString();
|
|
6198
|
+
const { changes } = await getDbClient2().run(`UPDATE slack_inbound_receipts
|
|
6199
|
+
SET state = 'uncertain', error_code = 'interrupted_during_processing', updated_at = ?
|
|
6200
|
+
WHERE state = 'processing'`, [nowIso]);
|
|
6201
|
+
return changes;
|
|
6202
|
+
}
|
|
6029
6203
|
async function getSlackInboundReceiptStats(uncertainLimit = 20) {
|
|
6030
6204
|
const db = getDbClient2();
|
|
6031
6205
|
return db.transaction(async (tx) => {
|
|
@@ -6122,6 +6296,7 @@ function emptyCounters() {
|
|
|
6122
6296
|
ignored: 0,
|
|
6123
6297
|
failed: 0,
|
|
6124
6298
|
uncertain: 0,
|
|
6299
|
+
ackNotReady: 0,
|
|
6125
6300
|
lastOutcomeAt: null,
|
|
6126
6301
|
lastFailure: null
|
|
6127
6302
|
};
|
|
@@ -6140,6 +6315,9 @@ function recordOutcome(transport, outcome) {
|
|
|
6140
6315
|
console.warn(`[Slack] inbound ${transport} delivery ${outcome.state}: ${outcome.code}`);
|
|
6141
6316
|
}
|
|
6142
6317
|
}
|
|
6318
|
+
function recordSlackSocketAckNotReady() {
|
|
6319
|
+
counters.socket.ackNotReady += 1;
|
|
6320
|
+
}
|
|
6143
6321
|
function slackInboundOutcomeMiddleware() {
|
|
6144
6322
|
return async ({ next }) => {
|
|
6145
6323
|
const existing = deliveryStorage.getStore();
|
|
@@ -6166,6 +6344,213 @@ function slackInboundOutcomeMiddleware() {
|
|
|
6166
6344
|
});
|
|
6167
6345
|
};
|
|
6168
6346
|
}
|
|
6347
|
+
async function runAdmittedSlackDelivery(transport, fn, options = {}) {
|
|
6348
|
+
const state = newDeliveryState(transport, true);
|
|
6349
|
+
try {
|
|
6350
|
+
await deliveryStorage.run(state, fn);
|
|
6351
|
+
} catch (error) {
|
|
6352
|
+
return resolveSlackInboundOutcome(state, error);
|
|
6353
|
+
}
|
|
6354
|
+
if (options.requireBoltDispatch && !state.dispatched) {
|
|
6355
|
+
return { state: "failed", code: "not_dispatched" };
|
|
6356
|
+
}
|
|
6357
|
+
return resolveSlackInboundOutcome(state);
|
|
6358
|
+
}
|
|
6359
|
+
function sha256(value) {
|
|
6360
|
+
return createHash("sha256").update(value).digest("hex");
|
|
6361
|
+
}
|
|
6362
|
+
function stringField(body, key) {
|
|
6363
|
+
const value = body[key];
|
|
6364
|
+
return typeof value === "string" && value.length > 0 ? value : null;
|
|
6365
|
+
}
|
|
6366
|
+
function computeSlackInboundKey(kind, rawBody, body) {
|
|
6367
|
+
if (!body || typeof body !== "object")
|
|
6368
|
+
return { ok: false, reason: "malformed" };
|
|
6369
|
+
const record = body;
|
|
6370
|
+
const payloadType = stringField(record, "type") ?? (kind === "command" ? "command" : null);
|
|
6371
|
+
if (!payloadType)
|
|
6372
|
+
return { ok: false, reason: "malformed" };
|
|
6373
|
+
const apiAppId = stringField(record, "api_app_id");
|
|
6374
|
+
if (kind === "event" && payloadType === "event_callback") {
|
|
6375
|
+
const eventId = stringField(record, "event_id");
|
|
6376
|
+
if (!eventId)
|
|
6377
|
+
return { ok: false, reason: "missing_event_id" };
|
|
6378
|
+
return {
|
|
6379
|
+
ok: true,
|
|
6380
|
+
dedupKey: `event:${apiAppId ?? "-"}:${eventId}`,
|
|
6381
|
+
payloadType,
|
|
6382
|
+
apiAppId,
|
|
6383
|
+
eventId
|
|
6384
|
+
};
|
|
6385
|
+
}
|
|
6386
|
+
return {
|
|
6387
|
+
ok: true,
|
|
6388
|
+
dedupKey: `${kind}:${payloadType}:${sha256(rawBody)}`,
|
|
6389
|
+
payloadType,
|
|
6390
|
+
apiAppId,
|
|
6391
|
+
eventId: null
|
|
6392
|
+
};
|
|
6393
|
+
}
|
|
6394
|
+
function socketEventKey(body) {
|
|
6395
|
+
if (body?.type !== "event_callback")
|
|
6396
|
+
return null;
|
|
6397
|
+
const key = computeSlackInboundKey("event", "", body);
|
|
6398
|
+
return key.ok ? key : null;
|
|
6399
|
+
}
|
|
6400
|
+
async function isSlackSocketEventStored(body, now = new Date) {
|
|
6401
|
+
const key = socketEventKey(body);
|
|
6402
|
+
return key ? touchSlackInboundDuplicate(key.dedupKey, now) : false;
|
|
6403
|
+
}
|
|
6404
|
+
async function recordSlackSocketEventRanInline(body, retry = {}, now = new Date) {
|
|
6405
|
+
const key = socketEventKey(body);
|
|
6406
|
+
if (!key)
|
|
6407
|
+
return "invalid";
|
|
6408
|
+
return recordSlackInboundInline({
|
|
6409
|
+
dedupKey: key.dedupKey,
|
|
6410
|
+
transport: "socket",
|
|
6411
|
+
kind: "event",
|
|
6412
|
+
payloadType: key.payloadType,
|
|
6413
|
+
apiAppId: key.apiAppId,
|
|
6414
|
+
eventId: key.eventId,
|
|
6415
|
+
retryNum: retry.retryNum,
|
|
6416
|
+
retryReason: retry.retryReason
|
|
6417
|
+
}, now);
|
|
6418
|
+
}
|
|
6419
|
+
async function admitSlackInbound(input, now = new Date) {
|
|
6420
|
+
const key = computeSlackInboundKey(input.kind, input.rawBody, input.body);
|
|
6421
|
+
if (!key.ok)
|
|
6422
|
+
return { status: "invalid", reason: key.reason };
|
|
6423
|
+
const payloadBytes = Buffer.byteLength(input.rawBody, "utf8");
|
|
6424
|
+
if (payloadBytes > SLACK_INBOUND_LIMITS.maxPayloadBytes) {
|
|
6425
|
+
return { status: "rejected", reason: "payload_too_large" };
|
|
6426
|
+
}
|
|
6427
|
+
return admitSlackInboundReceipt({
|
|
6428
|
+
dedupKey: key.dedupKey,
|
|
6429
|
+
transport: input.transport,
|
|
6430
|
+
kind: input.kind,
|
|
6431
|
+
payloadType: key.payloadType,
|
|
6432
|
+
apiAppId: key.apiAppId,
|
|
6433
|
+
eventId: key.eventId,
|
|
6434
|
+
payloadCiphertext: encryptSecret(input.rawBody, getEncryptionKey()),
|
|
6435
|
+
payloadBytes,
|
|
6436
|
+
retryNum: input.retryNum ?? null,
|
|
6437
|
+
retryReason: input.retryReason ?? null
|
|
6438
|
+
}, now);
|
|
6439
|
+
}
|
|
6440
|
+
async function processNextSlackInboundReceipt(processor, options = {}) {
|
|
6441
|
+
const now = options.now ?? (() => new Date);
|
|
6442
|
+
const receipt = await claimSlackInboundReceipt(now());
|
|
6443
|
+
if (!receipt)
|
|
6444
|
+
return null;
|
|
6445
|
+
let rawBody;
|
|
6446
|
+
try {
|
|
6447
|
+
if (!receipt.payloadCiphertext)
|
|
6448
|
+
throw new Error("payload already erased");
|
|
6449
|
+
rawBody = decryptSecret(receipt.payloadCiphertext, getEncryptionKey());
|
|
6450
|
+
} catch {
|
|
6451
|
+
const outcome = { state: "failed", code: "payload_unreadable" };
|
|
6452
|
+
await completeSlackInboundReceipt(receipt.id, { state: "failed", errorCode: outcome.code }, now());
|
|
6453
|
+
recordOutcome(receipt.transport, outcome);
|
|
6454
|
+
return { receiptId: receipt.id, outcome, state: "failed" };
|
|
6455
|
+
}
|
|
6456
|
+
const outcome = await runAdmittedSlackDelivery(receipt.transport, () => processor({ receipt, rawBody }), { requireBoltDispatch: options.requireBoltDispatch });
|
|
6457
|
+
recordOutcome(receipt.transport, outcome);
|
|
6458
|
+
if (outcome.state === "failed" && receipt.attempts < SLACK_INBOUND_LIMITS.maxAttempts) {
|
|
6459
|
+
const availableAt = new Date(now().getTime() + SLACK_INBOUND_LIMITS.retryBackoffMs * receipt.attempts);
|
|
6460
|
+
await releaseSlackInboundReceipt(receipt.id, outcome.code, availableAt, now());
|
|
6461
|
+
return { receiptId: receipt.id, outcome, state: "pending" };
|
|
6462
|
+
}
|
|
6463
|
+
await completeSlackInboundReceipt(receipt.id, {
|
|
6464
|
+
state: outcome.state,
|
|
6465
|
+
outcomeCode: outcome.state === "processed" || outcome.state === "ignored" ? outcome.code : null,
|
|
6466
|
+
errorCode: outcome.state === "failed" || outcome.state === "uncertain" ? outcome.code : null
|
|
6467
|
+
}, now());
|
|
6468
|
+
return { receiptId: receipt.id, outcome, state: outcome.state };
|
|
6469
|
+
}
|
|
6470
|
+
var defaultTimer = (fn, delayMs) => {
|
|
6471
|
+
const handle = setTimeout(fn, delayMs);
|
|
6472
|
+
handle.unref?.();
|
|
6473
|
+
return () => clearTimeout(handle);
|
|
6474
|
+
};
|
|
6475
|
+
var MIN_REARM_MS = 250;
|
|
6476
|
+
function createSlackInboundDrain(processor, options = {}) {
|
|
6477
|
+
const maxPerPass = options.maxPerPass ?? 50;
|
|
6478
|
+
const now = options.now ?? (() => new Date);
|
|
6479
|
+
const setTimer = options.setTimer ?? defaultTimer;
|
|
6480
|
+
let running = null;
|
|
6481
|
+
let again = false;
|
|
6482
|
+
let stopped = false;
|
|
6483
|
+
let cancelTimer = null;
|
|
6484
|
+
const clearTimer = () => {
|
|
6485
|
+
cancelTimer?.();
|
|
6486
|
+
cancelTimer = null;
|
|
6487
|
+
};
|
|
6488
|
+
const pass = async () => {
|
|
6489
|
+
for (let i = 0;i < maxPerPass; i++) {
|
|
6490
|
+
const result = await processNextSlackInboundReceipt(processor, {
|
|
6491
|
+
now,
|
|
6492
|
+
requireBoltDispatch: options.requireBoltDispatch
|
|
6493
|
+
});
|
|
6494
|
+
if (!result)
|
|
6495
|
+
return;
|
|
6496
|
+
}
|
|
6497
|
+
};
|
|
6498
|
+
const armRetryTimer = async () => {
|
|
6499
|
+
const next = await getNextSlackInboundAvailableAt();
|
|
6500
|
+
if (!next || stopped)
|
|
6501
|
+
return;
|
|
6502
|
+
const delayMs = Math.max(next.getTime() - now().getTime(), MIN_REARM_MS);
|
|
6503
|
+
cancelTimer = setTimer(() => {
|
|
6504
|
+
cancelTimer = null;
|
|
6505
|
+
drain.wake();
|
|
6506
|
+
}, delayMs);
|
|
6507
|
+
};
|
|
6508
|
+
const loop = async () => {
|
|
6509
|
+
do {
|
|
6510
|
+
again = false;
|
|
6511
|
+
clearTimer();
|
|
6512
|
+
try {
|
|
6513
|
+
await pass();
|
|
6514
|
+
} catch (error) {
|
|
6515
|
+
console.error("[Slack] inbound drain pass failed:", scrubSecrets(String(error)));
|
|
6516
|
+
return;
|
|
6517
|
+
}
|
|
6518
|
+
if (again)
|
|
6519
|
+
continue;
|
|
6520
|
+
try {
|
|
6521
|
+
await armRetryTimer();
|
|
6522
|
+
} catch (error) {
|
|
6523
|
+
console.error("[Slack] inbound drain could not arm retry:", scrubSecrets(String(error)));
|
|
6524
|
+
}
|
|
6525
|
+
} while (again);
|
|
6526
|
+
};
|
|
6527
|
+
const drain = {
|
|
6528
|
+
wake() {
|
|
6529
|
+
if (stopped)
|
|
6530
|
+
return Promise.resolve();
|
|
6531
|
+
if (running) {
|
|
6532
|
+
again = true;
|
|
6533
|
+
return running;
|
|
6534
|
+
}
|
|
6535
|
+
running = loop().finally(() => {
|
|
6536
|
+
running = null;
|
|
6537
|
+
});
|
|
6538
|
+
return running;
|
|
6539
|
+
},
|
|
6540
|
+
stop() {
|
|
6541
|
+
stopped = true;
|
|
6542
|
+
clearTimer();
|
|
6543
|
+
}
|
|
6544
|
+
};
|
|
6545
|
+
return drain;
|
|
6546
|
+
}
|
|
6547
|
+
async function recoverSlackInboundAfterRestart(now = new Date) {
|
|
6548
|
+
const interrupted = await markInterruptedSlackInboundReceiptsUncertain(now);
|
|
6549
|
+
if (interrupted > 0) {
|
|
6550
|
+
console.warn(`[Slack] ${interrupted} inbound receipt(s) were interrupted mid-processing and are now uncertain`);
|
|
6551
|
+
}
|
|
6552
|
+
return interrupted;
|
|
6553
|
+
}
|
|
6169
6554
|
async function getSlackInboundDiagnostics() {
|
|
6170
6555
|
const config = getSlackConfiguration();
|
|
6171
6556
|
return {
|
|
@@ -6180,6 +6565,117 @@ async function getSlackInboundDiagnostics() {
|
|
|
6180
6565
|
};
|
|
6181
6566
|
}
|
|
6182
6567
|
|
|
6568
|
+
// src/slack/socket-ack.ts
|
|
6569
|
+
var NOT_READY_MESSAGE = "Failed to send a WebSocket message as the client is not ready";
|
|
6570
|
+
function isSocketNotReadyError(error) {
|
|
6571
|
+
return error instanceof Error && error.message === NOT_READY_MESSAGE;
|
|
6572
|
+
}
|
|
6573
|
+
var ORDER_DEPENDENT_EVENTS = new Set(["assistant_thread_context_changed"]);
|
|
6574
|
+
function isOrderDependentEvent(body) {
|
|
6575
|
+
const type = body?.event?.type;
|
|
6576
|
+
return typeof type === "string" && ORDER_DEPENDENT_EVENTS.has(type);
|
|
6577
|
+
}
|
|
6578
|
+
function tolerateSocketNotReadyAcks(client, options) {
|
|
6579
|
+
const emit = client.emit.bind(client);
|
|
6580
|
+
const deliver = (event, args) => emit(event, ...args);
|
|
6581
|
+
client.emit = (event, ...args) => {
|
|
6582
|
+
const payload = args[0];
|
|
6583
|
+
if (event !== "slack_event" || payload?.type !== "events_api" || typeof payload.ack !== "function") {
|
|
6584
|
+
return deliver(event, args);
|
|
6585
|
+
}
|
|
6586
|
+
const ack = payload.ack;
|
|
6587
|
+
const envelope = payload.envelope_id ?? "unknown";
|
|
6588
|
+
payload.ack = async (response) => {
|
|
6589
|
+
try {
|
|
6590
|
+
await ack(response);
|
|
6591
|
+
} catch (error) {
|
|
6592
|
+
if (!isSocketNotReadyError(error))
|
|
6593
|
+
throw error;
|
|
6594
|
+
recordSlackSocketAckNotReady();
|
|
6595
|
+
const disposition = await dispose(payload, envelope);
|
|
6596
|
+
if (disposition === "drain") {
|
|
6597
|
+
options.onAdmitted();
|
|
6598
|
+
throw error;
|
|
6599
|
+
}
|
|
6600
|
+
if (disposition === "drop")
|
|
6601
|
+
throw error;
|
|
6602
|
+
console.warn(`[Slack] socket ack failed (client not ready), processing inline: envelope_id=${envelope}`);
|
|
6603
|
+
}
|
|
6604
|
+
};
|
|
6605
|
+
if (typeof payload.retry_num !== "number" || payload.retry_num < 1) {
|
|
6606
|
+
return deliver(event, args);
|
|
6607
|
+
}
|
|
6608
|
+
(async () => {
|
|
6609
|
+
let stored = false;
|
|
6610
|
+
try {
|
|
6611
|
+
stored = await isSlackSocketEventStored(payload.body);
|
|
6612
|
+
} catch (storeError) {
|
|
6613
|
+
console.warn("[Slack] could not check stored event key, processing:", storeError);
|
|
6614
|
+
}
|
|
6615
|
+
if (!stored) {
|
|
6616
|
+
deliver(event, args);
|
|
6617
|
+
return;
|
|
6618
|
+
}
|
|
6619
|
+
console.log(`[Slack] dropping redelivery of a stored event: envelope_id=${envelope}`);
|
|
6620
|
+
try {
|
|
6621
|
+
await ack();
|
|
6622
|
+
} catch (error) {
|
|
6623
|
+
console.warn("[Slack] ack of a dropped redelivery failed:", error);
|
|
6624
|
+
}
|
|
6625
|
+
})();
|
|
6626
|
+
return client.listenerCount(event) > 0;
|
|
6627
|
+
};
|
|
6628
|
+
}
|
|
6629
|
+
async function dispose(payload, envelope) {
|
|
6630
|
+
if (isOrderDependentEvent(payload.body)) {
|
|
6631
|
+
rememberInline(payload, envelope);
|
|
6632
|
+
return "inline";
|
|
6633
|
+
}
|
|
6634
|
+
try {
|
|
6635
|
+
const result = await admitSlackInbound({
|
|
6636
|
+
transport: "socket",
|
|
6637
|
+
kind: "event",
|
|
6638
|
+
rawBody: JSON.stringify(payload.body),
|
|
6639
|
+
body: payload.body,
|
|
6640
|
+
retryNum: payload.retry_num,
|
|
6641
|
+
retryReason: payload.retry_reason
|
|
6642
|
+
});
|
|
6643
|
+
if (result.status === "admitted" || result.status === "duplicate") {
|
|
6644
|
+
console.warn(`[Slack] socket ack failed (client not ready), event stored for the drain: envelope_id=${envelope}`);
|
|
6645
|
+
return "drain";
|
|
6646
|
+
}
|
|
6647
|
+
console.warn(`[Slack] could not store unacked event (${result.reason}): envelope_id=${envelope}`);
|
|
6648
|
+
} catch (storeError) {
|
|
6649
|
+
console.warn("[Slack] could not persist unacked event:", storeError);
|
|
6650
|
+
}
|
|
6651
|
+
return "inline";
|
|
6652
|
+
}
|
|
6653
|
+
async function rememberInline(payload, envelope) {
|
|
6654
|
+
try {
|
|
6655
|
+
const result = await recordSlackSocketEventRanInline(payload.body, {
|
|
6656
|
+
retryNum: payload.retry_num,
|
|
6657
|
+
retryReason: payload.retry_reason
|
|
6658
|
+
});
|
|
6659
|
+
if (result === "duplicate") {
|
|
6660
|
+
console.warn(`[Slack] inline event key was already stored: envelope_id=${envelope}`);
|
|
6661
|
+
}
|
|
6662
|
+
} catch (storeError) {
|
|
6663
|
+
console.warn("[Slack] could not remember unacked inline event:", storeError);
|
|
6664
|
+
}
|
|
6665
|
+
}
|
|
6666
|
+
function installSocketAckRecovery(client, app) {
|
|
6667
|
+
const drain = createSlackInboundDrain(async ({ receipt, rawBody }) => {
|
|
6668
|
+
await app.processEvent({
|
|
6669
|
+
body: JSON.parse(rawBody),
|
|
6670
|
+
ack: async () => {},
|
|
6671
|
+
retryNum: receipt.retryNum ?? undefined,
|
|
6672
|
+
retryReason: receipt.retryReason ?? undefined
|
|
6673
|
+
});
|
|
6674
|
+
}, { requireBoltDispatch: true });
|
|
6675
|
+
tolerateSocketNotReadyAcks(client, { onAdmitted: () => void drain.wake() });
|
|
6676
|
+
return drain;
|
|
6677
|
+
}
|
|
6678
|
+
|
|
6183
6679
|
// src/slack/socket-mode-guard.ts
|
|
6184
6680
|
init_env_flag();
|
|
6185
6681
|
var SLACK_DEV_SOCKET_MODE_OPT_IN = "SLACK_ALLOW_DEV_SOCKET_MODE";
|
|
@@ -6240,7 +6736,7 @@ async function initOtel(serviceRole = process.env.AGENT_ROLE || "api") {
|
|
|
6240
6736
|
return;
|
|
6241
6737
|
initialized = true;
|
|
6242
6738
|
try {
|
|
6243
|
-
const impl = await import("./otel-impl-
|
|
6739
|
+
const impl = await import("./otel-impl-jerq8vz8.js");
|
|
6244
6740
|
await impl.boot(serviceRole, {
|
|
6245
6741
|
exportConsoleLogs: serviceRole === "api" && isApiLogExportEnabled()
|
|
6246
6742
|
});
|
|
@@ -7616,7 +8112,7 @@ async function sendInlineTaskOutput(task) {
|
|
|
7616
8112
|
|
|
7617
8113
|
`),
|
|
7618
8114
|
username: getAgentDisplayName(agent),
|
|
7619
|
-
|
|
8115
|
+
icon: getAgentSlackIcon(agent),
|
|
7620
8116
|
blocks: batch.map((chunk) => ({
|
|
7621
8117
|
type: "section",
|
|
7622
8118
|
text: { type: "mrkdwn", text: chunk }
|
|
@@ -7669,7 +8165,7 @@ async function sendTaskResponse(task) {
|
|
|
7669
8165
|
thread_ts: task.slackThreadTs,
|
|
7670
8166
|
text: task.slackReplySent || i > 0 ? `${completedStatusIcon()} ${agentName} completed${i > 0 ? ` (continued ${i + 1}/${blockBatches.length})` : ""}` : body,
|
|
7671
8167
|
username: getAgentDisplayName(agent),
|
|
7672
|
-
|
|
8168
|
+
icon: getAgentSlackIcon(agent),
|
|
7673
8169
|
blocks: blockBatches[i]
|
|
7674
8170
|
});
|
|
7675
8171
|
}
|
|
@@ -7681,7 +8177,7 @@ async function sendTaskResponse(task) {
|
|
|
7681
8177
|
thread_ts: task.slackThreadTs,
|
|
7682
8178
|
text: `Task failed: ${reason}`,
|
|
7683
8179
|
username: getAgentDisplayName(agent),
|
|
7684
|
-
|
|
8180
|
+
icon: getAgentSlackIcon(agent),
|
|
7685
8181
|
blocks
|
|
7686
8182
|
});
|
|
7687
8183
|
} else if (task.status === "cancelled") {
|
|
@@ -7691,7 +8187,7 @@ async function sendTaskResponse(task) {
|
|
|
7691
8187
|
thread_ts: task.slackThreadTs,
|
|
7692
8188
|
text: "Task cancelled",
|
|
7693
8189
|
username: getAgentDisplayName(agent),
|
|
7694
|
-
|
|
8190
|
+
icon: getAgentSlackIcon(agent),
|
|
7695
8191
|
blocks
|
|
7696
8192
|
});
|
|
7697
8193
|
}
|
|
@@ -7718,7 +8214,7 @@ async function sendProgressUpdate(task, progress) {
|
|
|
7718
8214
|
thread_ts: task.slackThreadTs,
|
|
7719
8215
|
text: progress,
|
|
7720
8216
|
username: getAgentDisplayName(agent),
|
|
7721
|
-
|
|
8217
|
+
icon: getAgentSlackIcon(agent),
|
|
7722
8218
|
blocks
|
|
7723
8219
|
});
|
|
7724
8220
|
} catch (error) {
|
|
@@ -7809,7 +8305,7 @@ async function updateToFinal(task, messageTs) {
|
|
|
7809
8305
|
thread_ts: task.slackThreadTs ?? messageTs,
|
|
7810
8306
|
text: `${completedStatusIcon()} ${agentName} completed (continued ${i + 1}/${completionBlockBatches.length})`,
|
|
7811
8307
|
username: getAgentDisplayName(agent),
|
|
7812
|
-
|
|
8308
|
+
icon: getAgentSlackIcon(agent),
|
|
7813
8309
|
blocks: completionBlockBatches[i]
|
|
7814
8310
|
});
|
|
7815
8311
|
}
|
|
@@ -7861,11 +8357,20 @@ async function sendWithPersona(client, options) {
|
|
|
7861
8357
|
unfurl_links: false,
|
|
7862
8358
|
unfurl_media: false,
|
|
7863
8359
|
username: options.username,
|
|
7864
|
-
|
|
8360
|
+
...options.icon,
|
|
7865
8361
|
blocks
|
|
7866
8362
|
});
|
|
7867
8363
|
return result.ts;
|
|
7868
8364
|
}
|
|
8365
|
+
function getAgentSlackIcon(agent) {
|
|
8366
|
+
if (agent.slackIcon?.type === "url")
|
|
8367
|
+
return { icon_url: agent.slackIcon.url };
|
|
8368
|
+
if (agent.slackIcon?.type === "emoji")
|
|
8369
|
+
return { icon_emoji: agent.slackIcon.emoji };
|
|
8370
|
+
if (agent.slackIcon?.type === "app")
|
|
8371
|
+
return {};
|
|
8372
|
+
return { icon_emoji: getAgentEmoji(agent) };
|
|
8373
|
+
}
|
|
7869
8374
|
function getAgentEmoji(agent) {
|
|
7870
8375
|
if (agent.isLead)
|
|
7871
8376
|
return ":crown:";
|
|
@@ -8620,7 +9125,7 @@ async function createThreadTree(task) {
|
|
|
8620
9125
|
blocks: treeBlocks(text),
|
|
8621
9126
|
unfurl_links: false,
|
|
8622
9127
|
unfurl_media: false,
|
|
8623
|
-
...agent ? { username: getAgentDisplayName(agent),
|
|
9128
|
+
...agent ? { username: getAgentDisplayName(agent), ...getAgentSlackIcon(agent) } : {},
|
|
8624
9129
|
metadata: {
|
|
8625
9130
|
event_type: SLACK_RENDER_METADATA_EVENT,
|
|
8626
9131
|
event_payload: { message_id: reservation.id, kind: "tree" }
|
|
@@ -9035,10 +9540,8 @@ async function streamOutcomeCard(task, tree, options) {
|
|
|
9035
9540
|
markdown_text: presentation
|
|
9036
9541
|
};
|
|
9037
9542
|
const agent = task.agentId ? await getAgentById2(task.agentId) : undefined;
|
|
9038
|
-
|
|
9039
|
-
|
|
9040
|
-
startPayload.icon_emoji = getAgentEmoji(agent);
|
|
9041
|
-
}
|
|
9543
|
+
const persona = agent ? { username: getAgentDisplayName(agent), ...getAgentSlackIcon(agent) } : {};
|
|
9544
|
+
Object.assign(startPayload, persona);
|
|
9042
9545
|
if (!task.slackChannelId.startsWith("D") && task.slackUserId) {
|
|
9043
9546
|
const teamId = await slackTeamId(app.client);
|
|
9044
9547
|
if (teamId) {
|
|
@@ -9081,8 +9584,7 @@ async function streamOutcomeCard(task, tree, options) {
|
|
|
9081
9584
|
thread_ts: task.slackThreadTs,
|
|
9082
9585
|
text: presentation,
|
|
9083
9586
|
blocks: [{ type: "markdown", text: presentation }, ...captions],
|
|
9084
|
-
...
|
|
9085
|
-
...startPayload.icon_emoji ? { icon_emoji: startPayload.icon_emoji } : {}
|
|
9587
|
+
...persona
|
|
9086
9588
|
});
|
|
9087
9589
|
deliveredViaFallback = true;
|
|
9088
9590
|
}
|
|
@@ -9721,7 +10223,7 @@ async function postInitialDMTreeMessage(task) {
|
|
|
9721
10223
|
unfurl_links: false,
|
|
9722
10224
|
unfurl_media: false,
|
|
9723
10225
|
username: getAgentDisplayName(agent),
|
|
9724
|
-
|
|
10226
|
+
...getAgentSlackIcon(agent),
|
|
9725
10227
|
blocks
|
|
9726
10228
|
});
|
|
9727
10229
|
if (result.ts) {
|
|
@@ -10018,6 +10520,7 @@ function stopTaskWatcher() {
|
|
|
10018
10520
|
var app = null;
|
|
10019
10521
|
var receiver = null;
|
|
10020
10522
|
var initialized2 = false;
|
|
10523
|
+
var inboundDrain = null;
|
|
10021
10524
|
var SOCKET_EVENT_STATES = {
|
|
10022
10525
|
connecting: "connecting",
|
|
10023
10526
|
reconnecting: "connecting",
|
|
@@ -10083,19 +10586,20 @@ async function initSlackApp2() {
|
|
|
10083
10586
|
logLevel,
|
|
10084
10587
|
...clientOptions ? { clientOptions } : {}
|
|
10085
10588
|
});
|
|
10589
|
+
inboundDrain = installSocketAckRecovery(receiver.client, app);
|
|
10086
10590
|
initialized2 = true;
|
|
10087
10591
|
app.use(slackInboundOutcomeMiddleware());
|
|
10088
|
-
const { registerMessageHandler } = await import("./handlers-
|
|
10089
|
-
const { registerCommandHandler } = await import("./commands-
|
|
10090
|
-
const { registerActionHandlers } = await import("./actions-
|
|
10091
|
-
const { registerWorkObjectHandlers } = await import("./work-objects-
|
|
10592
|
+
const { registerMessageHandler } = await import("./handlers-ss5948rq.js");
|
|
10593
|
+
const { registerCommandHandler } = await import("./commands-hwdhacfx.js");
|
|
10594
|
+
const { registerActionHandlers } = await import("./actions-a90cfpca.js");
|
|
10595
|
+
const { registerWorkObjectHandlers } = await import("./work-objects-x7rb53qn.js");
|
|
10092
10596
|
registerMessageHandler(app);
|
|
10093
10597
|
registerCommandHandler(app);
|
|
10094
10598
|
registerActionHandlers(app);
|
|
10095
10599
|
registerWorkObjectHandlers(app);
|
|
10096
|
-
const { createAssistant } = await import("./assistant-
|
|
10600
|
+
const { createAssistant } = await import("./assistant-ck01q2yg.js");
|
|
10097
10601
|
app.assistant(createAssistant());
|
|
10098
|
-
const { isBlockExternalEnabled, scanExternalChannelsOnBoot } = await import("./external-channel-
|
|
10602
|
+
const { isBlockExternalEnabled, scanExternalChannelsOnBoot } = await import("./external-channel-g6vv85zv.js");
|
|
10099
10603
|
if (isBlockExternalEnabled()) {
|
|
10100
10604
|
scanExternalChannelsOnBoot(app.client).catch((error) => {
|
|
10101
10605
|
console.error("[Slack] External channel boot scan failed:", error);
|
|
@@ -10108,11 +10612,13 @@ async function startSlackApp2() {
|
|
|
10108
10612
|
await initSlackApp2();
|
|
10109
10613
|
}
|
|
10110
10614
|
if (app) {
|
|
10111
|
-
const { isSlackRenderV2Enabled } = await import("./render-v2-
|
|
10615
|
+
const { isSlackRenderV2Enabled } = await import("./render-v2-65x4ayj8.js");
|
|
10112
10616
|
if (isSlackRenderV2Enabled())
|
|
10113
10617
|
await ensureSlackRenderV2Activation2();
|
|
10618
|
+
await recoverSlackInboundAfterRestart();
|
|
10114
10619
|
await app.start();
|
|
10115
10620
|
console.log("[Slack] Bot connected via Socket Mode");
|
|
10621
|
+
inboundDrain?.wake();
|
|
10116
10622
|
await emitBuiltInIntegrationConnectedOnce2("slack");
|
|
10117
10623
|
await startTaskWatcher();
|
|
10118
10624
|
return true;
|
|
@@ -10121,6 +10627,8 @@ async function startSlackApp2() {
|
|
|
10121
10627
|
}
|
|
10122
10628
|
async function stopSlackApp2() {
|
|
10123
10629
|
stopTaskWatcher();
|
|
10630
|
+
inboundDrain?.stop();
|
|
10631
|
+
inboundDrain = null;
|
|
10124
10632
|
if (app) {
|
|
10125
10633
|
await app.stop();
|
|
10126
10634
|
app = null;
|
|
@@ -10131,4 +10639,4 @@ async function stopSlackApp2() {
|
|
|
10131
10639
|
initialized2 = false;
|
|
10132
10640
|
}
|
|
10133
10641
|
|
|
10134
|
-
export { require_dist4, getSlackConnectionState, noteSlackInboundSideEffect, ignoreSlackInbound, reportSlackInboundFailure, isAdmittedSlackDelivery, getSlackInboundDiagnostics, terminalReactionEvent, isPollTracingEnabled, initOtel, withSpan2, startSpan2, withSpanContext2, withRemoteContext2, injectTraceContext2, recordSessionCost2, recordDbRetentionSweep2, recordDbRetentionStatement2, slackTaskOutput, ackSlackMessage, getTaskLink, getTaskUrl, markdownToSlack, buildMrkdwnSectionBlocks, buildCaptionBlock, buildCancelledBlocks, buildBufferFlushBlocks, buildTreeBlocks, taskCitationIssues, stripInvalidTaskCitations, taskCitationSourceGroups, renderTaskCitations, taskCitationWarnings, MAX_TASK_CITATIONS, CitationInputSchema, TaskCitationSchema, upsertTaskCitations, getTaskCitations, getTaskCitationsForTasks, hasTaskCitationCheckRefusal, initialize, ensure, getAgentDisplayName,
|
|
10642
|
+
export { require_dist4, getSlackConnectionState, noteSlackInboundSideEffect, ignoreSlackInbound, reportSlackInboundFailure, isAdmittedSlackDelivery, getSlackInboundDiagnostics, terminalReactionEvent, isPollTracingEnabled, initOtel, withSpan2, startSpan2, withSpanContext2, withRemoteContext2, injectTraceContext2, recordSessionCost2, recordDbRetentionSweep2, recordDbRetentionStatement2, slackTaskOutput, ackSlackMessage, getTaskLink, getTaskUrl, markdownToSlack, buildMrkdwnSectionBlocks, buildCaptionBlock, buildCancelledBlocks, buildBufferFlushBlocks, buildTreeBlocks, taskCitationIssues, stripInvalidTaskCitations, taskCitationSourceGroups, renderTaskCitations, taskCitationWarnings, MAX_TASK_CITATIONS, CitationInputSchema, TaskCitationSchema, upsertTaskCitations, getTaskCitations, getTaskCitationsForTasks, hasTaskCitationCheckRefusal, initialize, ensure, getAgentDisplayName, getAgentSlackIcon, markSlackSessionProcessing, isSlackRenderV2Enabled2, callSlackWithRetry2, ensureSlackThreadTree2, slackErrorCode2, processSlackRenderV22, registerTreeMessage, getSlackApp2, initSlackApp2, startSlackApp2, stopSlackApp2 };
|