@sentry/junior 0.155.0 → 0.157.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-AWVTLAV2.js → agent-hooks-QI5EPOKQ.js} +10 -10
- package/dist/api/conversations/attachments.d.ts +32 -0
- package/dist/api/conversations/priority.d.ts +21 -0
- package/dist/api/conversations/routes.d.ts +4 -1
- package/dist/api/locations/detail.d.ts +4 -1
- package/dist/api/schema/conversation.d.ts +33 -8
- package/dist/api/schema/location.d.ts +4 -1
- package/dist/api/schema/person.d.ts +4 -1
- package/dist/api/schema/task.d.ts +8 -8
- package/dist/api/schema.js +1 -1
- package/dist/api.js +182 -48
- package/dist/app.js +128 -44
- package/dist/{catalog-runtime-V6YD6KH5.js → catalog-runtime-HUGHAFUN.js} +5 -5
- package/dist/chat/agent/types.d.ts +2 -0
- package/dist/chat/agent-invocations/types.d.ts +12 -12
- package/dist/chat/attachments/storage.d.ts +14 -0
- package/dist/chat/attachments/store.d.ts +68 -0
- package/dist/chat/attachments/vercel.d.ts +3 -0
- package/dist/chat/conversations/retention.d.ts +4 -0
- package/dist/chat/event-tasks/tool-support.d.ts +1 -1
- package/dist/chat/event-tasks/types.d.ts +1 -1
- package/dist/chat/ingress/bot-mention.d.ts +13 -0
- package/dist/chat/plugins/unfinished-work.d.ts +11 -0
- package/dist/chat/runtime/agent-runner.d.ts +2 -0
- package/dist/chat/scheduled-tasks/tool-support.d.ts +5 -5
- package/dist/chat/scheduled-tasks/tools/create.d.ts +2 -2
- package/dist/chat/scheduled-tasks/tools/delete.d.ts +2 -2
- package/dist/chat/scheduled-tasks/tools/list.d.ts +2 -2
- package/dist/chat/scheduled-tasks/tools/run-now.d.ts +2 -2
- package/dist/chat/scheduled-tasks/tools/update.d.ts +2 -2
- package/dist/chat/services/conversation-memory.d.ts +1 -1
- package/dist/chat/slack/tools/send-files.d.ts +17 -11
- package/dist/chat/state/conversation.d.ts +2 -1
- package/dist/chat/task-execution/slack-work.d.ts +2 -2
- package/dist/chat/tools/types.d.ts +2 -0
- package/dist/{chunk-773XC7P4.js → chunk-3GS7O66Z.js} +159 -128
- package/dist/{chunk-JFZBGFNX.js → chunk-46ADYIPE.js} +2 -1
- package/dist/{chunk-KTVHAHUV.js → chunk-4M25PSFB.js} +1 -1
- package/dist/{chunk-4K5N6HTX.js → chunk-5TIH5GOE.js} +5 -5
- package/dist/{chunk-TVXAN43I.js → chunk-6MI43QZO.js} +1 -1
- package/dist/{chunk-RN3AWYEP.js → chunk-77QB5FNI.js} +1 -1
- package/dist/{chunk-Y7ZUBP2K.js → chunk-7J65DOBL.js} +6 -6
- package/dist/{chunk-2AHVM3HK.js → chunk-AFQ47JQ7.js} +10 -8
- package/dist/{chunk-ELOTIL5F.js → chunk-BLCVTEE7.js} +4 -4
- package/dist/{chunk-ZLSFOSDK.js → chunk-CZCMFRUQ.js} +18 -1
- package/dist/{chunk-2WLJDM23.js → chunk-D7BNWRYL.js} +1 -1
- package/dist/{chunk-EORR34UB.js → chunk-F7VOY4VQ.js} +1 -1
- package/dist/{chunk-JJX77MB7.js → chunk-G2FN3I66.js} +3 -3
- package/dist/{chunk-J2SYI36O.js → chunk-GEY6IFXH.js} +4 -4
- package/dist/{chunk-37G5HJ2X.js → chunk-GO2W3VZY.js} +4 -4
- package/dist/{chunk-LQT3SWFA.js → chunk-HJ3EZHIX.js} +351 -5
- package/dist/{chunk-SDRJ2LE3.js → chunk-I3OQVVMV.js} +1 -1
- package/dist/{chunk-TKJ7277U.js → chunk-MDZQ62PB.js} +2 -2
- package/dist/{chunk-V57LZDHN.js → chunk-MGJW3SW4.js} +6 -6
- package/dist/{chunk-7NYEB2TM.js → chunk-MKA3T2R6.js} +1 -1
- package/dist/{chunk-RQ62VKM7.js → chunk-MXO6VFB3.js} +1 -1
- package/dist/{chunk-AENPRXCG.js → chunk-OWASYHHV.js} +68 -39
- package/dist/{chunk-UWTXAYBP.js → chunk-PP4UQTH3.js} +9 -9
- package/dist/{chunk-JIC33O5L.js → chunk-RQBRGPUF.js} +2 -2
- package/dist/{chunk-NWSKFYOH.js → chunk-S4PFOWRA.js} +1 -1
- package/dist/{chunk-NKFRRZIT.js → chunk-TA5R6BME.js} +19 -18
- package/dist/{chunk-XFZLQANQ.js → chunk-UJYA75N5.js} +2 -2
- package/dist/{chunk-Y6MVGU7L.js → chunk-VBKFO65J.js} +35 -10
- package/dist/{chunk-KBT2I5ER.js → chunk-VDAEXEBB.js} +6 -6
- package/dist/{chunk-J7MWZFFP.js → chunk-VIBHFGQC.js} +4 -4
- package/dist/{chunk-APHDJYN7.js → chunk-VYDM7HUF.js} +1 -1
- package/dist/{chunk-CPQBTTI6.js → chunk-WNNYOPXX.js} +5 -5
- package/dist/{chunk-MLBH7J7J.js → chunk-XRERMHPN.js} +1 -1
- package/dist/cli/chat.js +30 -30
- package/dist/cli/check.js +6 -6
- package/dist/cli/plugins.js +13 -13
- package/dist/cli/snapshot-create.js +9 -9
- package/dist/cli/upgrade.js +7 -7
- package/dist/db/schema/agent-invocations.d.ts +4 -4
- package/dist/db/schema/attachments.d.ts +178 -0
- package/dist/db/schema.d.ts +183 -5
- package/dist/{db-WT7P56AH.js → db-VQAV4PJ3.js} +7 -7
- package/dist/handlers/retention.d.ts +4 -1
- package/dist/instrumentation.js +4 -4
- package/dist/nitro.js +2 -2
- package/dist/{oauth-callback-server-R2PK2MCA.js → oauth-callback-server-K5KQAAAX.js} +23 -23
- package/dist/{runner-O7YYUIHT.js → runner-U7QI7P4S.js} +14 -15
- package/dist/{skills-S6HLQRH7.js → skills-ENKRBZ7K.js} +6 -6
- package/dist/spawn-4XGNONLS.js +37 -0
- package/dist/{validation-46WD2OAR.js → validation-VKCDVGA6.js} +6 -6
- package/dist/version.js +1 -1
- package/dist/{work-YT5QUBS3.js → work-IBD6PWP2.js} +17 -17
- package/dist/worker-TJFXOZRC.js +24 -0
- package/migrations/0027_attachment_storage.sql +16 -0
- package/migrations/meta/0027_snapshot.json +2554 -0
- package/migrations/meta/_journal.json +8 -1
- package/package.json +5 -4
- package/dist/spawn-B4SBFFA2.js +0 -37
- package/dist/worker-4C5BEDWN.js +0 -24
|
@@ -3,38 +3,38 @@ import {
|
|
|
3
3
|
} from "./chunk-RF6J3DIO.js";
|
|
4
4
|
import {
|
|
5
5
|
resolveBaseUrl
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-VDAEXEBB.js";
|
|
7
7
|
import {
|
|
8
8
|
isExperimentalFeatureEnabled
|
|
9
9
|
} from "./chunk-5IDFPCON.js";
|
|
10
10
|
import {
|
|
11
11
|
createPluginLogger,
|
|
12
12
|
getPlugins
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-MGJW3SW4.js";
|
|
14
14
|
import {
|
|
15
15
|
getSlackClient,
|
|
16
16
|
withSlackRetries
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-MDZQ62PB.js";
|
|
18
18
|
import {
|
|
19
19
|
getDb,
|
|
20
20
|
parseDestination
|
|
21
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-G2FN3I66.js";
|
|
22
22
|
import {
|
|
23
23
|
sleep
|
|
24
24
|
} from "./chunk-EM225ITJ.js";
|
|
25
25
|
import {
|
|
26
26
|
acquireActiveLock,
|
|
27
27
|
getStateAdapter
|
|
28
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-I3OQVVMV.js";
|
|
29
29
|
import {
|
|
30
30
|
pluginCatalogRuntime
|
|
31
|
-
} from "./chunk-
|
|
31
|
+
} from "./chunk-6MI43QZO.js";
|
|
32
32
|
import {
|
|
33
33
|
fetchWithBoundedOAuthErrorBodies
|
|
34
|
-
} from "./chunk-
|
|
34
|
+
} from "./chunk-77QB5FNI.js";
|
|
35
35
|
import {
|
|
36
36
|
isRecord
|
|
37
|
-
} from "./chunk-
|
|
37
|
+
} from "./chunk-MKA3T2R6.js";
|
|
38
38
|
|
|
39
39
|
// src/chat/capabilities/router.ts
|
|
40
40
|
var ProviderCredentialRouter = class {
|
|
@@ -149,6 +149,7 @@ async function issueProviderCredentialLease(input) {
|
|
|
149
149
|
// src/chat/runtime/agent-runner.ts
|
|
150
150
|
var AGENT_ABORT_SETTLE_GRACE_MS = 5e3;
|
|
151
151
|
function createAgentRunner(execute, options) {
|
|
152
|
+
const attachmentStorage = options?.attachmentStorage;
|
|
152
153
|
const streamFn = options?.streamFn;
|
|
153
154
|
const tracePropagation = options?.tracePropagation;
|
|
154
155
|
const bindSpawnAgent = options?.bindSpawnAgent;
|
|
@@ -160,6 +161,7 @@ function createAgentRunner(execute, options) {
|
|
|
160
161
|
...run,
|
|
161
162
|
environment: {
|
|
162
163
|
...run.environment,
|
|
164
|
+
attachmentStorage: run.environment?.attachmentStorage ?? attachmentStorage,
|
|
163
165
|
sandboxTracePropagation: run.environment?.sandboxTracePropagation ?? tracePropagation
|
|
164
166
|
},
|
|
165
167
|
...spawnAgent ? {
|
|
@@ -8,14 +8,14 @@ import {
|
|
|
8
8
|
getConversationStore,
|
|
9
9
|
parseDestination,
|
|
10
10
|
sameDestination
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-G2FN3I66.js";
|
|
12
12
|
import {
|
|
13
13
|
getDefaultRedisStateAdapterFor,
|
|
14
14
|
getStateAdapter
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-I3OQVVMV.js";
|
|
16
16
|
import {
|
|
17
17
|
getChatConfig
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-UJYA75N5.js";
|
|
19
19
|
import {
|
|
20
20
|
parseStoredSlackActor
|
|
21
21
|
} from "./chunk-V7YE4WCP.js";
|
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
isRecord,
|
|
24
24
|
toOptionalNumber,
|
|
25
25
|
toOptionalString
|
|
26
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-MKA3T2R6.js";
|
|
27
27
|
|
|
28
28
|
// src/chat/task-execution/state.ts
|
|
29
29
|
import { randomUUID } from "crypto";
|
|
@@ -56,6 +56,10 @@ var conversationSurfaceSchema = z2.enum([
|
|
|
56
56
|
]);
|
|
57
57
|
var conversationUsageSchema = usageSchema;
|
|
58
58
|
var conversationParamsSchema = z2.object({ conversationId: z2.string().min(1) }).strict();
|
|
59
|
+
var conversationAttachmentParamsSchema = z2.object({
|
|
60
|
+
attachmentId: z2.string().min(1),
|
|
61
|
+
conversationId: z2.string().min(1)
|
|
62
|
+
}).strict();
|
|
59
63
|
var conversationDetailQuerySchema = z2.object({
|
|
60
64
|
limit: z2.coerce.number().int().min(1).max(1e3).default(500)
|
|
61
65
|
}).strict();
|
|
@@ -175,13 +179,25 @@ var conversationSummaryReportSchema = z2.object({
|
|
|
175
179
|
sentryTraceUrl: z2.string().optional(),
|
|
176
180
|
sourceUrl: z2.string().url().optional(),
|
|
177
181
|
traceId: z2.string().optional(),
|
|
182
|
+
assignedWork: z2.boolean().optional(),
|
|
183
|
+
finishedWorkAt: z2.string().datetime().optional(),
|
|
184
|
+
/**
|
|
185
|
+
* Dashboard Priority membership for this conversation summary.
|
|
186
|
+
* Present on the conversation feed. Clients must not recompute it.
|
|
187
|
+
*
|
|
188
|
+
* True only when:
|
|
189
|
+
* - unfinished work was last seen within 48 hours
|
|
190
|
+
* - finished assigned work has conversation activity after the finish time
|
|
191
|
+
* - there is no known work and the conversation was last seen within 3 hours
|
|
192
|
+
*/
|
|
193
|
+
isPriority: z2.boolean().optional(),
|
|
178
194
|
unfinishedWork: z2.boolean().optional()
|
|
179
195
|
}).strict();
|
|
180
196
|
var conversationReportMessageEventDataSchema = z2.object({
|
|
181
197
|
type: z2.literal("message"),
|
|
182
198
|
messageId: z2.string().min(1),
|
|
183
199
|
role: z2.enum(["assistant", "system", "user"]),
|
|
184
|
-
source: z2.
|
|
200
|
+
source: z2.enum(["slack", "web"]).optional(),
|
|
185
201
|
actorIdentity: actorIdentitySchema.optional(),
|
|
186
202
|
eventType: z2.string().min(1).optional(),
|
|
187
203
|
explicitMention: z2.boolean().optional(),
|
|
@@ -781,6 +797,7 @@ var statsReportSchema = z8.object({
|
|
|
781
797
|
export {
|
|
782
798
|
apiErrorSchema,
|
|
783
799
|
conversationParamsSchema,
|
|
800
|
+
conversationAttachmentParamsSchema,
|
|
784
801
|
conversationDetailQuerySchema,
|
|
785
802
|
conversationEventsQuerySchema,
|
|
786
803
|
conversationFeedQuerySchema,
|
|
@@ -6,12 +6,12 @@ import {
|
|
|
6
6
|
juniorConversations,
|
|
7
7
|
juniorIdentities,
|
|
8
8
|
juniorUsers
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-3GS7O66Z.js";
|
|
10
10
|
import {
|
|
11
11
|
TURN_REASONING_LEVELS,
|
|
12
12
|
getChatConfig,
|
|
13
13
|
modelProfileSchema
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-UJYA75N5.js";
|
|
15
15
|
import {
|
|
16
16
|
juniorDestinations
|
|
17
17
|
} from "./chunk-VFUK3X5B.js";
|
|
@@ -22,7 +22,7 @@ import {
|
|
|
22
22
|
} from "./chunk-V7YE4WCP.js";
|
|
23
23
|
import {
|
|
24
24
|
normalizeIdentityEmail
|
|
25
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-MKA3T2R6.js";
|
|
26
26
|
|
|
27
27
|
// src/chat/conversations/sql/store.ts
|
|
28
28
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
instructionProvenanceFor,
|
|
14
14
|
sanitizePostgresJson,
|
|
15
15
|
withConversationEventLock
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-G2FN3I66.js";
|
|
17
17
|
import {
|
|
18
18
|
SANDBOX_WORKSPACE_ROOT,
|
|
19
19
|
sleep
|
|
@@ -23,14 +23,14 @@ import {
|
|
|
23
23
|
fenceLock,
|
|
24
24
|
getStateAdapter,
|
|
25
25
|
withLock
|
|
26
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-I3OQVVMV.js";
|
|
27
27
|
import {
|
|
28
28
|
botConfig,
|
|
29
29
|
completeText,
|
|
30
30
|
escapeXml,
|
|
31
31
|
resolveGatewayModel,
|
|
32
32
|
unwrapCurrentInstruction
|
|
33
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-UJYA75N5.js";
|
|
34
34
|
import {
|
|
35
35
|
parseSlackMessageTs,
|
|
36
36
|
toStoredSlackActor
|
|
@@ -40,7 +40,7 @@ import {
|
|
|
40
40
|
logException,
|
|
41
41
|
logWarn,
|
|
42
42
|
setSpanAttributes
|
|
43
|
-
} from "./chunk-
|
|
43
|
+
} from "./chunk-MKA3T2R6.js";
|
|
44
44
|
|
|
45
45
|
// src/chat/turn-context-tag.ts
|
|
46
46
|
var TURN_CONTEXT_TAG = "runtime-turn-context";
|
|
@@ -4,18 +4,18 @@ import {
|
|
|
4
4
|
} from "./chunk-EM225ITJ.js";
|
|
5
5
|
import {
|
|
6
6
|
getStateAdapter
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-I3OQVVMV.js";
|
|
8
8
|
import {
|
|
9
9
|
toOptionalTrimmed
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-UJYA75N5.js";
|
|
11
11
|
import {
|
|
12
12
|
pluginCatalogRuntime
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-6MI43QZO.js";
|
|
14
14
|
import {
|
|
15
15
|
setSpanAttributes,
|
|
16
16
|
setSpanStatus,
|
|
17
17
|
withSpan
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-MKA3T2R6.js";
|
|
19
19
|
|
|
20
20
|
// src/chat/sandbox/resources.ts
|
|
21
21
|
var configuredResources;
|
|
@@ -1,25 +1,27 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ToolInputError
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-GEY6IFXH.js";
|
|
4
4
|
import {
|
|
5
5
|
canRouteResourceEvents,
|
|
6
6
|
getPlugins
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-MGJW3SW4.js";
|
|
8
8
|
import {
|
|
9
9
|
getDb
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-G2FN3I66.js";
|
|
11
11
|
import {
|
|
12
|
+
juniorAttachments,
|
|
13
|
+
juniorConversations,
|
|
12
14
|
juniorEventTasks,
|
|
13
15
|
juniorSchedulerRuns,
|
|
14
16
|
juniorSchedulerTasks,
|
|
15
17
|
juniorStats
|
|
16
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-3GS7O66Z.js";
|
|
17
19
|
import {
|
|
18
20
|
juniorDestinations
|
|
19
21
|
} from "./chunk-VFUK3X5B.js";
|
|
20
22
|
import {
|
|
21
23
|
logInfo
|
|
22
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-MKA3T2R6.js";
|
|
23
25
|
|
|
24
26
|
// src/chat/event-tasks/store.ts
|
|
25
27
|
import { and, asc, desc, eq, inArray, or, sql } from "drizzle-orm";
|
|
@@ -1553,6 +1555,346 @@ function createSchedulerSqlStore(db) {
|
|
|
1553
1555
|
return new SqlSchedulerStore(db);
|
|
1554
1556
|
}
|
|
1555
1557
|
|
|
1558
|
+
// src/chat/attachments/store.ts
|
|
1559
|
+
import { createHash, randomUUID } from "crypto";
|
|
1560
|
+
import { and as and4, asc as asc4, eq as eq3, inArray as inArray3, isNotNull as isNotNull2, isNull, or as or3 } from "drizzle-orm";
|
|
1561
|
+
var ATTACHMENT_GC_BATCH_LIMIT = 200;
|
|
1562
|
+
function attachmentDigest(file) {
|
|
1563
|
+
return createHash("sha256").update(file.data).digest("hex");
|
|
1564
|
+
}
|
|
1565
|
+
function attachmentId(args) {
|
|
1566
|
+
return createHash("sha256").update(
|
|
1567
|
+
[
|
|
1568
|
+
args.conversationId,
|
|
1569
|
+
args.provider,
|
|
1570
|
+
args.sha256,
|
|
1571
|
+
args.filename,
|
|
1572
|
+
args.contentType
|
|
1573
|
+
].join("\0")
|
|
1574
|
+
).digest("hex");
|
|
1575
|
+
}
|
|
1576
|
+
function attachmentKey(args) {
|
|
1577
|
+
return `conversations/${args.conversationId}/attachments/${args.attachmentId}/${args.writeId}/${args.filename}`;
|
|
1578
|
+
}
|
|
1579
|
+
async function bestEffortDelete(storage, key) {
|
|
1580
|
+
try {
|
|
1581
|
+
await storage.delete([key]);
|
|
1582
|
+
} catch {
|
|
1583
|
+
}
|
|
1584
|
+
}
|
|
1585
|
+
async function isConversationPurged(db, conversationId) {
|
|
1586
|
+
const [row] = await db.db().select({
|
|
1587
|
+
transcriptPurgedAt: juniorConversations.transcriptPurgedAt
|
|
1588
|
+
}).from(juniorConversations).where(eq3(juniorConversations.conversationId, conversationId));
|
|
1589
|
+
return row?.transcriptPurgedAt != null;
|
|
1590
|
+
}
|
|
1591
|
+
function purgedConversationError(conversationId) {
|
|
1592
|
+
return new Error(
|
|
1593
|
+
`Cannot store attachment for purged conversation ${conversationId}`
|
|
1594
|
+
);
|
|
1595
|
+
}
|
|
1596
|
+
async function assertConversationNotPurged(db, conversationId) {
|
|
1597
|
+
if (await isConversationPurged(db, conversationId)) {
|
|
1598
|
+
throw purgedConversationError(conversationId);
|
|
1599
|
+
}
|
|
1600
|
+
}
|
|
1601
|
+
async function rejectPurgedAttachmentWrite(args) {
|
|
1602
|
+
await args.db.db().update(juniorAttachments).set({ deleteRequestedAt: args.now }).where(eq3(juniorAttachments.id, args.id));
|
|
1603
|
+
await bestEffortDelete(args.storage, args.storageKey);
|
|
1604
|
+
throw purgedConversationError(args.conversationId);
|
|
1605
|
+
}
|
|
1606
|
+
async function reuseLiveAttachment(args) {
|
|
1607
|
+
await bestEffortDelete(args.storage, args.storageKey);
|
|
1608
|
+
await assertConversationNotPurged(args.db, args.conversationId);
|
|
1609
|
+
return { id: args.id };
|
|
1610
|
+
}
|
|
1611
|
+
async function storeAttachment(args) {
|
|
1612
|
+
const now = new Date(args.nowMs ?? Date.now());
|
|
1613
|
+
const sha256 = attachmentDigest(args.file);
|
|
1614
|
+
const id = attachmentId({
|
|
1615
|
+
conversationId: args.conversationId,
|
|
1616
|
+
contentType: args.file.mimeType,
|
|
1617
|
+
filename: args.file.filename,
|
|
1618
|
+
provider: args.storage.provider,
|
|
1619
|
+
sha256
|
|
1620
|
+
});
|
|
1621
|
+
const [existing] = await args.db.db().select({
|
|
1622
|
+
contentType: juniorAttachments.contentType,
|
|
1623
|
+
conversationId: juniorAttachments.conversationId,
|
|
1624
|
+
deleteRequestedAt: juniorAttachments.deleteRequestedAt,
|
|
1625
|
+
filename: juniorAttachments.filename,
|
|
1626
|
+
id: juniorAttachments.id,
|
|
1627
|
+
provider: juniorAttachments.provider,
|
|
1628
|
+
sha256: juniorAttachments.sha256,
|
|
1629
|
+
storageKey: juniorAttachments.storageKey
|
|
1630
|
+
}).from(juniorAttachments).where(eq3(juniorAttachments.id, id));
|
|
1631
|
+
if (existing) {
|
|
1632
|
+
if (existing.contentType !== args.file.mimeType || existing.conversationId !== args.conversationId || existing.filename !== args.file.filename || existing.provider !== args.storage.provider || existing.sha256 !== sha256) {
|
|
1633
|
+
throw new Error(`Attachment write conflicts with ${existing.id}`);
|
|
1634
|
+
}
|
|
1635
|
+
if (existing.deleteRequestedAt === null) {
|
|
1636
|
+
await assertConversationNotPurged(args.db, args.conversationId);
|
|
1637
|
+
return { id: existing.id };
|
|
1638
|
+
}
|
|
1639
|
+
}
|
|
1640
|
+
await assertConversationNotPurged(args.db, args.conversationId);
|
|
1641
|
+
const storageKey = attachmentKey({
|
|
1642
|
+
attachmentId: id,
|
|
1643
|
+
conversationId: args.conversationId,
|
|
1644
|
+
filename: args.file.filename,
|
|
1645
|
+
writeId: randomUUID()
|
|
1646
|
+
});
|
|
1647
|
+
await args.storage.put({
|
|
1648
|
+
body: args.file.data,
|
|
1649
|
+
contentType: args.file.mimeType,
|
|
1650
|
+
key: storageKey
|
|
1651
|
+
});
|
|
1652
|
+
if (existing?.deleteRequestedAt != null) {
|
|
1653
|
+
if (await isConversationPurged(args.db, args.conversationId)) {
|
|
1654
|
+
await bestEffortDelete(args.storage, storageKey);
|
|
1655
|
+
throw purgedConversationError(args.conversationId);
|
|
1656
|
+
}
|
|
1657
|
+
const oldStorageKey = existing.storageKey;
|
|
1658
|
+
const revived2 = await args.db.db().update(juniorAttachments).set({
|
|
1659
|
+
deleteRequestedAt: null,
|
|
1660
|
+
storageKey
|
|
1661
|
+
}).where(
|
|
1662
|
+
and4(
|
|
1663
|
+
eq3(juniorAttachments.id, id),
|
|
1664
|
+
isNotNull2(juniorAttachments.deleteRequestedAt)
|
|
1665
|
+
)
|
|
1666
|
+
).returning({ id: juniorAttachments.id });
|
|
1667
|
+
if (revived2.length > 0) {
|
|
1668
|
+
if (await isConversationPurged(args.db, args.conversationId)) {
|
|
1669
|
+
await rejectPurgedAttachmentWrite({
|
|
1670
|
+
conversationId: args.conversationId,
|
|
1671
|
+
db: args.db,
|
|
1672
|
+
id,
|
|
1673
|
+
now,
|
|
1674
|
+
storage: args.storage,
|
|
1675
|
+
storageKey
|
|
1676
|
+
});
|
|
1677
|
+
}
|
|
1678
|
+
if (oldStorageKey !== storageKey) {
|
|
1679
|
+
await bestEffortDelete(args.storage, oldStorageKey);
|
|
1680
|
+
}
|
|
1681
|
+
return { id };
|
|
1682
|
+
}
|
|
1683
|
+
const [afterRace2] = await args.db.db().select({
|
|
1684
|
+
deleteRequestedAt: juniorAttachments.deleteRequestedAt,
|
|
1685
|
+
id: juniorAttachments.id,
|
|
1686
|
+
storageKey: juniorAttachments.storageKey
|
|
1687
|
+
}).from(juniorAttachments).where(eq3(juniorAttachments.id, id));
|
|
1688
|
+
if (afterRace2?.deleteRequestedAt === null) {
|
|
1689
|
+
return reuseLiveAttachment({
|
|
1690
|
+
conversationId: args.conversationId,
|
|
1691
|
+
db: args.db,
|
|
1692
|
+
id: afterRace2.id,
|
|
1693
|
+
storage: args.storage,
|
|
1694
|
+
storageKey
|
|
1695
|
+
});
|
|
1696
|
+
}
|
|
1697
|
+
}
|
|
1698
|
+
let inserted = [];
|
|
1699
|
+
try {
|
|
1700
|
+
inserted = await args.db.db().insert(juniorAttachments).values({
|
|
1701
|
+
id,
|
|
1702
|
+
conversationId: args.conversationId,
|
|
1703
|
+
provider: args.storage.provider,
|
|
1704
|
+
storageKey,
|
|
1705
|
+
filename: args.file.filename,
|
|
1706
|
+
contentType: args.file.mimeType,
|
|
1707
|
+
bytes: args.file.bytes,
|
|
1708
|
+
sha256,
|
|
1709
|
+
createdAt: now
|
|
1710
|
+
}).onConflictDoNothing({ target: juniorAttachments.id }).returning({ id: juniorAttachments.id });
|
|
1711
|
+
} catch (error) {
|
|
1712
|
+
await bestEffortDelete(args.storage, storageKey);
|
|
1713
|
+
throw error;
|
|
1714
|
+
}
|
|
1715
|
+
if (inserted.length > 0) {
|
|
1716
|
+
if (await isConversationPurged(args.db, args.conversationId)) {
|
|
1717
|
+
await rejectPurgedAttachmentWrite({
|
|
1718
|
+
conversationId: args.conversationId,
|
|
1719
|
+
db: args.db,
|
|
1720
|
+
id,
|
|
1721
|
+
now,
|
|
1722
|
+
storage: args.storage,
|
|
1723
|
+
storageKey
|
|
1724
|
+
});
|
|
1725
|
+
}
|
|
1726
|
+
return { id };
|
|
1727
|
+
}
|
|
1728
|
+
const [row] = await args.db.db().select({
|
|
1729
|
+
deleteRequestedAt: juniorAttachments.deleteRequestedAt,
|
|
1730
|
+
id: juniorAttachments.id,
|
|
1731
|
+
storageKey: juniorAttachments.storageKey
|
|
1732
|
+
}).from(juniorAttachments).where(eq3(juniorAttachments.id, id));
|
|
1733
|
+
if (!row) {
|
|
1734
|
+
await bestEffortDelete(args.storage, storageKey);
|
|
1735
|
+
throw new Error(`Attachment row missing after write for ${id}`);
|
|
1736
|
+
}
|
|
1737
|
+
if (row.deleteRequestedAt === null) {
|
|
1738
|
+
return reuseLiveAttachment({
|
|
1739
|
+
conversationId: args.conversationId,
|
|
1740
|
+
db: args.db,
|
|
1741
|
+
id: row.id,
|
|
1742
|
+
storage: args.storage,
|
|
1743
|
+
storageKey
|
|
1744
|
+
});
|
|
1745
|
+
}
|
|
1746
|
+
if (await isConversationPurged(args.db, args.conversationId)) {
|
|
1747
|
+
await bestEffortDelete(args.storage, storageKey);
|
|
1748
|
+
throw purgedConversationError(args.conversationId);
|
|
1749
|
+
}
|
|
1750
|
+
const revived = await args.db.db().update(juniorAttachments).set({
|
|
1751
|
+
deleteRequestedAt: null,
|
|
1752
|
+
storageKey
|
|
1753
|
+
}).where(
|
|
1754
|
+
and4(
|
|
1755
|
+
eq3(juniorAttachments.id, id),
|
|
1756
|
+
isNotNull2(juniorAttachments.deleteRequestedAt)
|
|
1757
|
+
)
|
|
1758
|
+
).returning({ id: juniorAttachments.id });
|
|
1759
|
+
if (revived.length > 0) {
|
|
1760
|
+
if (await isConversationPurged(args.db, args.conversationId)) {
|
|
1761
|
+
await rejectPurgedAttachmentWrite({
|
|
1762
|
+
conversationId: args.conversationId,
|
|
1763
|
+
db: args.db,
|
|
1764
|
+
id,
|
|
1765
|
+
now,
|
|
1766
|
+
storage: args.storage,
|
|
1767
|
+
storageKey
|
|
1768
|
+
});
|
|
1769
|
+
}
|
|
1770
|
+
if (row.storageKey !== storageKey) {
|
|
1771
|
+
await bestEffortDelete(args.storage, row.storageKey);
|
|
1772
|
+
}
|
|
1773
|
+
return { id };
|
|
1774
|
+
}
|
|
1775
|
+
const [afterRace] = await args.db.db().select({
|
|
1776
|
+
deleteRequestedAt: juniorAttachments.deleteRequestedAt,
|
|
1777
|
+
id: juniorAttachments.id
|
|
1778
|
+
}).from(juniorAttachments).where(eq3(juniorAttachments.id, id));
|
|
1779
|
+
if (afterRace?.deleteRequestedAt === null) {
|
|
1780
|
+
return reuseLiveAttachment({
|
|
1781
|
+
conversationId: args.conversationId,
|
|
1782
|
+
db: args.db,
|
|
1783
|
+
id: afterRace.id,
|
|
1784
|
+
storage: args.storage,
|
|
1785
|
+
storageKey
|
|
1786
|
+
});
|
|
1787
|
+
}
|
|
1788
|
+
await bestEffortDelete(args.storage, storageKey);
|
|
1789
|
+
throw new Error(`Attachment ${id} disappeared while reviving`);
|
|
1790
|
+
}
|
|
1791
|
+
async function readLiveAttachment(args) {
|
|
1792
|
+
const [row] = await args.db.db().select({
|
|
1793
|
+
bytes: juniorAttachments.bytes,
|
|
1794
|
+
contentType: juniorAttachments.contentType,
|
|
1795
|
+
conversationId: juniorAttachments.conversationId,
|
|
1796
|
+
deleteRequestedAt: juniorAttachments.deleteRequestedAt,
|
|
1797
|
+
filename: juniorAttachments.filename,
|
|
1798
|
+
id: juniorAttachments.id,
|
|
1799
|
+
provider: juniorAttachments.provider,
|
|
1800
|
+
storageKey: juniorAttachments.storageKey
|
|
1801
|
+
}).from(juniorAttachments).where(
|
|
1802
|
+
and4(
|
|
1803
|
+
eq3(juniorAttachments.id, args.attachmentId),
|
|
1804
|
+
eq3(juniorAttachments.conversationId, args.conversationId),
|
|
1805
|
+
isNull(juniorAttachments.deleteRequestedAt)
|
|
1806
|
+
)
|
|
1807
|
+
);
|
|
1808
|
+
if (!row) return null;
|
|
1809
|
+
if (await isConversationPurged(args.db, args.conversationId)) {
|
|
1810
|
+
return null;
|
|
1811
|
+
}
|
|
1812
|
+
return {
|
|
1813
|
+
bytes: row.bytes,
|
|
1814
|
+
contentType: row.contentType,
|
|
1815
|
+
conversationId: row.conversationId,
|
|
1816
|
+
filename: row.filename,
|
|
1817
|
+
id: row.id,
|
|
1818
|
+
provider: row.provider,
|
|
1819
|
+
storageKey: row.storageKey
|
|
1820
|
+
};
|
|
1821
|
+
}
|
|
1822
|
+
async function storeAttachments(args) {
|
|
1823
|
+
const stored = [];
|
|
1824
|
+
for (const file of args.files) {
|
|
1825
|
+
stored.push(
|
|
1826
|
+
await storeAttachment({
|
|
1827
|
+
conversationId: args.conversationId,
|
|
1828
|
+
db: args.db,
|
|
1829
|
+
file,
|
|
1830
|
+
...args.nowMs !== void 0 ? { nowMs: args.nowMs } : {},
|
|
1831
|
+
storage: args.storage
|
|
1832
|
+
})
|
|
1833
|
+
);
|
|
1834
|
+
}
|
|
1835
|
+
return stored;
|
|
1836
|
+
}
|
|
1837
|
+
async function requestAttachmentDeletion(db, conversationIds, nowMs) {
|
|
1838
|
+
if (conversationIds.length === 0) return;
|
|
1839
|
+
await db.db().update(juniorAttachments).set({ deleteRequestedAt: new Date(nowMs) }).where(
|
|
1840
|
+
and4(
|
|
1841
|
+
inArray3(juniorAttachments.conversationId, conversationIds),
|
|
1842
|
+
isNull(juniorAttachments.deleteRequestedAt)
|
|
1843
|
+
)
|
|
1844
|
+
);
|
|
1845
|
+
}
|
|
1846
|
+
async function collectAttachmentGarbage(args) {
|
|
1847
|
+
void args.nowMs;
|
|
1848
|
+
const rows = await args.db.db().select({
|
|
1849
|
+
id: juniorAttachments.id,
|
|
1850
|
+
storageKey: juniorAttachments.storageKey
|
|
1851
|
+
}).from(juniorAttachments).innerJoin(
|
|
1852
|
+
juniorConversations,
|
|
1853
|
+
eq3(
|
|
1854
|
+
juniorAttachments.conversationId,
|
|
1855
|
+
juniorConversations.conversationId
|
|
1856
|
+
)
|
|
1857
|
+
).where(
|
|
1858
|
+
and4(
|
|
1859
|
+
eq3(juniorAttachments.provider, args.storage.provider),
|
|
1860
|
+
or3(
|
|
1861
|
+
isNotNull2(juniorAttachments.deleteRequestedAt),
|
|
1862
|
+
isNotNull2(juniorConversations.transcriptPurgedAt)
|
|
1863
|
+
)
|
|
1864
|
+
)
|
|
1865
|
+
).orderBy(asc4(juniorAttachments.createdAt), asc4(juniorAttachments.id)).limit(args.limit ?? ATTACHMENT_GC_BATCH_LIMIT);
|
|
1866
|
+
if (rows.length === 0) return { deleted: 0 };
|
|
1867
|
+
await args.storage.delete(rows.map((row) => row.storageKey));
|
|
1868
|
+
const stillEligible = await args.db.db().select({ id: juniorAttachments.id }).from(juniorAttachments).innerJoin(
|
|
1869
|
+
juniorConversations,
|
|
1870
|
+
eq3(
|
|
1871
|
+
juniorAttachments.conversationId,
|
|
1872
|
+
juniorConversations.conversationId
|
|
1873
|
+
)
|
|
1874
|
+
).where(
|
|
1875
|
+
and4(
|
|
1876
|
+
inArray3(
|
|
1877
|
+
juniorAttachments.id,
|
|
1878
|
+
rows.map((row) => row.id)
|
|
1879
|
+
),
|
|
1880
|
+
or3(
|
|
1881
|
+
isNotNull2(juniorAttachments.deleteRequestedAt),
|
|
1882
|
+
isNotNull2(juniorConversations.transcriptPurgedAt)
|
|
1883
|
+
)
|
|
1884
|
+
)
|
|
1885
|
+
);
|
|
1886
|
+
if (stillEligible.length === 0) return { deleted: 0 };
|
|
1887
|
+
const removed = await args.db.db().delete(juniorAttachments).where(
|
|
1888
|
+
inArray3(
|
|
1889
|
+
juniorAttachments.id,
|
|
1890
|
+
stillEligible.map((row) => row.id)
|
|
1891
|
+
)
|
|
1892
|
+
).returning({
|
|
1893
|
+
id: juniorAttachments.id
|
|
1894
|
+
});
|
|
1895
|
+
return { deleted: removed.length };
|
|
1896
|
+
}
|
|
1897
|
+
|
|
1556
1898
|
export {
|
|
1557
1899
|
juniorToolOutputSchema,
|
|
1558
1900
|
injectContinuationToolName,
|
|
@@ -1591,6 +1933,10 @@ export {
|
|
|
1591
1933
|
SCHEDULED_TASK_SYSTEM_ACTOR,
|
|
1592
1934
|
listPublicScheduledTasksForTeams,
|
|
1593
1935
|
createSchedulerSqlStore,
|
|
1936
|
+
readLiveAttachment,
|
|
1937
|
+
storeAttachments,
|
|
1938
|
+
requestAttachmentDeletion,
|
|
1939
|
+
collectAttachmentGarbage,
|
|
1594
1940
|
incrementStat,
|
|
1595
1941
|
readStats
|
|
1596
1942
|
};
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
} from "./chunk-EM225ITJ.js";
|
|
4
4
|
import {
|
|
5
5
|
getSlackBotToken
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-UJYA75N5.js";
|
|
7
7
|
import {
|
|
8
8
|
parseSlackChannelReferenceId
|
|
9
9
|
} from "./chunk-V7YE4WCP.js";
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
setSpanAttributes,
|
|
13
13
|
setSpanStatus,
|
|
14
14
|
withSpan
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-MKA3T2R6.js";
|
|
16
16
|
|
|
17
17
|
// src/chat/slack/client.ts
|
|
18
18
|
import { AsyncLocalStorage as AsyncLocalStorage2 } from "async_hooks";
|