@sentry/junior 0.106.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-KR5BCWOK.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 +3586 -3614
- 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 +2 -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-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 -16
- 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-DDRQ4U7I.js → chunk-4YF7Z6IA.js} +390 -270
- package/dist/{chunk-AZ5OMSN5.js → chunk-AUUOHQAT.js} +2 -2
- package/dist/chunk-B2Z2H66D.js +250 -0
- package/dist/{chunk-4W4O4DCV.js → chunk-CQ7KSO2B.js} +75 -45
- package/dist/{chunk-MJSJAHBW.js → chunk-DY7TRYB5.js} +1 -1
- package/dist/{chunk-GPPUTY5M.js → chunk-EDLNHZH3.js} +861 -891
- package/dist/{chunk-R5BFYK2O.js → chunk-IGHMVDWI.js} +134 -18
- package/dist/chunk-MU6HHZEN.js +99 -0
- package/dist/{chunk-XTKJPSMF.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-ZMRLBBD5.js → chunk-RMVOAJRL.js} +30 -13
- package/dist/{chunk-3NYUCBLE.js → chunk-SPUAJVVH.js} +6 -4
- package/dist/{chunk-4UYIRWDW.js → chunk-SS67LUOK.js} +41 -290
- package/dist/{chunk-FXFQNHRU.js → chunk-VFUK3X5B.js} +4 -2
- package/dist/{chunk-3MPPVPGZ.js → chunk-VH6KWKG2.js} +2 -2
- package/dist/chunk-VIXFG2VC.js +182 -0
- package/dist/{chunk-BKM4UXUD.js → chunk-YFQ7CQDE.js} +669 -18
- package/dist/{chunk-77LHNQK4.js → chunk-YIPD3L6L.js} +4 -2
- package/dist/{chunk-3OUSJPR7.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-S33LFWG2.js → db-DIGO4TGW.js} +6 -8
- package/dist/{runner-HA5XAL6K.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 +5 -5
- 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-P4P7O5WG.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-TMJISRKO.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,14 +570,17 @@ 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
|
|
@@ -679,10 +669,10 @@ function parseSlashCommand(rawValue) {
|
|
|
679
669
|
}
|
|
680
670
|
return command;
|
|
681
671
|
}
|
|
682
|
-
var DEFAULT_MODEL_ID = getModel("vercel-ai-gateway", "
|
|
672
|
+
var DEFAULT_MODEL_ID = getModel("vercel-ai-gateway", "xai/grok-4.5").id;
|
|
683
673
|
var DEFAULT_FAST_MODEL_ID = getModel(
|
|
684
674
|
"vercel-ai-gateway",
|
|
685
|
-
"
|
|
675
|
+
"anthropic/claude-haiku-4.5"
|
|
686
676
|
).id;
|
|
687
677
|
var DEFAULT_HANDOFF_MODEL_ID = getModel(
|
|
688
678
|
"vercel-ai-gateway",
|
|
@@ -698,9 +688,13 @@ function validateGatewayModelId(raw) {
|
|
|
698
688
|
function validateEmbeddingModelId(raw) {
|
|
699
689
|
return toOptionalTrimmed(raw);
|
|
700
690
|
}
|
|
701
|
-
function
|
|
691
|
+
function parseProfiles(rawValue, standardModelId2, handoffModelId) {
|
|
702
692
|
const profiles = {
|
|
703
|
-
[
|
|
693
|
+
[STANDARD_MODEL_PROFILE]: { modelId: standardModelId2 },
|
|
694
|
+
[DEFAULT_HANDOFF_MODEL_PROFILE]: {
|
|
695
|
+
modelId: handoffModelId,
|
|
696
|
+
reasoningLevel: "high"
|
|
697
|
+
}
|
|
704
698
|
};
|
|
705
699
|
const trimmed = toOptionalTrimmed(rawValue);
|
|
706
700
|
if (trimmed === void 0) {
|
|
@@ -731,7 +725,7 @@ function parseModelProfiles(rawValue, handoffModelId) {
|
|
|
731
725
|
if (!modelId) {
|
|
732
726
|
throw new Error(`AI_MODEL_PROFILES.${profile} must not be empty`);
|
|
733
727
|
}
|
|
734
|
-
profiles[profile] = modelId;
|
|
728
|
+
profiles[profile] = { modelId };
|
|
735
729
|
}
|
|
736
730
|
return profiles;
|
|
737
731
|
}
|
|
@@ -757,8 +751,7 @@ function readBotConfig(env) {
|
|
|
757
751
|
const handoffModelId = validateGatewayModelId(env.AI_HANDOFF_MODEL) ?? DEFAULT_HANDOFF_MODEL_ID;
|
|
758
752
|
return {
|
|
759
753
|
userName: toOptionalTrimmed(env.JUNIOR_BOT_NAME) ?? "junior",
|
|
760
|
-
modelId,
|
|
761
|
-
modelProfiles: parseModelProfiles(env.AI_MODEL_PROFILES, handoffModelId),
|
|
754
|
+
profiles: parseProfiles(env.AI_MODEL_PROFILES, modelId, handoffModelId),
|
|
762
755
|
modelContextWindowTokens: parseOptionalPositiveInteger(
|
|
763
756
|
"AI_MODEL_CONTEXT_WINDOW_TOKENS",
|
|
764
757
|
env.AI_MODEL_CONTEXT_WINDOW_TOKENS
|
|
@@ -873,245 +866,6 @@ function setSlackReactionConfig(overrides) {
|
|
|
873
866
|
}
|
|
874
867
|
}
|
|
875
868
|
|
|
876
|
-
// src/chat/state/adapter.ts
|
|
877
|
-
import { createMemoryState } from "@chat-adapter/state-memory";
|
|
878
|
-
import { createRedisState } from "@chat-adapter/state-redis";
|
|
879
|
-
|
|
880
|
-
// src/chat/state/locks.ts
|
|
881
|
-
var ACTIVE_LOCK_TTL_MS = 9e4;
|
|
882
|
-
async function acquireActiveLock(state, threadId) {
|
|
883
|
-
return await state.acquireLock(threadId, ACTIVE_LOCK_TTL_MS);
|
|
884
|
-
}
|
|
885
|
-
|
|
886
|
-
// src/chat/state/adapter.ts
|
|
887
|
-
var ACTIVE_LOCK_HEARTBEAT_MS = 3e4;
|
|
888
|
-
var stateAdapter;
|
|
889
|
-
var redisStateAdapter;
|
|
890
|
-
function createPrefixedStateAdapter(base, prefix) {
|
|
891
|
-
const prefixed = (value) => `${prefix}:${value}`;
|
|
892
|
-
const unprefixed = (value) => value.startsWith(`${prefix}:`) ? value.slice(prefix.length + 1) : value;
|
|
893
|
-
const prefixLock = (lock) => ({
|
|
894
|
-
...lock,
|
|
895
|
-
threadId: prefixed(lock.threadId)
|
|
896
|
-
});
|
|
897
|
-
const unprefixLock = (lock) => ({
|
|
898
|
-
...lock,
|
|
899
|
-
threadId: unprefixed(lock.threadId)
|
|
900
|
-
});
|
|
901
|
-
return {
|
|
902
|
-
appendToList: (key, value, options) => base.appendToList(prefixed(key), value, options),
|
|
903
|
-
connect: () => base.connect(),
|
|
904
|
-
disconnect: () => base.disconnect(),
|
|
905
|
-
subscribe: (threadId) => base.subscribe(prefixed(threadId)),
|
|
906
|
-
unsubscribe: (threadId) => base.unsubscribe(prefixed(threadId)),
|
|
907
|
-
isSubscribed: (threadId) => base.isSubscribed(prefixed(threadId)),
|
|
908
|
-
acquireLock: async (threadId, ttlMs) => {
|
|
909
|
-
const lock = await base.acquireLock(prefixed(threadId), ttlMs);
|
|
910
|
-
return lock ? unprefixLock(lock) : null;
|
|
911
|
-
},
|
|
912
|
-
releaseLock: (lock) => base.releaseLock(prefixLock(lock)),
|
|
913
|
-
extendLock: async (lock, ttlMs) => {
|
|
914
|
-
const prefixedLock = prefixLock(lock);
|
|
915
|
-
const extended = await base.extendLock(prefixedLock, ttlMs);
|
|
916
|
-
if (extended) {
|
|
917
|
-
lock.expiresAt = prefixedLock.expiresAt;
|
|
918
|
-
}
|
|
919
|
-
return extended;
|
|
920
|
-
},
|
|
921
|
-
forceReleaseLock: (threadId) => base.forceReleaseLock(prefixed(threadId)),
|
|
922
|
-
enqueue: (threadId, entry, maxSize) => base.enqueue(prefixed(threadId), entry, maxSize),
|
|
923
|
-
dequeue: (threadId) => base.dequeue(prefixed(threadId)),
|
|
924
|
-
queueDepth: (threadId) => base.queueDepth(prefixed(threadId)),
|
|
925
|
-
get: (key) => base.get(prefixed(key)),
|
|
926
|
-
getList: (key) => base.getList(prefixed(key)),
|
|
927
|
-
set: (key, value, ttlMs) => base.set(prefixed(key), value, ttlMs),
|
|
928
|
-
setIfNotExists: (key, value, ttlMs) => base.setIfNotExists(prefixed(key), value, ttlMs),
|
|
929
|
-
delete: (key) => base.delete(prefixed(key))
|
|
930
|
-
};
|
|
931
|
-
}
|
|
932
|
-
function createQueuedStateAdapter(base, options) {
|
|
933
|
-
const heartbeats = /* @__PURE__ */ new Map();
|
|
934
|
-
const shouldHeartbeatLock = (ttlMs) => ttlMs === ACTIVE_LOCK_TTL_MS;
|
|
935
|
-
const heartbeatKey = (lock) => `${lock.threadId}:${lock.token}`;
|
|
936
|
-
const stopHeartbeatByKey = (key) => {
|
|
937
|
-
const heartbeat = heartbeats.get(key);
|
|
938
|
-
if (!heartbeat) {
|
|
939
|
-
return;
|
|
940
|
-
}
|
|
941
|
-
clearInterval(heartbeat.timer);
|
|
942
|
-
heartbeats.delete(key);
|
|
943
|
-
};
|
|
944
|
-
const stopHeartbeat = (lock) => {
|
|
945
|
-
stopHeartbeatByKey(heartbeatKey(lock));
|
|
946
|
-
};
|
|
947
|
-
const stopHeartbeatsForThread = (threadId) => {
|
|
948
|
-
for (const [key, heartbeat] of heartbeats) {
|
|
949
|
-
if (heartbeat.lock.threadId === threadId) {
|
|
950
|
-
stopHeartbeatByKey(key);
|
|
951
|
-
}
|
|
952
|
-
}
|
|
953
|
-
};
|
|
954
|
-
const stopAllHeartbeats = () => {
|
|
955
|
-
for (const key of heartbeats.keys()) {
|
|
956
|
-
stopHeartbeatByKey(key);
|
|
957
|
-
}
|
|
958
|
-
};
|
|
959
|
-
const runHeartbeat = async (key) => {
|
|
960
|
-
const heartbeat = heartbeats.get(key);
|
|
961
|
-
if (!heartbeat || heartbeat.inFlight) {
|
|
962
|
-
return;
|
|
963
|
-
}
|
|
964
|
-
heartbeat.inFlight = true;
|
|
965
|
-
try {
|
|
966
|
-
if (Date.now() - heartbeat.startedAtMs >= options.activeLockMaxAgeMs) {
|
|
967
|
-
stopHeartbeatByKey(key);
|
|
968
|
-
return;
|
|
969
|
-
}
|
|
970
|
-
const extended = await base.extendLock(heartbeat.lock, heartbeat.ttlMs);
|
|
971
|
-
if (!extended) {
|
|
972
|
-
stopHeartbeatByKey(key);
|
|
973
|
-
return;
|
|
974
|
-
}
|
|
975
|
-
heartbeat.lock.expiresAt = Date.now() + heartbeat.ttlMs;
|
|
976
|
-
} catch {
|
|
977
|
-
} finally {
|
|
978
|
-
const current = heartbeats.get(key);
|
|
979
|
-
if (current === heartbeat) {
|
|
980
|
-
current.inFlight = false;
|
|
981
|
-
}
|
|
982
|
-
}
|
|
983
|
-
};
|
|
984
|
-
const startOrUpdateHeartbeat = (lock, ttlMs) => {
|
|
985
|
-
const key = heartbeatKey(lock);
|
|
986
|
-
const existing = heartbeats.get(key);
|
|
987
|
-
if (existing) {
|
|
988
|
-
existing.ttlMs = ttlMs;
|
|
989
|
-
return;
|
|
990
|
-
}
|
|
991
|
-
const timer = setInterval(() => {
|
|
992
|
-
void runHeartbeat(key);
|
|
993
|
-
}, ACTIVE_LOCK_HEARTBEAT_MS);
|
|
994
|
-
timer.unref?.();
|
|
995
|
-
heartbeats.set(key, {
|
|
996
|
-
inFlight: false,
|
|
997
|
-
lock,
|
|
998
|
-
startedAtMs: Date.now(),
|
|
999
|
-
timer,
|
|
1000
|
-
ttlMs
|
|
1001
|
-
});
|
|
1002
|
-
};
|
|
1003
|
-
const acquireLock = async (threadId, ttlMs) => {
|
|
1004
|
-
const lock = await base.acquireLock(threadId, ttlMs);
|
|
1005
|
-
if (lock && shouldHeartbeatLock(ttlMs)) {
|
|
1006
|
-
startOrUpdateHeartbeat(lock, ttlMs);
|
|
1007
|
-
}
|
|
1008
|
-
return lock;
|
|
1009
|
-
};
|
|
1010
|
-
return {
|
|
1011
|
-
appendToList: (key, value, options2) => base.appendToList(key, value, options2),
|
|
1012
|
-
connect: () => base.connect(),
|
|
1013
|
-
disconnect: async () => {
|
|
1014
|
-
stopAllHeartbeats();
|
|
1015
|
-
await base.disconnect();
|
|
1016
|
-
},
|
|
1017
|
-
subscribe: (threadId) => base.subscribe(threadId),
|
|
1018
|
-
unsubscribe: (threadId) => base.unsubscribe(threadId),
|
|
1019
|
-
isSubscribed: (threadId) => base.isSubscribed(threadId),
|
|
1020
|
-
acquireLock,
|
|
1021
|
-
releaseLock: async (lock) => {
|
|
1022
|
-
stopHeartbeat(lock);
|
|
1023
|
-
await base.releaseLock(lock);
|
|
1024
|
-
},
|
|
1025
|
-
extendLock: async (lock, ttlMs) => {
|
|
1026
|
-
const extended = await base.extendLock(lock, ttlMs);
|
|
1027
|
-
if (extended) {
|
|
1028
|
-
lock.expiresAt = Date.now() + ttlMs;
|
|
1029
|
-
if (shouldHeartbeatLock(ttlMs)) {
|
|
1030
|
-
startOrUpdateHeartbeat(lock, ttlMs);
|
|
1031
|
-
} else {
|
|
1032
|
-
stopHeartbeat(lock);
|
|
1033
|
-
}
|
|
1034
|
-
} else {
|
|
1035
|
-
stopHeartbeat(lock);
|
|
1036
|
-
}
|
|
1037
|
-
return extended;
|
|
1038
|
-
},
|
|
1039
|
-
forceReleaseLock: async (threadId) => {
|
|
1040
|
-
stopHeartbeatsForThread(threadId);
|
|
1041
|
-
await base.forceReleaseLock(threadId);
|
|
1042
|
-
},
|
|
1043
|
-
enqueue: (threadId, entry, maxSize) => base.enqueue(threadId, entry, maxSize),
|
|
1044
|
-
dequeue: (threadId) => base.dequeue(threadId),
|
|
1045
|
-
queueDepth: (threadId) => base.queueDepth(threadId),
|
|
1046
|
-
get: (key) => base.get(key),
|
|
1047
|
-
getList: (key) => base.getList(key),
|
|
1048
|
-
set: (key, value, ttlMs) => base.set(key, value, ttlMs),
|
|
1049
|
-
setIfNotExists: (key, value, ttlMs) => base.setIfNotExists(key, value, ttlMs),
|
|
1050
|
-
delete: (key) => base.delete(key)
|
|
1051
|
-
};
|
|
1052
|
-
}
|
|
1053
|
-
function withOptionalPrefix(base, prefix) {
|
|
1054
|
-
return prefix ? createPrefixedStateAdapter(base, prefix) : base;
|
|
1055
|
-
}
|
|
1056
|
-
function createStateAdapter() {
|
|
1057
|
-
const config = getChatConfig();
|
|
1058
|
-
const activeLockMaxAgeMs = config.bot.turnTimeoutMs + ACTIVE_LOCK_TTL_MS;
|
|
1059
|
-
if (config.state.adapter === "memory") {
|
|
1060
|
-
redisStateAdapter = void 0;
|
|
1061
|
-
return createQueuedStateAdapter(
|
|
1062
|
-
withOptionalPrefix(createMemoryState(), config.state.keyPrefix),
|
|
1063
|
-
{ activeLockMaxAgeMs }
|
|
1064
|
-
);
|
|
1065
|
-
}
|
|
1066
|
-
if (!config.state.redisUrl) {
|
|
1067
|
-
throw new Error("REDIS_URL is required for durable Slack thread state");
|
|
1068
|
-
}
|
|
1069
|
-
const redisState = createRedisState({
|
|
1070
|
-
url: config.state.redisUrl
|
|
1071
|
-
});
|
|
1072
|
-
redisStateAdapter = redisState;
|
|
1073
|
-
return createQueuedStateAdapter(
|
|
1074
|
-
withOptionalPrefix(redisState, config.state.keyPrefix),
|
|
1075
|
-
{ activeLockMaxAgeMs }
|
|
1076
|
-
);
|
|
1077
|
-
}
|
|
1078
|
-
function getOptionalRedisStateAdapter() {
|
|
1079
|
-
getStateAdapter();
|
|
1080
|
-
return redisStateAdapter;
|
|
1081
|
-
}
|
|
1082
|
-
async function getConnectedStateContext() {
|
|
1083
|
-
const adapter = getStateAdapter();
|
|
1084
|
-
await adapter.connect();
|
|
1085
|
-
return {
|
|
1086
|
-
redisStateAdapter: getOptionalRedisStateAdapter(),
|
|
1087
|
-
stateAdapter: adapter
|
|
1088
|
-
};
|
|
1089
|
-
}
|
|
1090
|
-
async function getDefaultRedisStateAdapterFor(adapter) {
|
|
1091
|
-
if (adapter !== stateAdapter) {
|
|
1092
|
-
return void 0;
|
|
1093
|
-
}
|
|
1094
|
-
const context = await getConnectedStateContext();
|
|
1095
|
-
return context.stateAdapter === adapter ? context.redisStateAdapter : void 0;
|
|
1096
|
-
}
|
|
1097
|
-
function getStateAdapter() {
|
|
1098
|
-
if (!stateAdapter) {
|
|
1099
|
-
stateAdapter = createStateAdapter();
|
|
1100
|
-
}
|
|
1101
|
-
return stateAdapter;
|
|
1102
|
-
}
|
|
1103
|
-
async function disconnectStateAdapter() {
|
|
1104
|
-
if (!stateAdapter) {
|
|
1105
|
-
return;
|
|
1106
|
-
}
|
|
1107
|
-
try {
|
|
1108
|
-
await stateAdapter.disconnect();
|
|
1109
|
-
} finally {
|
|
1110
|
-
stateAdapter = void 0;
|
|
1111
|
-
redisStateAdapter = void 0;
|
|
1112
|
-
}
|
|
1113
|
-
}
|
|
1114
|
-
|
|
1115
869
|
export {
|
|
1116
870
|
toOptionalTrimmed,
|
|
1117
871
|
escapeXml,
|
|
@@ -1154,6 +908,8 @@ export {
|
|
|
1154
908
|
modelProfileSchema,
|
|
1155
909
|
ModelProfileNotConfiguredError,
|
|
1156
910
|
modelIdForProfile,
|
|
911
|
+
standardModelId,
|
|
912
|
+
profileConfig,
|
|
1157
913
|
FUNCTION_TIMEOUT_BUFFER_SECONDS,
|
|
1158
914
|
getChatConfig,
|
|
1159
915
|
botConfig,
|
|
@@ -1163,10 +919,5 @@ export {
|
|
|
1163
919
|
getSlackClientSecret,
|
|
1164
920
|
getRuntimeMetadata,
|
|
1165
921
|
getSlackReactionConfig,
|
|
1166
|
-
setSlackReactionConfig
|
|
1167
|
-
acquireActiveLock,
|
|
1168
|
-
getConnectedStateContext,
|
|
1169
|
-
getDefaultRedisStateAdapterFor,
|
|
1170
|
-
getStateAdapter,
|
|
1171
|
-
disconnectStateAdapter
|
|
922
|
+
setSlackReactionConfig
|
|
1172
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
|
+
};
|