@sentry/junior 0.105.0 → 0.107.0
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/dist/{agent-hooks-EOFSY2PD.js → agent-hooks-ICPIJAFY.js} +9 -7
- package/dist/api/conversations/detail.d.ts +1 -1
- package/dist/api/conversations/events.d.ts +14 -0
- package/dist/api/conversations/schema.d.ts +196 -463
- package/dist/api/schema.d.ts +2 -7
- package/dist/api/schema.js +10 -8
- package/dist/api.js +377 -810
- package/dist/app.js +2284 -2288
- package/dist/{catalog-runtime-5CVM2DOF.js → catalog-runtime-FOFNPR3P.js} +3 -2
- package/dist/chat/agent/prompt.d.ts +1 -1
- package/dist/chat/agent/request.d.ts +28 -29
- package/dist/chat/agent/resume.d.ts +7 -7
- package/dist/chat/agent/session.d.ts +5 -6
- package/dist/chat/agent/tools.d.ts +3 -3
- package/dist/chat/agent-dispatch/runner.d.ts +2 -0
- package/dist/chat/config.d.ts +3 -2
- package/dist/chat/conversations/history.d.ts +582 -167
- package/dist/chat/conversations/message-projection.d.ts +6 -0
- package/dist/chat/conversations/message-summaries.d.ts +9 -0
- package/dist/chat/conversations/messages.d.ts +13 -27
- package/dist/chat/conversations/projection.d.ts +30 -53
- package/dist/chat/conversations/provenance.d.ts +42 -0
- package/dist/chat/conversations/search.d.ts +2 -2
- package/dist/chat/conversations/sql/conversation-row.d.ts +1 -1
- package/dist/chat/conversations/sql/event-lock.d.ts +3 -0
- package/dist/chat/conversations/sql/history.d.ts +3 -3
- package/dist/chat/conversations/sql/privacy.d.ts +27 -0
- package/dist/chat/conversations/sql/purge.d.ts +2 -10
- package/dist/chat/conversations/sql/store.d.ts +0 -5
- package/dist/chat/conversations/store.d.ts +8 -13
- package/dist/chat/conversations/turn-lifecycle.d.ts +41 -0
- package/dist/chat/db.d.ts +4 -10
- package/dist/chat/model-profile.d.ts +10 -0
- package/dist/chat/oauth-flow.d.ts +0 -5
- package/dist/chat/pi/conversation-events.d.ts +33 -0
- package/dist/chat/pi/sql-model-usage.d.ts +10 -0
- package/dist/chat/plugins/agent-hooks.d.ts +4 -2
- package/dist/chat/resource-events/ingest.d.ts +0 -13
- package/dist/chat/runtime/delivered-turn-state.d.ts +1 -1
- package/dist/chat/runtime/generated-artifacts.d.ts +1 -1
- package/dist/chat/runtime/reply-executor.d.ts +2 -0
- package/dist/chat/runtime/slack-resume.d.ts +23 -28
- package/dist/chat/runtime/slack-runtime.d.ts +2 -0
- package/dist/chat/runtime/turn.d.ts +14 -1
- package/dist/chat/services/context-compaction-marker.d.ts +0 -1
- package/dist/chat/services/context-compaction.d.ts +1 -0
- package/dist/chat/services/conversation-memory.d.ts +9 -0
- package/dist/chat/services/plugin-auth-orchestration.d.ts +1 -4
- package/dist/chat/services/subscribed-decision.d.ts +1 -1
- package/dist/chat/services/turn-failure-response.d.ts +10 -3
- package/dist/chat/services/turn-limit.d.ts +6 -0
- package/dist/chat/services/turn-result.d.ts +7 -12
- package/dist/chat/services/{turn-reasoning-level.d.ts → turn-router.d.ts} +12 -8
- package/dist/chat/services/turn-session-record.d.ts +15 -17
- package/dist/chat/slack/adapter.d.ts +2 -2
- package/dist/chat/slack/errors.d.ts +2 -0
- package/dist/chat/slack/outbound.d.ts +0 -1
- package/dist/chat/slack/reply.d.ts +2 -8
- package/dist/chat/slack/tools/channel-capabilities.d.ts +2 -2
- package/dist/chat/slack/tools/{send-message.d.ts → send-files.d.ts} +27 -19
- package/dist/chat/state/conversation.d.ts +4 -4
- package/dist/chat/state/turn-id.d.ts +2 -0
- package/dist/chat/state/turn-session-keys.d.ts +6 -0
- package/dist/chat/state/turn-session.d.ts +11 -9
- package/dist/chat/task-execution/state.d.ts +6 -1
- package/dist/chat/task-execution/store.d.ts +1 -1
- package/dist/chat/tool-support/pi-tool-adapter.d.ts +1 -1
- package/dist/chat/tool-support/tool-execution-report.d.ts +1 -0
- package/dist/chat/tools/handoff/tool.d.ts +2 -2
- package/dist/chat/tools/sandbox/file-uploads.d.ts +28 -6
- package/dist/chat/tools/types.d.ts +6 -9
- package/dist/chat/tools/web/image-generate.d.ts +4 -6
- package/dist/{chunk-QDKRE3LS.js → chunk-4YF7Z6IA.js} +390 -270
- package/dist/{chunk-4PDVOHXP.js → chunk-AUUOHQAT.js} +2 -2
- package/dist/chunk-B2Z2H66D.js +250 -0
- package/dist/{chunk-QVTVCJR4.js → chunk-CQ7KSO2B.js} +75 -45
- package/dist/{chunk-MJSJAHBW.js → chunk-DY7TRYB5.js} +1 -1
- package/dist/{chunk-NJJFU6CP.js → chunk-EDLNHZH3.js} +883 -898
- package/dist/{chunk-O7ILGCMJ.js → chunk-IGHMVDWI.js} +134 -18
- package/dist/chunk-MU6HHZEN.js +99 -0
- package/dist/{chunk-BCULHGZK.js → chunk-NVOTGWYX.js} +458 -684
- package/dist/{chunk-AEWZ7F65.js → chunk-O24R4DCK.js} +2 -179
- package/dist/{chunk-CCFROYAV.js → chunk-PUAMO4PI.js} +115 -125
- package/dist/{chunk-VDHMFCDY.js → chunk-RMVOAJRL.js} +30 -13
- package/dist/{chunk-7G4J3CR7.js → chunk-SPUAJVVH.js} +6 -4
- package/dist/{chunk-M3UAVLEN.js → chunk-SS67LUOK.js} +43 -290
- package/dist/{chunk-FXFQNHRU.js → chunk-VFUK3X5B.js} +4 -2
- package/dist/{chunk-CCTCIISK.js → chunk-VH6KWKG2.js} +2 -2
- package/dist/chunk-VIXFG2VC.js +182 -0
- package/dist/{chunk-RMZ65YAA.js → chunk-YFQ7CQDE.js} +687 -21
- package/dist/{chunk-77LHNQK4.js → chunk-YIPD3L6L.js} +4 -2
- package/dist/{chunk-U26ZWZCN.js → chunk-YNP2ATQX.js} +6 -4
- package/dist/{chunk-WR7H7VLJ.js → chunk-YT72TOEK.js} +2 -2
- package/dist/cli/chat.js +21 -20
- package/dist/cli/check.js +4 -3
- package/dist/cli/plugins.js +11 -9
- package/dist/cli/snapshot-warmup.js +7 -5
- package/dist/cli/upgrade.js +2046 -105
- package/dist/db/schema/{agent-steps.d.ts → conversation-events.d.ts} +37 -21
- package/dist/db/schema.d.ts +28 -159
- package/dist/{db-PDMC67T3.js → db-DIGO4TGW.js} +6 -8
- package/dist/{runner-6A7MQRUE.js → runner-ACR2HAIC.js} +209 -101
- package/dist/{skills-722AXRV5.js → skills-ITNHBARB.js} +4 -3
- package/dist/{validation-EUI2UFRM.js → validation-AGQ46ZGV.js} +4 -3
- package/migrations/0005_conversation_events.sql +122 -0
- package/migrations/README.md +23 -10
- package/migrations/meta/0005_snapshot.json +948 -0
- package/migrations/meta/_journal.json +7 -0
- package/package.json +6 -6
- package/dist/api/conversations/activity.d.ts +0 -40
- package/dist/api/conversations/detail-projection.d.ts +0 -11
- package/dist/api/conversations/detail.query.d.ts +0 -3
- package/dist/api/conversations/subagent.d.ts +0 -10
- package/dist/api/conversations/transcript.d.ts +0 -28
- package/dist/chat/conversations/legacy-advisor-session.d.ts +0 -7
- package/dist/chat/conversations/legacy-import.d.ts +0 -38
- package/dist/chat/conversations/sql/legacy-history-import.d.ts +0 -55
- package/dist/chat/conversations/sql/messages.d.ts +0 -4
- package/dist/chat/conversations/visible-compactions.d.ts +0 -11
- package/dist/chat/conversations/visible-messages.d.ts +0 -47
- package/dist/chat/services/reply-delivery-plan.d.ts +0 -5
- package/dist/chat/state/session-log.d.ts +0 -384
- package/dist/chunk-RYDF4GOX.js +0 -1072
- package/dist/chunk-XIMUQ4IU.js +0 -147
- package/dist/db/schema/conversation-messages.d.ts +0 -153
- package/dist/handlers/github-webhook/check-suite.d.ts +0 -3
- package/dist/handlers/github-webhook/issue-comment.d.ts +0 -3
- package/dist/handlers/github-webhook/pull-request-review-comment.d.ts +0 -3
- package/dist/handlers/github-webhook/pull-request-review.d.ts +0 -3
- package/dist/handlers/github-webhook/pull-request.d.ts +0 -3
- package/dist/handlers/github-webhook/resource.d.ts +0 -10
- package/dist/handlers/github-webhook.d.ts +0 -15
- package/dist/legacy-import-G333RHJZ.js +0 -18
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
normalizeGenAiFinishReason,
|
|
13
13
|
serializeGenAiAttribute,
|
|
14
14
|
withSpan
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-O24R4DCK.js";
|
|
16
16
|
|
|
17
17
|
// src/chat/xml.ts
|
|
18
18
|
function escapeXml(value) {
|
|
@@ -75,6 +75,13 @@ var TURN_CONTEXT_TAG = "runtime-turn-context";
|
|
|
75
75
|
|
|
76
76
|
// src/chat/pi/transcript.ts
|
|
77
77
|
var RUNTIME_TURN_CONTEXT_START = `<${TURN_CONTEXT_TAG}>`;
|
|
78
|
+
function userMessageContent(message) {
|
|
79
|
+
const record = message;
|
|
80
|
+
return record.role === "user" && Array.isArray(record.content) ? record.content : void 0;
|
|
81
|
+
}
|
|
82
|
+
function isRuntimeTurnContextPart(part) {
|
|
83
|
+
return part !== null && typeof part === "object" && part.type === "text" && typeof part.text === "string" && part.text.startsWith(RUNTIME_TURN_CONTEXT_START);
|
|
84
|
+
}
|
|
78
85
|
var EMBEDDED_THREAD_CONTEXT_TAGS = [
|
|
79
86
|
"recent-thread-messages",
|
|
80
87
|
"thread-compactions",
|
|
@@ -120,14 +127,14 @@ function extractAssistantText(message) {
|
|
|
120
127
|
).map((part) => part.text).join("\n");
|
|
121
128
|
}
|
|
122
129
|
function getTerminalAssistantMessages(messages) {
|
|
123
|
-
let
|
|
130
|
+
let lastNonAssistantIndex = -1;
|
|
124
131
|
for (let index = messages.length - 1; index >= 0; index -= 1) {
|
|
125
|
-
if (
|
|
126
|
-
|
|
132
|
+
if (!isAssistantMessage(messages[index])) {
|
|
133
|
+
lastNonAssistantIndex = index;
|
|
127
134
|
break;
|
|
128
135
|
}
|
|
129
136
|
}
|
|
130
|
-
return messages.slice(
|
|
137
|
+
return messages.slice(lastNonAssistantIndex + 1).filter(isAssistantMessage);
|
|
131
138
|
}
|
|
132
139
|
function trimTrailingAssistantMessages(messages) {
|
|
133
140
|
let end = messages.length;
|
|
@@ -136,27 +143,14 @@ function trimTrailingAssistantMessages(messages) {
|
|
|
136
143
|
}
|
|
137
144
|
return end === messages.length ? [...messages] : messages.slice(0, end);
|
|
138
145
|
}
|
|
139
|
-
function getUserMessageContent(message) {
|
|
140
|
-
const record = message;
|
|
141
|
-
return record.role === "user" && Array.isArray(record.content) ? record.content : void 0;
|
|
142
|
-
}
|
|
143
|
-
function isRuntimeTurnContextPart(part) {
|
|
144
|
-
return part !== null && typeof part === "object" && part.type === "text" && typeof part.text === "string" && part.text.startsWith(RUNTIME_TURN_CONTEXT_START);
|
|
145
|
-
}
|
|
146
146
|
function hasRuntimeTurnContext(messages) {
|
|
147
147
|
return messages.some(
|
|
148
|
-
(message) =>
|
|
149
|
-
(part) => isRuntimeTurnContextPart(part)
|
|
150
|
-
)
|
|
148
|
+
(message) => userMessageContent(message)?.some(isRuntimeTurnContextPart)
|
|
151
149
|
);
|
|
152
150
|
}
|
|
153
151
|
function retainRuntimeTurnContext(messages) {
|
|
154
152
|
return messages.flatMap((message) => {
|
|
155
|
-
const
|
|
156
|
-
if (!content) {
|
|
157
|
-
return [];
|
|
158
|
-
}
|
|
159
|
-
const runtimeContent = content.filter(isRuntimeTurnContextPart);
|
|
153
|
+
const runtimeContent = userMessageContent(message)?.filter(isRuntimeTurnContextPart) ?? [];
|
|
160
154
|
return runtimeContent.length > 0 ? [{ ...message, content: runtimeContent }] : [];
|
|
161
155
|
});
|
|
162
156
|
}
|
|
@@ -166,19 +160,13 @@ function instructionTextForProjection(text) {
|
|
|
166
160
|
}
|
|
167
161
|
function stripRuntimeTurnContext(messages) {
|
|
168
162
|
return messages.flatMap((message) => {
|
|
169
|
-
const content =
|
|
170
|
-
if (!content)
|
|
171
|
-
return [message];
|
|
172
|
-
}
|
|
163
|
+
const content = userMessageContent(message);
|
|
164
|
+
if (!content) return [message];
|
|
173
165
|
const nextContent = content.filter(
|
|
174
166
|
(part) => !isRuntimeTurnContextPart(part)
|
|
175
167
|
);
|
|
176
|
-
if (nextContent.length === content.length)
|
|
177
|
-
|
|
178
|
-
}
|
|
179
|
-
if (nextContent.length === 0) {
|
|
180
|
-
return [];
|
|
181
|
-
}
|
|
168
|
+
if (nextContent.length === content.length) return [message];
|
|
169
|
+
if (nextContent.length === 0) return [];
|
|
182
170
|
return [{ ...message, content: nextContent }];
|
|
183
171
|
});
|
|
184
172
|
}
|
|
@@ -260,11 +248,10 @@ function nextProviderRetry(args) {
|
|
|
260
248
|
|
|
261
249
|
// src/chat/services/context-compaction-marker.ts
|
|
262
250
|
var COMPACTION_SUMMARY_PREFIX = "Context compaction summary for future Junior turns:";
|
|
263
|
-
var LEGACY_COMPACTION_SUMMARY_PREFIX = "Context handoff summary for future Junior turns:";
|
|
264
251
|
var MODEL_HANDOFF_SUMMARY_PREFIX = "Model handoff checkpoint. Continue the outstanding request now using this summary as the complete prior context:";
|
|
265
252
|
function isCompactionSummaryText(text) {
|
|
266
253
|
const normalized = (unwrapCurrentInstruction(text) ?? text).trimStart();
|
|
267
|
-
return normalized.startsWith(COMPACTION_SUMMARY_PREFIX) || normalized.startsWith(
|
|
254
|
+
return normalized.startsWith(COMPACTION_SUMMARY_PREFIX) || normalized.startsWith(MODEL_HANDOFF_SUMMARY_PREFIX);
|
|
268
255
|
}
|
|
269
256
|
function hasCompactedConversationContext(messages) {
|
|
270
257
|
return messages.some((message) => {
|
|
@@ -583,19 +570,23 @@ var ModelProfileNotConfiguredError = class extends Error {
|
|
|
583
570
|
}
|
|
584
571
|
};
|
|
585
572
|
function modelIdForProfile(config, profile) {
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
573
|
+
return profileConfig(config, profile).modelId;
|
|
574
|
+
}
|
|
575
|
+
function standardModelId(config) {
|
|
576
|
+
return modelIdForProfile(config, STANDARD_MODEL_PROFILE);
|
|
577
|
+
}
|
|
578
|
+
function profileConfig(config, profile) {
|
|
579
|
+
const profileConfig2 = Object.hasOwn(config.profiles, profile) ? config.profiles[profile] : void 0;
|
|
580
|
+
if (!profileConfig2) {
|
|
591
581
|
throw new ModelProfileNotConfiguredError(profile);
|
|
592
582
|
}
|
|
593
|
-
return
|
|
583
|
+
return profileConfig2;
|
|
594
584
|
}
|
|
595
585
|
|
|
596
586
|
// src/chat/config.ts
|
|
597
587
|
var MIN_AGENT_TURN_TIMEOUT_MS = 10 * 1e3;
|
|
598
588
|
var DEFAULT_AGENT_TURN_TIMEOUT_MS = 12 * 60 * 1e3;
|
|
589
|
+
var MAX_SLICES_PER_TURN = 100;
|
|
599
590
|
var DEFAULT_FUNCTION_MAX_DURATION_SECONDS = 300;
|
|
600
591
|
var DEFAULT_SLACK_SLASH_COMMAND = "/jr";
|
|
601
592
|
var DEFAULT_PROCESSING_REACTION_EMOJI = "eyes";
|
|
@@ -678,10 +669,10 @@ function parseSlashCommand(rawValue) {
|
|
|
678
669
|
}
|
|
679
670
|
return command;
|
|
680
671
|
}
|
|
681
|
-
var DEFAULT_MODEL_ID = getModel("vercel-ai-gateway", "
|
|
672
|
+
var DEFAULT_MODEL_ID = getModel("vercel-ai-gateway", "xai/grok-4.5").id;
|
|
682
673
|
var DEFAULT_FAST_MODEL_ID = getModel(
|
|
683
674
|
"vercel-ai-gateway",
|
|
684
|
-
"
|
|
675
|
+
"anthropic/claude-haiku-4.5"
|
|
685
676
|
).id;
|
|
686
677
|
var DEFAULT_HANDOFF_MODEL_ID = getModel(
|
|
687
678
|
"vercel-ai-gateway",
|
|
@@ -697,9 +688,13 @@ function validateGatewayModelId(raw) {
|
|
|
697
688
|
function validateEmbeddingModelId(raw) {
|
|
698
689
|
return toOptionalTrimmed(raw);
|
|
699
690
|
}
|
|
700
|
-
function
|
|
691
|
+
function parseProfiles(rawValue, standardModelId2, handoffModelId) {
|
|
701
692
|
const profiles = {
|
|
702
|
-
[
|
|
693
|
+
[STANDARD_MODEL_PROFILE]: { modelId: standardModelId2 },
|
|
694
|
+
[DEFAULT_HANDOFF_MODEL_PROFILE]: {
|
|
695
|
+
modelId: handoffModelId,
|
|
696
|
+
reasoningLevel: "high"
|
|
697
|
+
}
|
|
703
698
|
};
|
|
704
699
|
const trimmed = toOptionalTrimmed(rawValue);
|
|
705
700
|
if (trimmed === void 0) {
|
|
@@ -730,7 +725,7 @@ function parseModelProfiles(rawValue, handoffModelId) {
|
|
|
730
725
|
if (!modelId) {
|
|
731
726
|
throw new Error(`AI_MODEL_PROFILES.${profile} must not be empty`);
|
|
732
727
|
}
|
|
733
|
-
profiles[profile] = modelId;
|
|
728
|
+
profiles[profile] = { modelId };
|
|
734
729
|
}
|
|
735
730
|
return profiles;
|
|
736
731
|
}
|
|
@@ -756,8 +751,7 @@ function readBotConfig(env) {
|
|
|
756
751
|
const handoffModelId = validateGatewayModelId(env.AI_HANDOFF_MODEL) ?? DEFAULT_HANDOFF_MODEL_ID;
|
|
757
752
|
return {
|
|
758
753
|
userName: toOptionalTrimmed(env.JUNIOR_BOT_NAME) ?? "junior",
|
|
759
|
-
modelId,
|
|
760
|
-
modelProfiles: parseModelProfiles(env.AI_MODEL_PROFILES, handoffModelId),
|
|
754
|
+
profiles: parseProfiles(env.AI_MODEL_PROFILES, modelId, handoffModelId),
|
|
761
755
|
modelContextWindowTokens: parseOptionalPositiveInteger(
|
|
762
756
|
"AI_MODEL_CONTEXT_WINDOW_TOKENS",
|
|
763
757
|
env.AI_MODEL_CONTEXT_WINDOW_TOKENS
|
|
@@ -767,6 +761,7 @@ function readBotConfig(env) {
|
|
|
767
761
|
embeddingModelId: validateEmbeddingModelId(env.AI_EMBEDDING_MODEL) ?? DEFAULT_EMBEDDING_MODEL_ID,
|
|
768
762
|
loadingMessages: parseLoadingMessages(env.JUNIOR_LOADING_MESSAGES),
|
|
769
763
|
visionModelId: validateGatewayModelId(env.AI_VISION_MODEL),
|
|
764
|
+
maxSlicesPerTurn: MAX_SLICES_PER_TURN,
|
|
770
765
|
turnTimeoutMs: parseAgentTurnTimeoutMs(
|
|
771
766
|
env.AGENT_TURN_TIMEOUT_MS,
|
|
772
767
|
maxTurnTimeoutMs
|
|
@@ -871,245 +866,6 @@ function setSlackReactionConfig(overrides) {
|
|
|
871
866
|
}
|
|
872
867
|
}
|
|
873
868
|
|
|
874
|
-
// src/chat/state/adapter.ts
|
|
875
|
-
import { createMemoryState } from "@chat-adapter/state-memory";
|
|
876
|
-
import { createRedisState } from "@chat-adapter/state-redis";
|
|
877
|
-
|
|
878
|
-
// src/chat/state/locks.ts
|
|
879
|
-
var ACTIVE_LOCK_TTL_MS = 9e4;
|
|
880
|
-
async function acquireActiveLock(state, threadId) {
|
|
881
|
-
return await state.acquireLock(threadId, ACTIVE_LOCK_TTL_MS);
|
|
882
|
-
}
|
|
883
|
-
|
|
884
|
-
// src/chat/state/adapter.ts
|
|
885
|
-
var ACTIVE_LOCK_HEARTBEAT_MS = 3e4;
|
|
886
|
-
var stateAdapter;
|
|
887
|
-
var redisStateAdapter;
|
|
888
|
-
function createPrefixedStateAdapter(base, prefix) {
|
|
889
|
-
const prefixed = (value) => `${prefix}:${value}`;
|
|
890
|
-
const unprefixed = (value) => value.startsWith(`${prefix}:`) ? value.slice(prefix.length + 1) : value;
|
|
891
|
-
const prefixLock = (lock) => ({
|
|
892
|
-
...lock,
|
|
893
|
-
threadId: prefixed(lock.threadId)
|
|
894
|
-
});
|
|
895
|
-
const unprefixLock = (lock) => ({
|
|
896
|
-
...lock,
|
|
897
|
-
threadId: unprefixed(lock.threadId)
|
|
898
|
-
});
|
|
899
|
-
return {
|
|
900
|
-
appendToList: (key, value, options) => base.appendToList(prefixed(key), value, options),
|
|
901
|
-
connect: () => base.connect(),
|
|
902
|
-
disconnect: () => base.disconnect(),
|
|
903
|
-
subscribe: (threadId) => base.subscribe(prefixed(threadId)),
|
|
904
|
-
unsubscribe: (threadId) => base.unsubscribe(prefixed(threadId)),
|
|
905
|
-
isSubscribed: (threadId) => base.isSubscribed(prefixed(threadId)),
|
|
906
|
-
acquireLock: async (threadId, ttlMs) => {
|
|
907
|
-
const lock = await base.acquireLock(prefixed(threadId), ttlMs);
|
|
908
|
-
return lock ? unprefixLock(lock) : null;
|
|
909
|
-
},
|
|
910
|
-
releaseLock: (lock) => base.releaseLock(prefixLock(lock)),
|
|
911
|
-
extendLock: async (lock, ttlMs) => {
|
|
912
|
-
const prefixedLock = prefixLock(lock);
|
|
913
|
-
const extended = await base.extendLock(prefixedLock, ttlMs);
|
|
914
|
-
if (extended) {
|
|
915
|
-
lock.expiresAt = prefixedLock.expiresAt;
|
|
916
|
-
}
|
|
917
|
-
return extended;
|
|
918
|
-
},
|
|
919
|
-
forceReleaseLock: (threadId) => base.forceReleaseLock(prefixed(threadId)),
|
|
920
|
-
enqueue: (threadId, entry, maxSize) => base.enqueue(prefixed(threadId), entry, maxSize),
|
|
921
|
-
dequeue: (threadId) => base.dequeue(prefixed(threadId)),
|
|
922
|
-
queueDepth: (threadId) => base.queueDepth(prefixed(threadId)),
|
|
923
|
-
get: (key) => base.get(prefixed(key)),
|
|
924
|
-
getList: (key) => base.getList(prefixed(key)),
|
|
925
|
-
set: (key, value, ttlMs) => base.set(prefixed(key), value, ttlMs),
|
|
926
|
-
setIfNotExists: (key, value, ttlMs) => base.setIfNotExists(prefixed(key), value, ttlMs),
|
|
927
|
-
delete: (key) => base.delete(prefixed(key))
|
|
928
|
-
};
|
|
929
|
-
}
|
|
930
|
-
function createQueuedStateAdapter(base, options) {
|
|
931
|
-
const heartbeats = /* @__PURE__ */ new Map();
|
|
932
|
-
const shouldHeartbeatLock = (ttlMs) => ttlMs === ACTIVE_LOCK_TTL_MS;
|
|
933
|
-
const heartbeatKey = (lock) => `${lock.threadId}:${lock.token}`;
|
|
934
|
-
const stopHeartbeatByKey = (key) => {
|
|
935
|
-
const heartbeat = heartbeats.get(key);
|
|
936
|
-
if (!heartbeat) {
|
|
937
|
-
return;
|
|
938
|
-
}
|
|
939
|
-
clearInterval(heartbeat.timer);
|
|
940
|
-
heartbeats.delete(key);
|
|
941
|
-
};
|
|
942
|
-
const stopHeartbeat = (lock) => {
|
|
943
|
-
stopHeartbeatByKey(heartbeatKey(lock));
|
|
944
|
-
};
|
|
945
|
-
const stopHeartbeatsForThread = (threadId) => {
|
|
946
|
-
for (const [key, heartbeat] of heartbeats) {
|
|
947
|
-
if (heartbeat.lock.threadId === threadId) {
|
|
948
|
-
stopHeartbeatByKey(key);
|
|
949
|
-
}
|
|
950
|
-
}
|
|
951
|
-
};
|
|
952
|
-
const stopAllHeartbeats = () => {
|
|
953
|
-
for (const key of heartbeats.keys()) {
|
|
954
|
-
stopHeartbeatByKey(key);
|
|
955
|
-
}
|
|
956
|
-
};
|
|
957
|
-
const runHeartbeat = async (key) => {
|
|
958
|
-
const heartbeat = heartbeats.get(key);
|
|
959
|
-
if (!heartbeat || heartbeat.inFlight) {
|
|
960
|
-
return;
|
|
961
|
-
}
|
|
962
|
-
heartbeat.inFlight = true;
|
|
963
|
-
try {
|
|
964
|
-
if (Date.now() - heartbeat.startedAtMs >= options.activeLockMaxAgeMs) {
|
|
965
|
-
stopHeartbeatByKey(key);
|
|
966
|
-
return;
|
|
967
|
-
}
|
|
968
|
-
const extended = await base.extendLock(heartbeat.lock, heartbeat.ttlMs);
|
|
969
|
-
if (!extended) {
|
|
970
|
-
stopHeartbeatByKey(key);
|
|
971
|
-
return;
|
|
972
|
-
}
|
|
973
|
-
heartbeat.lock.expiresAt = Date.now() + heartbeat.ttlMs;
|
|
974
|
-
} catch {
|
|
975
|
-
} finally {
|
|
976
|
-
const current = heartbeats.get(key);
|
|
977
|
-
if (current === heartbeat) {
|
|
978
|
-
current.inFlight = false;
|
|
979
|
-
}
|
|
980
|
-
}
|
|
981
|
-
};
|
|
982
|
-
const startOrUpdateHeartbeat = (lock, ttlMs) => {
|
|
983
|
-
const key = heartbeatKey(lock);
|
|
984
|
-
const existing = heartbeats.get(key);
|
|
985
|
-
if (existing) {
|
|
986
|
-
existing.ttlMs = ttlMs;
|
|
987
|
-
return;
|
|
988
|
-
}
|
|
989
|
-
const timer = setInterval(() => {
|
|
990
|
-
void runHeartbeat(key);
|
|
991
|
-
}, ACTIVE_LOCK_HEARTBEAT_MS);
|
|
992
|
-
timer.unref?.();
|
|
993
|
-
heartbeats.set(key, {
|
|
994
|
-
inFlight: false,
|
|
995
|
-
lock,
|
|
996
|
-
startedAtMs: Date.now(),
|
|
997
|
-
timer,
|
|
998
|
-
ttlMs
|
|
999
|
-
});
|
|
1000
|
-
};
|
|
1001
|
-
const acquireLock = async (threadId, ttlMs) => {
|
|
1002
|
-
const lock = await base.acquireLock(threadId, ttlMs);
|
|
1003
|
-
if (lock && shouldHeartbeatLock(ttlMs)) {
|
|
1004
|
-
startOrUpdateHeartbeat(lock, ttlMs);
|
|
1005
|
-
}
|
|
1006
|
-
return lock;
|
|
1007
|
-
};
|
|
1008
|
-
return {
|
|
1009
|
-
appendToList: (key, value, options2) => base.appendToList(key, value, options2),
|
|
1010
|
-
connect: () => base.connect(),
|
|
1011
|
-
disconnect: async () => {
|
|
1012
|
-
stopAllHeartbeats();
|
|
1013
|
-
await base.disconnect();
|
|
1014
|
-
},
|
|
1015
|
-
subscribe: (threadId) => base.subscribe(threadId),
|
|
1016
|
-
unsubscribe: (threadId) => base.unsubscribe(threadId),
|
|
1017
|
-
isSubscribed: (threadId) => base.isSubscribed(threadId),
|
|
1018
|
-
acquireLock,
|
|
1019
|
-
releaseLock: async (lock) => {
|
|
1020
|
-
stopHeartbeat(lock);
|
|
1021
|
-
await base.releaseLock(lock);
|
|
1022
|
-
},
|
|
1023
|
-
extendLock: async (lock, ttlMs) => {
|
|
1024
|
-
const extended = await base.extendLock(lock, ttlMs);
|
|
1025
|
-
if (extended) {
|
|
1026
|
-
lock.expiresAt = Date.now() + ttlMs;
|
|
1027
|
-
if (shouldHeartbeatLock(ttlMs)) {
|
|
1028
|
-
startOrUpdateHeartbeat(lock, ttlMs);
|
|
1029
|
-
} else {
|
|
1030
|
-
stopHeartbeat(lock);
|
|
1031
|
-
}
|
|
1032
|
-
} else {
|
|
1033
|
-
stopHeartbeat(lock);
|
|
1034
|
-
}
|
|
1035
|
-
return extended;
|
|
1036
|
-
},
|
|
1037
|
-
forceReleaseLock: async (threadId) => {
|
|
1038
|
-
stopHeartbeatsForThread(threadId);
|
|
1039
|
-
await base.forceReleaseLock(threadId);
|
|
1040
|
-
},
|
|
1041
|
-
enqueue: (threadId, entry, maxSize) => base.enqueue(threadId, entry, maxSize),
|
|
1042
|
-
dequeue: (threadId) => base.dequeue(threadId),
|
|
1043
|
-
queueDepth: (threadId) => base.queueDepth(threadId),
|
|
1044
|
-
get: (key) => base.get(key),
|
|
1045
|
-
getList: (key) => base.getList(key),
|
|
1046
|
-
set: (key, value, ttlMs) => base.set(key, value, ttlMs),
|
|
1047
|
-
setIfNotExists: (key, value, ttlMs) => base.setIfNotExists(key, value, ttlMs),
|
|
1048
|
-
delete: (key) => base.delete(key)
|
|
1049
|
-
};
|
|
1050
|
-
}
|
|
1051
|
-
function withOptionalPrefix(base, prefix) {
|
|
1052
|
-
return prefix ? createPrefixedStateAdapter(base, prefix) : base;
|
|
1053
|
-
}
|
|
1054
|
-
function createStateAdapter() {
|
|
1055
|
-
const config = getChatConfig();
|
|
1056
|
-
const activeLockMaxAgeMs = config.bot.turnTimeoutMs + ACTIVE_LOCK_TTL_MS;
|
|
1057
|
-
if (config.state.adapter === "memory") {
|
|
1058
|
-
redisStateAdapter = void 0;
|
|
1059
|
-
return createQueuedStateAdapter(
|
|
1060
|
-
withOptionalPrefix(createMemoryState(), config.state.keyPrefix),
|
|
1061
|
-
{ activeLockMaxAgeMs }
|
|
1062
|
-
);
|
|
1063
|
-
}
|
|
1064
|
-
if (!config.state.redisUrl) {
|
|
1065
|
-
throw new Error("REDIS_URL is required for durable Slack thread state");
|
|
1066
|
-
}
|
|
1067
|
-
const redisState = createRedisState({
|
|
1068
|
-
url: config.state.redisUrl
|
|
1069
|
-
});
|
|
1070
|
-
redisStateAdapter = redisState;
|
|
1071
|
-
return createQueuedStateAdapter(
|
|
1072
|
-
withOptionalPrefix(redisState, config.state.keyPrefix),
|
|
1073
|
-
{ activeLockMaxAgeMs }
|
|
1074
|
-
);
|
|
1075
|
-
}
|
|
1076
|
-
function getOptionalRedisStateAdapter() {
|
|
1077
|
-
getStateAdapter();
|
|
1078
|
-
return redisStateAdapter;
|
|
1079
|
-
}
|
|
1080
|
-
async function getConnectedStateContext() {
|
|
1081
|
-
const adapter = getStateAdapter();
|
|
1082
|
-
await adapter.connect();
|
|
1083
|
-
return {
|
|
1084
|
-
redisStateAdapter: getOptionalRedisStateAdapter(),
|
|
1085
|
-
stateAdapter: adapter
|
|
1086
|
-
};
|
|
1087
|
-
}
|
|
1088
|
-
async function getDefaultRedisStateAdapterFor(adapter) {
|
|
1089
|
-
if (adapter !== stateAdapter) {
|
|
1090
|
-
return void 0;
|
|
1091
|
-
}
|
|
1092
|
-
const context = await getConnectedStateContext();
|
|
1093
|
-
return context.stateAdapter === adapter ? context.redisStateAdapter : void 0;
|
|
1094
|
-
}
|
|
1095
|
-
function getStateAdapter() {
|
|
1096
|
-
if (!stateAdapter) {
|
|
1097
|
-
stateAdapter = createStateAdapter();
|
|
1098
|
-
}
|
|
1099
|
-
return stateAdapter;
|
|
1100
|
-
}
|
|
1101
|
-
async function disconnectStateAdapter() {
|
|
1102
|
-
if (!stateAdapter) {
|
|
1103
|
-
return;
|
|
1104
|
-
}
|
|
1105
|
-
try {
|
|
1106
|
-
await stateAdapter.disconnect();
|
|
1107
|
-
} finally {
|
|
1108
|
-
stateAdapter = void 0;
|
|
1109
|
-
redisStateAdapter = void 0;
|
|
1110
|
-
}
|
|
1111
|
-
}
|
|
1112
|
-
|
|
1113
869
|
export {
|
|
1114
870
|
toOptionalTrimmed,
|
|
1115
871
|
escapeXml,
|
|
@@ -1152,6 +908,8 @@ export {
|
|
|
1152
908
|
modelProfileSchema,
|
|
1153
909
|
ModelProfileNotConfiguredError,
|
|
1154
910
|
modelIdForProfile,
|
|
911
|
+
standardModelId,
|
|
912
|
+
profileConfig,
|
|
1155
913
|
FUNCTION_TIMEOUT_BUFFER_SECONDS,
|
|
1156
914
|
getChatConfig,
|
|
1157
915
|
botConfig,
|
|
@@ -1161,10 +919,5 @@ export {
|
|
|
1161
919
|
getSlackClientSecret,
|
|
1162
920
|
getRuntimeMetadata,
|
|
1163
921
|
getSlackReactionConfig,
|
|
1164
|
-
setSlackReactionConfig
|
|
1165
|
-
acquireActiveLock,
|
|
1166
|
-
getConnectedStateContext,
|
|
1167
|
-
getDefaultRedisStateAdapterFor,
|
|
1168
|
-
getStateAdapter,
|
|
1169
|
-
disconnectStateAdapter
|
|
922
|
+
setSlackReactionConfig
|
|
1170
923
|
};
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
+
// src/db/schema/destinations.ts
|
|
2
|
+
import { index, jsonb, pgTable, text, uniqueIndex } from "drizzle-orm/pg-core";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
|
|
1
5
|
// src/db/schema/timestamps.ts
|
|
2
6
|
import { timestamp } from "drizzle-orm/pg-core";
|
|
3
7
|
var timestamptz = (name) => timestamp(name, { withTimezone: true });
|
|
4
8
|
|
|
5
9
|
// src/db/schema/destinations.ts
|
|
6
|
-
import { index, jsonb, pgTable, text, uniqueIndex } from "drizzle-orm/pg-core";
|
|
7
|
-
import { z } from "zod";
|
|
8
10
|
var juniorDestinationKindSchema = z.enum([
|
|
9
11
|
"channel",
|
|
10
12
|
"dm",
|
|
@@ -3,13 +3,13 @@ import {
|
|
|
3
3
|
} from "./chunk-4ZNGQH7C.js";
|
|
4
4
|
import {
|
|
5
5
|
getSlackBotToken
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-SS67LUOK.js";
|
|
7
7
|
import {
|
|
8
8
|
logWarn,
|
|
9
9
|
setSpanAttributes,
|
|
10
10
|
setSpanStatus,
|
|
11
11
|
withSpan
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-O24R4DCK.js";
|
|
13
13
|
import {
|
|
14
14
|
parseSlackChannelReferenceId
|
|
15
15
|
} from "./chunk-7FBGKXPE.js";
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import {
|
|
2
|
+
parseSlackTeamId
|
|
3
|
+
} from "./chunk-7FBGKXPE.js";
|
|
4
|
+
|
|
5
|
+
// src/chat/actor.ts
|
|
6
|
+
import { z } from "zod";
|
|
7
|
+
import { actorSchema } from "@sentry/junior-plugin-api";
|
|
8
|
+
var SLACK_USER_ID_DISPLAY_PATTERN = /^[UW][A-Z0-9]{5,}$/;
|
|
9
|
+
var EMAIL_PATTERN = /^[^\s@<>]+@[^\s@<>]+\.[^\s@<>]+$/;
|
|
10
|
+
var exactStoredStringSchema = z.string().min(1).refine((value) => value === value.trim());
|
|
11
|
+
var storedSlackActorSchema = z.object({
|
|
12
|
+
email: exactStoredStringSchema.optional(),
|
|
13
|
+
fullName: exactStoredStringSchema.optional(),
|
|
14
|
+
platform: z.literal("slack").optional(),
|
|
15
|
+
slackUserId: exactStoredStringSchema.optional(),
|
|
16
|
+
slackUserName: exactStoredStringSchema.optional(),
|
|
17
|
+
teamId: exactStoredStringSchema.optional()
|
|
18
|
+
}).strict();
|
|
19
|
+
function isUserActor(actor) {
|
|
20
|
+
return Boolean(actor && "userId" in actor);
|
|
21
|
+
}
|
|
22
|
+
function clean(value) {
|
|
23
|
+
const trimmed = value?.trim();
|
|
24
|
+
return trimmed ? trimmed : void 0;
|
|
25
|
+
}
|
|
26
|
+
function isSyntheticActorUserId(value) {
|
|
27
|
+
return value.toLowerCase() === "unknown";
|
|
28
|
+
}
|
|
29
|
+
function isSlackUserId(value) {
|
|
30
|
+
return SLACK_USER_ID_DISPLAY_PATTERN.test(value);
|
|
31
|
+
}
|
|
32
|
+
function cleanActorDisplayName(value, userId) {
|
|
33
|
+
const displayName = clean(value);
|
|
34
|
+
if (!displayName) {
|
|
35
|
+
return void 0;
|
|
36
|
+
}
|
|
37
|
+
if (displayName.toLowerCase() === "unknown") {
|
|
38
|
+
return void 0;
|
|
39
|
+
}
|
|
40
|
+
if (userId && displayName === userId) {
|
|
41
|
+
return void 0;
|
|
42
|
+
}
|
|
43
|
+
return isSlackUserId(displayName) ? void 0 : displayName;
|
|
44
|
+
}
|
|
45
|
+
function cleanActorEmail(value) {
|
|
46
|
+
const email = clean(value);
|
|
47
|
+
return email && EMAIL_PATTERN.test(email) ? email : void 0;
|
|
48
|
+
}
|
|
49
|
+
function parseActorUserId(value) {
|
|
50
|
+
if (typeof value !== "string" || value.length === 0) {
|
|
51
|
+
return void 0;
|
|
52
|
+
}
|
|
53
|
+
if (value !== value.trim() || isSyntheticActorUserId(value)) {
|
|
54
|
+
return void 0;
|
|
55
|
+
}
|
|
56
|
+
return value;
|
|
57
|
+
}
|
|
58
|
+
function isActorUserId(value) {
|
|
59
|
+
return parseActorUserId(value) === value;
|
|
60
|
+
}
|
|
61
|
+
function createActor(input, context) {
|
|
62
|
+
const platform = context.platform ?? input?.platform;
|
|
63
|
+
if (!platform) {
|
|
64
|
+
return void 0;
|
|
65
|
+
}
|
|
66
|
+
const contextUserId = parseActorUserId(context.userId);
|
|
67
|
+
if (context.userId !== void 0 && !contextUserId) {
|
|
68
|
+
return void 0;
|
|
69
|
+
}
|
|
70
|
+
const inputUserId = parseActorUserId(input?.userId);
|
|
71
|
+
if (input?.userId !== void 0 && !inputUserId) {
|
|
72
|
+
return void 0;
|
|
73
|
+
}
|
|
74
|
+
const actorUserId = contextUserId ?? inputUserId;
|
|
75
|
+
if (!actorUserId) {
|
|
76
|
+
return void 0;
|
|
77
|
+
}
|
|
78
|
+
const contextTeamId = parseSlackTeamId(context.teamId);
|
|
79
|
+
if (context.teamId !== void 0 && !contextTeamId) {
|
|
80
|
+
return void 0;
|
|
81
|
+
}
|
|
82
|
+
const inputTeamId = parseSlackTeamId(input?.teamId);
|
|
83
|
+
if (input?.teamId !== void 0 && !inputTeamId) {
|
|
84
|
+
return void 0;
|
|
85
|
+
}
|
|
86
|
+
const actorTeamId = contextTeamId ?? inputTeamId;
|
|
87
|
+
if (platform === "slack" && !actorTeamId) {
|
|
88
|
+
return void 0;
|
|
89
|
+
}
|
|
90
|
+
const canUseInputProfile = (!contextUserId || !inputUserId || contextUserId === inputUserId) && (platform !== "slack" || !contextTeamId || !inputTeamId || contextTeamId === inputTeamId);
|
|
91
|
+
const actor = {
|
|
92
|
+
...canUseInputProfile && cleanActorEmail(input?.email) ? { email: cleanActorEmail(input?.email) } : {},
|
|
93
|
+
...canUseInputProfile && cleanActorDisplayName(input?.fullName, actorUserId) ? {
|
|
94
|
+
fullName: cleanActorDisplayName(input?.fullName, actorUserId)
|
|
95
|
+
} : {},
|
|
96
|
+
platform,
|
|
97
|
+
userId: actorUserId,
|
|
98
|
+
...canUseInputProfile && cleanActorDisplayName(input?.userName, actorUserId) ? {
|
|
99
|
+
userName: cleanActorDisplayName(input?.userName, actorUserId)
|
|
100
|
+
} : {}
|
|
101
|
+
};
|
|
102
|
+
if (platform === "slack") {
|
|
103
|
+
return { ...actor, platform, teamId: actorTeamId };
|
|
104
|
+
}
|
|
105
|
+
return { ...actor, platform };
|
|
106
|
+
}
|
|
107
|
+
function createSlackActor(teamId, userId, profile) {
|
|
108
|
+
const actorUserId = parseActorUserId(userId);
|
|
109
|
+
const actorTeamId = parseSlackTeamId(teamId);
|
|
110
|
+
if (!actorTeamId || !actorUserId) {
|
|
111
|
+
throw new Error("Slack actor requires team and user ids");
|
|
112
|
+
}
|
|
113
|
+
const actor = createActor(
|
|
114
|
+
{
|
|
115
|
+
email: profile?.email,
|
|
116
|
+
fullName: profile?.fullName,
|
|
117
|
+
platform: "slack",
|
|
118
|
+
teamId: actorTeamId,
|
|
119
|
+
userId: actorUserId,
|
|
120
|
+
userName: profile?.userName
|
|
121
|
+
},
|
|
122
|
+
{ teamId: actorTeamId, userId: actorUserId }
|
|
123
|
+
);
|
|
124
|
+
if (!actor || actor.platform !== "slack") {
|
|
125
|
+
throw new Error("Slack actor requires team and user ids");
|
|
126
|
+
}
|
|
127
|
+
return actor;
|
|
128
|
+
}
|
|
129
|
+
function parseStoredSlackActor(value) {
|
|
130
|
+
const parsed = storedSlackActorSchema.safeParse(value);
|
|
131
|
+
if (!parsed.success) {
|
|
132
|
+
return void 0;
|
|
133
|
+
}
|
|
134
|
+
if (parsed.data.slackUserId !== void 0 && !parseActorUserId(parsed.data.slackUserId)) {
|
|
135
|
+
return void 0;
|
|
136
|
+
}
|
|
137
|
+
if (parsed.data.teamId !== void 0 && !parseSlackTeamId(parsed.data.teamId)) {
|
|
138
|
+
return void 0;
|
|
139
|
+
}
|
|
140
|
+
if ((parsed.data.platform !== void 0 || parsed.data.teamId !== void 0) && (!parsed.data.platform || !parsed.data.teamId)) {
|
|
141
|
+
return void 0;
|
|
142
|
+
}
|
|
143
|
+
return parsed.data;
|
|
144
|
+
}
|
|
145
|
+
function toStoredSlackActor(actor) {
|
|
146
|
+
return {
|
|
147
|
+
...actor.email ? { email: actor.email } : {},
|
|
148
|
+
...actor.fullName ? { fullName: actor.fullName } : {},
|
|
149
|
+
platform: actor.platform,
|
|
150
|
+
slackUserId: actor.userId,
|
|
151
|
+
...actor.userName ? { slackUserName: actor.userName } : {},
|
|
152
|
+
teamId: actor.teamId
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
function createSlackResumeActor(args) {
|
|
156
|
+
if (args.actor) {
|
|
157
|
+
if (args.actor.platform !== "slack" || args.actor.teamId !== args.teamId || args.actor.userId !== args.userId) {
|
|
158
|
+
throw new Error("Stored Slack actor did not match resume actor");
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
const actor = createActor(args.actor, {
|
|
162
|
+
platform: "slack",
|
|
163
|
+
teamId: args.teamId,
|
|
164
|
+
userId: args.userId
|
|
165
|
+
});
|
|
166
|
+
if (!actor || actor.platform !== "slack") {
|
|
167
|
+
throw new Error("Slack actor requires team and user ids");
|
|
168
|
+
}
|
|
169
|
+
return actor;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
export {
|
|
173
|
+
storedSlackActorSchema,
|
|
174
|
+
isUserActor,
|
|
175
|
+
parseActorUserId,
|
|
176
|
+
isActorUserId,
|
|
177
|
+
createActor,
|
|
178
|
+
createSlackActor,
|
|
179
|
+
parseStoredSlackActor,
|
|
180
|
+
toStoredSlackActor,
|
|
181
|
+
createSlackResumeActor
|
|
182
|
+
};
|