@sentry/junior 0.128.1 → 0.129.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-IWQNFJMS.js → agent-hooks-ZM4WMZCN.js} +9 -9
- package/dist/api/schema/task.d.ts +152 -0
- package/dist/api/schema.d.ts +2 -0
- package/dist/api/schema.js +13 -3
- package/dist/api/tasks/routes.d.ts +4 -0
- package/dist/api.js +425 -23
- package/dist/app.js +309 -27
- package/dist/{catalog-runtime-KLSYFS4A.js → catalog-runtime-TN2GPVEI.js} +5 -5
- package/dist/chat/agent-dispatch/context.d.ts +18 -0
- package/dist/chat/event-tasks/store.d.ts +7 -1
- package/dist/chat/event-tasks/tool-support.d.ts +1 -0
- package/dist/chat/resource-events/runtime-catalog.d.ts +3 -0
- package/dist/chat/scheduled-tasks/cadence.d.ts +27 -0
- package/dist/chat/scheduled-tasks/heartbeat.d.ts +6 -0
- package/dist/chat/scheduled-tasks/identity.d.ts +6 -0
- package/dist/chat/scheduled-tasks/personal.d.ts +26 -0
- package/dist/chat/scheduled-tasks/schedule-intent.d.ts +61 -0
- package/dist/chat/scheduled-tasks/store.d.ts +77 -0
- package/dist/chat/scheduled-tasks/tool-support.d.ts +203 -0
- package/dist/chat/scheduled-tasks/tools/create.d.ts +80 -0
- package/dist/chat/scheduled-tasks/tools/delete.d.ts +56 -0
- package/dist/chat/scheduled-tasks/tools/list.d.ts +54 -0
- package/dist/chat/scheduled-tasks/tools/run-now.d.ts +56 -0
- package/dist/chat/scheduled-tasks/tools/update.d.ts +82 -0
- package/dist/chat/scheduled-tasks/tools.d.ts +6 -0
- package/dist/chat/scheduled-tasks/types.d.ts +81 -0
- package/dist/chat/tasks/read.d.ts +9 -0
- package/dist/chat/tools/scheduled-tasks.d.ts +4 -0
- package/dist/{chunk-5IR7SGRO.js → chunk-2BCQKJTX.js} +2 -2
- package/dist/{chunk-MZ6ZOWMJ.js → chunk-3N4MWF3R.js} +1 -1
- package/dist/{chunk-ETGUGGO2.js → chunk-6CMYU62S.js} +7 -7
- package/dist/{chunk-AAMF2IRC.js → chunk-6QQOLIJJ.js} +1308 -804
- package/dist/{chunk-R2LXTX4J.js → chunk-A6QQPVSH.js} +1 -1
- package/dist/chunk-BDIEEZK7.js +1470 -0
- package/dist/{chunk-AFJF3RGU.js → chunk-BVKP37NE.js} +61 -13
- package/dist/{chunk-54KP2EAH.js → chunk-CZJUBH6O.js} +12 -12
- package/dist/{chunk-O3YROBH4.js → chunk-CZQ2DSQZ.js} +1 -1
- package/dist/{chunk-O3C5BJFD.js → chunk-E4UCPRYL.js} +1 -1
- package/dist/{chunk-S2O64VXP.js → chunk-ESYXDXNX.js} +6 -6
- package/dist/{chunk-EHEACYJ6.js → chunk-GPWHBHAG.js} +1 -1
- package/dist/{chunk-PLAMHS3D.js → chunk-GURSWCI4.js} +2 -2
- package/dist/{chunk-Q5TMMCBV.js → chunk-K3U5447S.js} +1 -1
- package/dist/{chunk-SHMHHXD5.js → chunk-KB2M27DL.js} +58 -0
- package/dist/{chunk-LIJ4APSS.js → chunk-LV2BQ26V.js} +1 -1
- package/dist/{chunk-MKM5552O.js → chunk-NNRV4T2C.js} +1 -2
- package/dist/{chunk-TONH5NXR.js → chunk-P6I7LFKC.js} +1 -1
- package/dist/{chunk-J3YIO3LE.js → chunk-PQFNTLZI.js} +3 -3
- package/dist/{chunk-H4HMCSOZ.js → chunk-QAOA4GUG.js} +5 -5
- package/dist/{chunk-EOIA25WC.js → chunk-R62DRNKB.js} +2 -2
- package/dist/{chunk-OIQCRZ67.js → chunk-U23X4ASF.js} +4 -4
- package/dist/{chunk-P7UUNWC4.js → chunk-XENYUOZG.js} +4 -4
- package/dist/cli/chat.js +24 -24
- package/dist/cli/check.js +6 -6
- package/dist/cli/plugins.js +12 -12
- package/dist/cli/snapshot-create.js +9 -9
- package/dist/cli/upgrade.js +9 -17
- package/dist/db/schema/scheduled-tasks.d.ts +257 -0
- package/dist/db/schema.d.ts +258 -1
- package/dist/{db-VOU5QNLY.js → db-ZI6TBXIS.js} +7 -7
- package/dist/instrumentation.js +4 -4
- package/dist/nitro.js +2 -2
- package/dist/{oauth-callback-server-GS7FBYBC.js → oauth-callback-server-TLA4GARF.js} +17 -17
- package/dist/{runner-GSJSBI3J.js → runner-23YFRWQJ.js} +11 -11
- package/dist/{skills-DSHG54LM.js → skills-QIUG4D6M.js} +6 -6
- package/dist/{validation-25XWT6TA.js → validation-3KGEBATS.js} +6 -6
- package/dist/version.js +1 -1
- package/migrations/0016_neat_the_anarchist.sql +171 -0
- package/migrations/meta/0016_snapshot.json +1617 -0
- package/migrations/meta/_journal.json +7 -0
- package/package.json +5 -6
- package/dist/chunk-REHOYCYS.js +0 -37
package/dist/app.js
CHANGED
|
@@ -50,7 +50,7 @@ import {
|
|
|
50
50
|
startConversationWork,
|
|
51
51
|
startSlackProcessingReaction,
|
|
52
52
|
stripLeadingBotMention
|
|
53
|
-
} from "./chunk-
|
|
53
|
+
} from "./chunk-CZJUBH6O.js";
|
|
54
54
|
import "./chunk-FA6POGLH.js";
|
|
55
55
|
import {
|
|
56
56
|
ConversationTurnLifecycleService,
|
|
@@ -65,13 +65,13 @@ import {
|
|
|
65
65
|
processPluginTask,
|
|
66
66
|
requireTurnFailureEventId,
|
|
67
67
|
scheduleSessionCompletedPluginTasks
|
|
68
|
-
} from "./chunk-
|
|
68
|
+
} from "./chunk-ESYXDXNX.js";
|
|
69
69
|
import {
|
|
70
70
|
GET,
|
|
71
71
|
conversationVisibilityFromSlackChannelType,
|
|
72
72
|
resolveSlackChannelTypeFromMessage,
|
|
73
73
|
resolveSlackConversationContext
|
|
74
|
-
} from "./chunk-
|
|
74
|
+
} from "./chunk-GURSWCI4.js";
|
|
75
75
|
import "./chunk-4CODA7P5.js";
|
|
76
76
|
import "./chunk-UTL3MHPC.js";
|
|
77
77
|
import {
|
|
@@ -90,7 +90,7 @@ import {
|
|
|
90
90
|
import {
|
|
91
91
|
validatePluginEgressCredentialHooks,
|
|
92
92
|
validatePluginRegistrations
|
|
93
|
-
} from "./chunk-
|
|
93
|
+
} from "./chunk-E4UCPRYL.js";
|
|
94
94
|
import {
|
|
95
95
|
defineJuniorPlugins,
|
|
96
96
|
pluginCatalogConfigFromEnv,
|
|
@@ -112,7 +112,6 @@ import {
|
|
|
112
112
|
deliverResourceEventSubscription,
|
|
113
113
|
executeAgentRun,
|
|
114
114
|
executeCredentialedEgressRequest,
|
|
115
|
-
findMatchingEventTasks,
|
|
116
115
|
findMatchingResourceEventSubscriptions,
|
|
117
116
|
getConfigDefaults,
|
|
118
117
|
latestReportedProgress,
|
|
@@ -122,10 +121,11 @@ import {
|
|
|
122
121
|
renderSlackLegacyAttachmentText,
|
|
123
122
|
resolveDestinationVisibility,
|
|
124
123
|
resolveSandboxEgressProviderForHost,
|
|
124
|
+
sanitizeScheduledTaskPrincipal,
|
|
125
125
|
setConfigDefaults,
|
|
126
126
|
shouldEmitDevAgentTrace,
|
|
127
127
|
shouldPropagateSandboxEgressTrace
|
|
128
|
-
} from "./chunk-
|
|
128
|
+
} from "./chunk-6QQOLIJJ.js";
|
|
129
129
|
import "./chunk-DIB4GX3G.js";
|
|
130
130
|
import {
|
|
131
131
|
RetryableDeliveryError,
|
|
@@ -136,7 +136,7 @@ import {
|
|
|
136
136
|
formatProviderLabel,
|
|
137
137
|
postSlackMessage,
|
|
138
138
|
startOAuthFlow
|
|
139
|
-
} from "./chunk-
|
|
139
|
+
} from "./chunk-6CMYU62S.js";
|
|
140
140
|
import {
|
|
141
141
|
ConversationTurnBoundaryError,
|
|
142
142
|
CooperativeTurnYieldError,
|
|
@@ -192,16 +192,19 @@ import {
|
|
|
192
192
|
trimTrailingAssistantMessages,
|
|
193
193
|
updateConversationStats,
|
|
194
194
|
upsertConversationMessage
|
|
195
|
-
} from "./chunk-
|
|
195
|
+
} from "./chunk-U23X4ASF.js";
|
|
196
196
|
import "./chunk-EPBBYMNE.js";
|
|
197
197
|
import {
|
|
198
198
|
getSandboxResourceConfig,
|
|
199
199
|
setSandboxResourceConfig
|
|
200
|
-
} from "./chunk-
|
|
201
|
-
import
|
|
200
|
+
} from "./chunk-XENYUOZG.js";
|
|
201
|
+
import {
|
|
202
|
+
createSchedulerSqlStore,
|
|
203
|
+
findMatchingEventTasks
|
|
204
|
+
} from "./chunk-BDIEEZK7.js";
|
|
202
205
|
import {
|
|
203
206
|
parseSlackThreadId
|
|
204
|
-
} from "./chunk-
|
|
207
|
+
} from "./chunk-LV2BQ26V.js";
|
|
205
208
|
import "./chunk-HX236W2U.js";
|
|
206
209
|
import "./chunk-PDO5BLNM.js";
|
|
207
210
|
import "./chunk-UIE3R5XU.js";
|
|
@@ -229,7 +232,7 @@ import {
|
|
|
229
232
|
verifyEventTaskCredentialSubject,
|
|
230
233
|
verifyScheduledTaskCredentialSubject,
|
|
231
234
|
verifySlackDirectCredentialSubject
|
|
232
|
-
} from "./chunk-
|
|
235
|
+
} from "./chunk-QAOA4GUG.js";
|
|
233
236
|
import {
|
|
234
237
|
contextProvenance,
|
|
235
238
|
createSlackDestination,
|
|
@@ -240,16 +243,16 @@ import {
|
|
|
240
243
|
instructionProvenanceFor,
|
|
241
244
|
requireSlackDestination,
|
|
242
245
|
withConversationEventLock
|
|
243
|
-
} from "./chunk-
|
|
246
|
+
} from "./chunk-PQFNTLZI.js";
|
|
244
247
|
import {
|
|
245
248
|
juniorConversationEvents,
|
|
246
249
|
juniorConversations
|
|
247
|
-
} from "./chunk-
|
|
250
|
+
} from "./chunk-KB2M27DL.js";
|
|
248
251
|
import {
|
|
249
252
|
acquireActiveLock,
|
|
250
253
|
getStateAdapter,
|
|
251
254
|
sleep
|
|
252
|
-
} from "./chunk-
|
|
255
|
+
} from "./chunk-3N4MWF3R.js";
|
|
253
256
|
import {
|
|
254
257
|
STANDARD_MODEL_PROFILE,
|
|
255
258
|
botConfig,
|
|
@@ -267,16 +270,16 @@ import {
|
|
|
267
270
|
modelIdForProfile,
|
|
268
271
|
setSlackReactionConfig,
|
|
269
272
|
standardModelId
|
|
270
|
-
} from "./chunk-
|
|
273
|
+
} from "./chunk-2BCQKJTX.js";
|
|
271
274
|
import {
|
|
272
275
|
juniorDestinations
|
|
273
276
|
} from "./chunk-VFUK3X5B.js";
|
|
274
|
-
import "./chunk-
|
|
275
|
-
import "./chunk-
|
|
277
|
+
import "./chunk-GPWHBHAG.js";
|
|
278
|
+
import "./chunk-R62DRNKB.js";
|
|
276
279
|
import {
|
|
277
280
|
pluginCatalogRuntime
|
|
278
|
-
} from "./chunk-
|
|
279
|
-
import "./chunk-
|
|
281
|
+
} from "./chunk-A6QQPVSH.js";
|
|
282
|
+
import "./chunk-CZQ2DSQZ.js";
|
|
280
283
|
import {
|
|
281
284
|
credentialSubjectSchema
|
|
282
285
|
} from "./chunk-77VDLF3Z.js";
|
|
@@ -308,7 +311,7 @@ import {
|
|
|
308
311
|
withContext,
|
|
309
312
|
withLogContext,
|
|
310
313
|
withSpan
|
|
311
|
-
} from "./chunk-
|
|
314
|
+
} from "./chunk-P6I7LFKC.js";
|
|
312
315
|
import {
|
|
313
316
|
continueTrace
|
|
314
317
|
} from "./chunk-6GWA276C.js";
|
|
@@ -316,10 +319,10 @@ import "./chunk-OOUNJNMR.js";
|
|
|
316
319
|
import "./chunk-H4HBKISO.js";
|
|
317
320
|
import {
|
|
318
321
|
JUNIOR_PLUGIN_TASK_CALLBACK_ROUTE
|
|
319
|
-
} from "./chunk-
|
|
322
|
+
} from "./chunk-K3U5447S.js";
|
|
320
323
|
import {
|
|
321
324
|
JUNIOR_VERSION
|
|
322
|
-
} from "./chunk-
|
|
325
|
+
} from "./chunk-NNRV4T2C.js";
|
|
323
326
|
import "./chunk-MLKGABMK.js";
|
|
324
327
|
|
|
325
328
|
// src/app.ts
|
|
@@ -1236,6 +1239,11 @@ async function recoverConversationWork(args) {
|
|
|
1236
1239
|
return result;
|
|
1237
1240
|
}
|
|
1238
1241
|
|
|
1242
|
+
// src/chat/scheduled-tasks/heartbeat.ts
|
|
1243
|
+
import {
|
|
1244
|
+
createSlackSource
|
|
1245
|
+
} from "@sentry/junior-plugin-api";
|
|
1246
|
+
|
|
1239
1247
|
// src/chat/agent-dispatch/validation.ts
|
|
1240
1248
|
import {
|
|
1241
1249
|
dispatchOptionsSchema,
|
|
@@ -1470,6 +1478,264 @@ async function dispatchEventTask(args) {
|
|
|
1470
1478
|
plugin
|
|
1471
1479
|
});
|
|
1472
1480
|
}
|
|
1481
|
+
async function dispatchScheduledTask(args) {
|
|
1482
|
+
const plugin = "scheduler";
|
|
1483
|
+
const { credentialSubject, ...unboundOptions } = args.options;
|
|
1484
|
+
validateDispatchOptions({ ...unboundOptions });
|
|
1485
|
+
const boundSubject = credentialSubject ? bindScheduledTaskCredentialSubject({
|
|
1486
|
+
plugin,
|
|
1487
|
+
subject: credentialSubject
|
|
1488
|
+
}) : void 0;
|
|
1489
|
+
if (credentialSubject && !boundSubject) {
|
|
1490
|
+
throw new Error("Dispatch credentialSubject is not valid for this action");
|
|
1491
|
+
}
|
|
1492
|
+
const options = {
|
|
1493
|
+
...unboundOptions,
|
|
1494
|
+
...boundSubject ? { credentialSubject: boundSubject } : {}
|
|
1495
|
+
};
|
|
1496
|
+
return await dispatch({
|
|
1497
|
+
conversationWorkQueue: args.conversationWorkQueue,
|
|
1498
|
+
nowMs: args.nowMs,
|
|
1499
|
+
options,
|
|
1500
|
+
plugin
|
|
1501
|
+
});
|
|
1502
|
+
}
|
|
1503
|
+
async function getScheduledTaskDispatch(id) {
|
|
1504
|
+
return await getPluginDispatchProjection({ plugin: "scheduler", id });
|
|
1505
|
+
}
|
|
1506
|
+
|
|
1507
|
+
// src/chat/scheduled-tasks/heartbeat.ts
|
|
1508
|
+
var SCHEDULED_TASK_HEARTBEAT_LIMIT = 10;
|
|
1509
|
+
var SCHEDULE_FREQUENCY_COPY = {
|
|
1510
|
+
daily: { label: "Daily", unit: "day" },
|
|
1511
|
+
weekly: { label: "Weekly", unit: "week" },
|
|
1512
|
+
monthly: { label: "Monthly", unit: "month" },
|
|
1513
|
+
yearly: { label: "Yearly", unit: "year" }
|
|
1514
|
+
};
|
|
1515
|
+
function singleLineMetadataValue(value) {
|
|
1516
|
+
return value.replace(/[\r\n]+/g, " ").replace(/\s+/g, " ").trim();
|
|
1517
|
+
}
|
|
1518
|
+
function buildDispatchMetadata(args) {
|
|
1519
|
+
const creator = sanitizeScheduledTaskPrincipal(args.task.createdBy);
|
|
1520
|
+
if (!args.task.task.text?.trim()) {
|
|
1521
|
+
throw new Error("Scheduled task text is required");
|
|
1522
|
+
}
|
|
1523
|
+
return {
|
|
1524
|
+
creatorSlackUserId: creator.slackUserId,
|
|
1525
|
+
runId: args.run.id,
|
|
1526
|
+
schedule: singleLineMetadataValue(args.task.schedule.description),
|
|
1527
|
+
scheduleKind: args.task.schedule.kind,
|
|
1528
|
+
scheduledFor: new Date(args.run.scheduledForMs).toISOString(),
|
|
1529
|
+
runningAt: new Date(args.nowMs).toISOString(),
|
|
1530
|
+
taskId: args.task.id,
|
|
1531
|
+
timezone: args.task.schedule.timezone,
|
|
1532
|
+
...args.task.schedule.recurrence ? {
|
|
1533
|
+
recurrenceFrequency: args.task.schedule.recurrence.frequency,
|
|
1534
|
+
recurrenceInterval: String(args.task.schedule.recurrence.interval),
|
|
1535
|
+
recurrenceStartDate: args.task.schedule.recurrence.startDate
|
|
1536
|
+
} : {}
|
|
1537
|
+
};
|
|
1538
|
+
}
|
|
1539
|
+
function replyAttribution(task) {
|
|
1540
|
+
if (task.schedule.kind === "one_off") {
|
|
1541
|
+
return { label: "Scheduled task", detail: "One-time" };
|
|
1542
|
+
}
|
|
1543
|
+
const recurrence = task.schedule.recurrence;
|
|
1544
|
+
if (!recurrence) {
|
|
1545
|
+
return { label: "Scheduled task", detail: "Recurring" };
|
|
1546
|
+
}
|
|
1547
|
+
const frequency = SCHEDULE_FREQUENCY_COPY[recurrence.frequency];
|
|
1548
|
+
return recurrence.interval === 1 ? { label: "Scheduled task", detail: frequency.label } : {
|
|
1549
|
+
label: "Scheduled task",
|
|
1550
|
+
detail: `Every ${recurrence.interval} ${frequency.unit}s`
|
|
1551
|
+
};
|
|
1552
|
+
}
|
|
1553
|
+
function dispatchSource(task) {
|
|
1554
|
+
return createSlackSource({
|
|
1555
|
+
teamId: task.destination.teamId,
|
|
1556
|
+
channelId: task.destination.channelId,
|
|
1557
|
+
visibility: task.conversationAccess.visibility
|
|
1558
|
+
});
|
|
1559
|
+
}
|
|
1560
|
+
function shouldSkipRun(task, run) {
|
|
1561
|
+
if (task.status === "deleted") {
|
|
1562
|
+
return `Scheduled task ${task.id} was deleted before the run started.`;
|
|
1563
|
+
}
|
|
1564
|
+
if (task.status !== "active") {
|
|
1565
|
+
return `Scheduled task ${task.id} was ${task.status} before the run started.`;
|
|
1566
|
+
}
|
|
1567
|
+
if (task.nextRunAtMs !== run.scheduledForMs && task.runNowAtMs !== run.scheduledForMs) {
|
|
1568
|
+
return `Scheduled task ${task.id} no longer targets ${new Date(run.scheduledForMs).toISOString()}.`;
|
|
1569
|
+
}
|
|
1570
|
+
return void 0;
|
|
1571
|
+
}
|
|
1572
|
+
async function applyDispatchResult(args) {
|
|
1573
|
+
if (args.dispatch.status === "completed") {
|
|
1574
|
+
const completed = await args.store.markRunCompleted({
|
|
1575
|
+
completedAtMs: args.nowMs,
|
|
1576
|
+
resultMessageTs: args.dispatch.resultMessageTs,
|
|
1577
|
+
runId: args.run.id,
|
|
1578
|
+
startedAtMs: args.run.startedAtMs
|
|
1579
|
+
});
|
|
1580
|
+
if (!completed) return false;
|
|
1581
|
+
await args.store.updateTaskAfterRun({
|
|
1582
|
+
nowMs: args.nowMs,
|
|
1583
|
+
run: args.run,
|
|
1584
|
+
status: "completed"
|
|
1585
|
+
});
|
|
1586
|
+
return true;
|
|
1587
|
+
}
|
|
1588
|
+
if (args.dispatch.status === "blocked") {
|
|
1589
|
+
const blocked = await args.store.markRunBlocked({
|
|
1590
|
+
completedAtMs: args.nowMs,
|
|
1591
|
+
errorMessage: args.dispatch.errorMessage ?? "Dispatch blocked.",
|
|
1592
|
+
runId: args.run.id,
|
|
1593
|
+
startedAtMs: args.run.startedAtMs
|
|
1594
|
+
});
|
|
1595
|
+
if (!blocked) return false;
|
|
1596
|
+
await args.store.updateTaskAfterRun({
|
|
1597
|
+
errorMessage: blocked.errorMessage,
|
|
1598
|
+
nowMs: args.nowMs,
|
|
1599
|
+
run: args.run,
|
|
1600
|
+
status: "blocked"
|
|
1601
|
+
});
|
|
1602
|
+
return true;
|
|
1603
|
+
}
|
|
1604
|
+
if (args.dispatch.status === "failed") {
|
|
1605
|
+
const failed = await args.store.markRunFailed({
|
|
1606
|
+
completedAtMs: args.nowMs,
|
|
1607
|
+
errorMessage: args.dispatch.errorMessage ?? "Dispatch failed.",
|
|
1608
|
+
runId: args.run.id,
|
|
1609
|
+
startedAtMs: args.run.startedAtMs
|
|
1610
|
+
});
|
|
1611
|
+
if (!failed) return false;
|
|
1612
|
+
await args.store.updateTaskAfterRun({
|
|
1613
|
+
errorMessage: failed.errorMessage,
|
|
1614
|
+
nowMs: args.nowMs,
|
|
1615
|
+
run: args.run,
|
|
1616
|
+
status: "failed"
|
|
1617
|
+
});
|
|
1618
|
+
return true;
|
|
1619
|
+
}
|
|
1620
|
+
return false;
|
|
1621
|
+
}
|
|
1622
|
+
async function finishClaimedRun(args) {
|
|
1623
|
+
const finished = args.status === "blocked" ? await args.store.markRunBlocked({
|
|
1624
|
+
completedAtMs: args.nowMs,
|
|
1625
|
+
errorMessage: args.errorMessage,
|
|
1626
|
+
runId: args.run.id
|
|
1627
|
+
}) : await args.store.markRunFailed({
|
|
1628
|
+
completedAtMs: args.nowMs,
|
|
1629
|
+
errorMessage: args.errorMessage,
|
|
1630
|
+
runId: args.run.id,
|
|
1631
|
+
startedAtMs: args.run.startedAtMs
|
|
1632
|
+
});
|
|
1633
|
+
if (!finished) return;
|
|
1634
|
+
await args.store.updateTaskAfterRun({
|
|
1635
|
+
errorMessage: args.errorMessage,
|
|
1636
|
+
nowMs: args.nowMs,
|
|
1637
|
+
run: args.run,
|
|
1638
|
+
status: args.status
|
|
1639
|
+
});
|
|
1640
|
+
}
|
|
1641
|
+
async function runScheduledTaskHeartbeat(args) {
|
|
1642
|
+
const store = createSchedulerSqlStore(getDb());
|
|
1643
|
+
let processedCount = 0;
|
|
1644
|
+
let dispatchCount = 0;
|
|
1645
|
+
for (const run of await store.listIncompleteRuns()) {
|
|
1646
|
+
if (!run.dispatchId) continue;
|
|
1647
|
+
const dispatch2 = await getScheduledTaskDispatch(run.dispatchId);
|
|
1648
|
+
if (!dispatch2) {
|
|
1649
|
+
await finishClaimedRun({
|
|
1650
|
+
errorMessage: "Scheduled task dispatch record is missing.",
|
|
1651
|
+
nowMs: args.nowMs,
|
|
1652
|
+
run,
|
|
1653
|
+
status: "failed",
|
|
1654
|
+
store
|
|
1655
|
+
});
|
|
1656
|
+
continue;
|
|
1657
|
+
}
|
|
1658
|
+
if (await applyDispatchResult({ dispatch: dispatch2, nowMs: args.nowMs, run, store })) {
|
|
1659
|
+
processedCount += 1;
|
|
1660
|
+
}
|
|
1661
|
+
}
|
|
1662
|
+
for (let index = processedCount; index < SCHEDULED_TASK_HEARTBEAT_LIMIT; index += 1) {
|
|
1663
|
+
const run = await store.claimDueRun({ nowMs: args.nowMs });
|
|
1664
|
+
if (!run) break;
|
|
1665
|
+
const task = await store.getTask(run.taskId);
|
|
1666
|
+
if (!task) {
|
|
1667
|
+
await store.markRunFailed({
|
|
1668
|
+
completedAtMs: args.nowMs,
|
|
1669
|
+
errorMessage: `Scheduled task ${run.taskId} was not found`,
|
|
1670
|
+
runId: run.id
|
|
1671
|
+
});
|
|
1672
|
+
continue;
|
|
1673
|
+
}
|
|
1674
|
+
const skippedReason = shouldSkipRun(task, run);
|
|
1675
|
+
if (skippedReason) {
|
|
1676
|
+
await store.markRunSkipped({
|
|
1677
|
+
completedAtMs: args.nowMs,
|
|
1678
|
+
errorMessage: skippedReason,
|
|
1679
|
+
runId: run.id
|
|
1680
|
+
});
|
|
1681
|
+
continue;
|
|
1682
|
+
}
|
|
1683
|
+
let metadata;
|
|
1684
|
+
try {
|
|
1685
|
+
metadata = buildDispatchMetadata({ nowMs: args.nowMs, run, task });
|
|
1686
|
+
} catch (error) {
|
|
1687
|
+
await finishClaimedRun({
|
|
1688
|
+
errorMessage: error instanceof Error ? `Scheduled task dispatch metadata could not be built: ${error.message}` : "Scheduled task dispatch metadata could not be built.",
|
|
1689
|
+
nowMs: args.nowMs,
|
|
1690
|
+
run,
|
|
1691
|
+
status: "blocked",
|
|
1692
|
+
store
|
|
1693
|
+
});
|
|
1694
|
+
continue;
|
|
1695
|
+
}
|
|
1696
|
+
let dispatch2;
|
|
1697
|
+
try {
|
|
1698
|
+
dispatch2 = await dispatchScheduledTask({
|
|
1699
|
+
conversationWorkQueue: args.conversationWorkQueue,
|
|
1700
|
+
nowMs: args.nowMs,
|
|
1701
|
+
options: {
|
|
1702
|
+
idempotencyKey: run.id,
|
|
1703
|
+
...task.credentialMode === "creator" ? {
|
|
1704
|
+
credentialSubject: {
|
|
1705
|
+
type: "user",
|
|
1706
|
+
userId: task.createdBy.slackUserId,
|
|
1707
|
+
allowedWhen: "scheduled-task",
|
|
1708
|
+
taskId: task.id
|
|
1709
|
+
}
|
|
1710
|
+
} : {},
|
|
1711
|
+
destination: task.destination,
|
|
1712
|
+
destinationVisibility: task.conversationAccess.visibility,
|
|
1713
|
+
input: task.task.text,
|
|
1714
|
+
metadata,
|
|
1715
|
+
replyAttribution: replyAttribution(task),
|
|
1716
|
+
source: dispatchSource(task)
|
|
1717
|
+
}
|
|
1718
|
+
});
|
|
1719
|
+
} catch (error) {
|
|
1720
|
+
await finishClaimedRun({
|
|
1721
|
+
errorMessage: error instanceof Error ? `Scheduled task dispatch could not be created: ${error.message}` : "Scheduled task dispatch could not be created.",
|
|
1722
|
+
nowMs: args.nowMs,
|
|
1723
|
+
run,
|
|
1724
|
+
status: "blocked",
|
|
1725
|
+
store
|
|
1726
|
+
});
|
|
1727
|
+
continue;
|
|
1728
|
+
}
|
|
1729
|
+
await store.markRunDispatched({
|
|
1730
|
+
claimedAtMs: run.claimedAtMs,
|
|
1731
|
+
dispatchId: dispatch2.id,
|
|
1732
|
+
nowMs: args.nowMs,
|
|
1733
|
+
runId: run.id
|
|
1734
|
+
});
|
|
1735
|
+
dispatchCount += 1;
|
|
1736
|
+
}
|
|
1737
|
+
return dispatchCount;
|
|
1738
|
+
}
|
|
1473
1739
|
|
|
1474
1740
|
// src/chat/agent-dispatch/heartbeat.ts
|
|
1475
1741
|
var DEFAULT_PLUGIN_LIMIT = 25;
|
|
@@ -1571,6 +1837,19 @@ async function runHeartbeat(args) {
|
|
|
1571
1837
|
conversationWorkQueue: queue,
|
|
1572
1838
|
nowMs: args.nowMs
|
|
1573
1839
|
});
|
|
1840
|
+
try {
|
|
1841
|
+
const dispatchCount = await runScheduledTaskHeartbeat({
|
|
1842
|
+
conversationWorkQueue: queue,
|
|
1843
|
+
nowMs: args.nowMs
|
|
1844
|
+
});
|
|
1845
|
+
if (dispatchCount > 0) {
|
|
1846
|
+
logInfo("scheduled_tasks.heartbeat.dispatched", {
|
|
1847
|
+
"app.dispatch.count": dispatchCount
|
|
1848
|
+
});
|
|
1849
|
+
}
|
|
1850
|
+
} catch (error) {
|
|
1851
|
+
logException(error, "scheduled_tasks.heartbeat.failed");
|
|
1852
|
+
}
|
|
1574
1853
|
await runPluginHeartbeats({
|
|
1575
1854
|
conversationWorkQueue: queue,
|
|
1576
1855
|
nowMs: args.nowMs
|
|
@@ -6259,7 +6538,7 @@ function createJuniorRuntimeServices(overrides = {}) {
|
|
|
6259
6538
|
}
|
|
6260
6539
|
|
|
6261
6540
|
// src/chat/runtime/reply-executor.ts
|
|
6262
|
-
import { createSlackSource } from "@sentry/junior-plugin-api";
|
|
6541
|
+
import { createSlackSource as createSlackSource2 } from "@sentry/junior-plugin-api";
|
|
6263
6542
|
|
|
6264
6543
|
// src/chat/slack/message.ts
|
|
6265
6544
|
function getSlackMessageTs(message) {
|
|
@@ -6549,7 +6828,7 @@ function createReplyToThread(deps) {
|
|
|
6549
6828
|
const assistantThreadContext = getAssistantThreadContext(message);
|
|
6550
6829
|
const messageTs = getMessageTs(message);
|
|
6551
6830
|
const teamId = destination.teamId;
|
|
6552
|
-
const source = options.execution?.source ??
|
|
6831
|
+
const source = options.execution?.source ?? createSlackSource2({
|
|
6553
6832
|
channelId: channelId ?? destination.channelId,
|
|
6554
6833
|
messageTs,
|
|
6555
6834
|
teamId,
|
|
@@ -8958,7 +9237,7 @@ async function ingestResourceEvent(input, options) {
|
|
|
8958
9237
|
// src/chat/event-tasks/ingest.ts
|
|
8959
9238
|
import { createHash as createHash2 } from "crypto";
|
|
8960
9239
|
import {
|
|
8961
|
-
createSlackSource as
|
|
9240
|
+
createSlackSource as createSlackSource3,
|
|
8962
9241
|
RESOURCE_EVENT_SUMMARY_MAX_LENGTH,
|
|
8963
9242
|
RESOURCE_EVENT_TEXT_MAX_LENGTH,
|
|
8964
9243
|
resourceEventSchema as resourceEventSchema2
|
|
@@ -9021,7 +9300,7 @@ async function ingestEventTasks(input, options) {
|
|
|
9021
9300
|
destination: task.destination,
|
|
9022
9301
|
destinationVisibility: task.destinationVisibility,
|
|
9023
9302
|
input: eventInput(task, event),
|
|
9024
|
-
source:
|
|
9303
|
+
source: createSlackSource3({
|
|
9025
9304
|
teamId: task.destination.teamId,
|
|
9026
9305
|
channelId: task.destination.channelId,
|
|
9027
9306
|
visibility: task.destinationVisibility
|
|
@@ -9196,6 +9475,7 @@ function dashboardHostRoutePaths(dashboard) {
|
|
|
9196
9475
|
`${pagePath("locations")}/*`,
|
|
9197
9476
|
peoplePath,
|
|
9198
9477
|
`${peoplePath}/*`,
|
|
9478
|
+
pagePath("tasks"),
|
|
9199
9479
|
pagePath("system"),
|
|
9200
9480
|
`${pagePath("system")}/*`,
|
|
9201
9481
|
pagePath("plugins"),
|
|
@@ -9219,6 +9499,8 @@ function dashboardHostRoutePaths(dashboard) {
|
|
|
9219
9499
|
"/api/plugin-reports",
|
|
9220
9500
|
"/api/user-pages",
|
|
9221
9501
|
"/api/user-pages/*",
|
|
9502
|
+
"/api/tasks",
|
|
9503
|
+
"/api/tasks/*",
|
|
9222
9504
|
"/api/skills",
|
|
9223
9505
|
"/api/stats",
|
|
9224
9506
|
"/api/conversations",
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import {
|
|
2
2
|
pluginCatalogRuntime
|
|
3
|
-
} from "./chunk-
|
|
4
|
-
import "./chunk-
|
|
3
|
+
} from "./chunk-A6QQPVSH.js";
|
|
4
|
+
import "./chunk-CZQ2DSQZ.js";
|
|
5
5
|
import "./chunk-77VDLF3Z.js";
|
|
6
6
|
import "./chunk-HZF5P5UN.js";
|
|
7
7
|
import "./chunk-F3B2YJ76.js";
|
|
8
|
-
import "./chunk-
|
|
8
|
+
import "./chunk-P6I7LFKC.js";
|
|
9
9
|
import "./chunk-6GWA276C.js";
|
|
10
10
|
import "./chunk-OOUNJNMR.js";
|
|
11
11
|
import "./chunk-H4HBKISO.js";
|
|
12
|
-
import "./chunk-
|
|
13
|
-
import "./chunk-
|
|
12
|
+
import "./chunk-K3U5447S.js";
|
|
13
|
+
import "./chunk-NNRV4T2C.js";
|
|
14
14
|
import "./chunk-MLKGABMK.js";
|
|
15
15
|
export {
|
|
16
16
|
pluginCatalogRuntime
|
|
@@ -23,3 +23,21 @@ export declare function dispatchEventTask(args: {
|
|
|
23
23
|
id: string;
|
|
24
24
|
status: "already_exists" | "created";
|
|
25
25
|
}>;
|
|
26
|
+
/** Create and enqueue one core-owned scheduled task dispatch. */
|
|
27
|
+
export declare function dispatchScheduledTask(args: {
|
|
28
|
+
conversationWorkQueue: ConversationWorkQueue;
|
|
29
|
+
nowMs: number;
|
|
30
|
+
options: Omit<SlackDispatchOptions, "credentialSubject"> & {
|
|
31
|
+
credentialSubject?: {
|
|
32
|
+
allowedWhen: "scheduled-task";
|
|
33
|
+
taskId: string;
|
|
34
|
+
type: "user";
|
|
35
|
+
userId: string;
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
}): Promise<{
|
|
39
|
+
id: string;
|
|
40
|
+
status: "already_exists" | "created";
|
|
41
|
+
}>;
|
|
42
|
+
/** Read the bounded outcome for one core-owned scheduled task dispatch. */
|
|
43
|
+
export declare function getScheduledTaskDispatch(id: string): Promise<import("./types").DispatchProjection | undefined>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type ResourceEvent } from "@sentry/junior-plugin-api";
|
|
1
|
+
import { type ResourceEvent, type User } from "@sentry/junior-plugin-api";
|
|
2
2
|
import type { JuniorDatabase } from "@/db/db";
|
|
3
3
|
import { type EventTask } from "./types";
|
|
4
4
|
/** Read one event task by id. */
|
|
@@ -11,5 +11,11 @@ export declare function saveEventTask(db: JuniorDatabase, task: EventTask): Prom
|
|
|
11
11
|
export declare function deleteEventTask(db: JuniorDatabase, id: string): Promise<EventTask | undefined>;
|
|
12
12
|
/** List event tasks in one Slack workspace. */
|
|
13
13
|
export declare function listEventTasksForTeam(db: JuniorDatabase, teamId: string): Promise<EventTask[]>;
|
|
14
|
+
/** Return whether one event task was created by a viewer-linked Slack identity. */
|
|
15
|
+
export declare function eventTaskBelongsToUser(task: EventTask, user: User): boolean;
|
|
16
|
+
/** List a bounded newest-first page of event tasks created by one user. */
|
|
17
|
+
export declare function listEventTasksCreatedBy(db: JuniorDatabase, user: User, limit: number): Promise<EventTask[]>;
|
|
18
|
+
/** List event tasks whose current Slack destination is public. */
|
|
19
|
+
export declare function listPublicEventTasksForTeams(db: JuniorDatabase, teamIds: string[], limit: number): Promise<EventTask[]>;
|
|
14
20
|
/** Find every task matching one normalized resource event. */
|
|
15
21
|
export declare function findMatchingEventTasks(db: JuniorDatabase, event: ResourceEvent, teamId: string): Promise<EventTask[]>;
|
|
@@ -102,6 +102,7 @@ export declare function eventTaskMatchesDestination(task: EventTask, destination
|
|
|
102
102
|
}): boolean;
|
|
103
103
|
/** Load one task only when it belongs to this Slack channel or DM. */
|
|
104
104
|
export declare function writableEventTask(context: ToolRuntimeContext, id: string): Promise<EventTask>;
|
|
105
|
+
export declare function eventTaskTriggerAvailable(task: EventTask, catalog: ResourceEventCatalog): boolean;
|
|
105
106
|
/** Project an event task into the bounded tool-result shape. */
|
|
106
107
|
export declare function compactEventTask(task: EventTask, catalog: ResourceEventCatalog): {
|
|
107
108
|
id: string;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/** Calendar arithmetic for core-owned scheduled tasks. */
|
|
2
|
+
import type { ScheduledLocalTime, ScheduledTask, ScheduledTaskRecurrence } from "./types";
|
|
3
|
+
export interface ZonedDateTimeParts {
|
|
4
|
+
day: number;
|
|
5
|
+
hour: number;
|
|
6
|
+
minute: number;
|
|
7
|
+
month: number;
|
|
8
|
+
second: number;
|
|
9
|
+
weekday: number;
|
|
10
|
+
year: number;
|
|
11
|
+
}
|
|
12
|
+
/** Resolve a UTC timestamp into calendar parts for a named time zone. */
|
|
13
|
+
export declare function getZonedDateTimeParts(timestampMs: number, timezone: string): ZonedDateTimeParts;
|
|
14
|
+
/** Resolve local time, rejecting DST gaps and choosing the earlier instant in a fold. */
|
|
15
|
+
export declare function resolveLocalScheduleAtMs(args: {
|
|
16
|
+
date: string;
|
|
17
|
+
time: ScheduledLocalTime;
|
|
18
|
+
timezone: string;
|
|
19
|
+
}): number | undefined;
|
|
20
|
+
/** Compute the first recurring calendar occurrence strictly after a timestamp. */
|
|
21
|
+
export declare function getFirstRunAtMs(args: {
|
|
22
|
+
afterMs: number;
|
|
23
|
+
recurrence: ScheduledTaskRecurrence;
|
|
24
|
+
timezone: string;
|
|
25
|
+
}): number | undefined;
|
|
26
|
+
/** Return the next fire time after a completed run, when the task recurs. */
|
|
27
|
+
export declare function getNextRunAtMs(task: ScheduledTask, scheduledForMs: number, afterMs?: number): number | undefined;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { ConversationWorkQueue } from "@/chat/task-execution/queue";
|
|
2
|
+
/** Reconcile completed dispatches and enqueue a bounded batch of due tasks. */
|
|
3
|
+
export declare function runScheduledTaskHeartbeat(args: {
|
|
4
|
+
conversationWorkQueue: ConversationWorkQueue;
|
|
5
|
+
nowMs: number;
|
|
6
|
+
}): Promise<number>;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/** Presentation helpers for persisted scheduled-task creators. */
|
|
2
|
+
import type { ScheduledTaskPrincipal } from "./types";
|
|
3
|
+
/** Keep scheduler creator metadata from promoting Slack IDs into display names. */
|
|
4
|
+
export declare function sanitizeScheduledTaskPrincipal(principal: ScheduledTaskPrincipal): ScheduledTaskPrincipal;
|
|
5
|
+
/** Render scheduler creator metadata without inventing human profile fields. */
|
|
6
|
+
export declare function scheduledTaskPrincipalLabel(principal: ScheduledTaskPrincipal): string;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/** Viewer-scoped scheduled-task queries and mutations. */
|
|
2
|
+
import type { User } from "@sentry/junior-plugin-api";
|
|
3
|
+
import type { SchedulerStore } from "./store";
|
|
4
|
+
import type { ScheduledTask } from "./types";
|
|
5
|
+
type PersonalScheduledTaskStore = Pick<SchedulerStore, "getTask" | "listTasksCreatedBy" | "saveTask">;
|
|
6
|
+
export interface ViewerScheduledTaskPage {
|
|
7
|
+
nextCursor?: string;
|
|
8
|
+
tasks: ScheduledTask[];
|
|
9
|
+
}
|
|
10
|
+
export interface ViewerScheduledTaskPageInput {
|
|
11
|
+
cursor?: string;
|
|
12
|
+
limit: number;
|
|
13
|
+
query?: string;
|
|
14
|
+
}
|
|
15
|
+
export declare class InvalidScheduledTaskCursorError extends Error {
|
|
16
|
+
constructor();
|
|
17
|
+
}
|
|
18
|
+
export declare class PersonalScheduledTaskNotFoundError extends Error {
|
|
19
|
+
constructor();
|
|
20
|
+
}
|
|
21
|
+
/** Build scheduled-task operations limited to tasks created by one user. */
|
|
22
|
+
export declare function createViewerScheduledTasks(store: PersonalScheduledTaskStore, user: User): {
|
|
23
|
+
delete(id: string, nowMs?: number): Promise<void>;
|
|
24
|
+
list(input: ViewerScheduledTaskPageInput): Promise<ViewerScheduledTaskPage>;
|
|
25
|
+
};
|
|
26
|
+
export {};
|