@sentry/junior-scheduler 0.72.0 → 0.73.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/index.js +39 -26
- package/dist/schedule-tools.d.ts +6 -6
- package/dist/types.d.ts +2 -2
- package/package.json +2 -2
- package/src/plugin.ts +15 -9
- package/src/schedule-tools.ts +38 -28
- package/src/store.ts +2 -1
- package/src/types.ts +2 -2
package/dist/index.js
CHANGED
|
@@ -125,7 +125,8 @@ function buildScheduledTaskRunPrompt(args) {
|
|
|
125
125
|
// src/store.ts
|
|
126
126
|
import {
|
|
127
127
|
agentPluginCredentialSubjectSchema,
|
|
128
|
-
destinationSchema
|
|
128
|
+
destinationSchema,
|
|
129
|
+
isSlackDestination
|
|
129
130
|
} from "@sentry/junior-plugin-api";
|
|
130
131
|
|
|
131
132
|
// src/cadence.ts
|
|
@@ -662,7 +663,7 @@ function parseStoredTask(value) {
|
|
|
662
663
|
}
|
|
663
664
|
const record = value;
|
|
664
665
|
const destination = destinationSchema.safeParse(record.destination);
|
|
665
|
-
if (!destination.success) {
|
|
666
|
+
if (!destination.success || !isSlackDestination(destination.data)) {
|
|
666
667
|
return void 0;
|
|
667
668
|
}
|
|
668
669
|
const credentialSubject = record.credentialSubject === void 0 ? void 0 : agentPluginCredentialSubjectSchema.safeParse(record.credentialSubject);
|
|
@@ -1050,7 +1051,8 @@ import { Type } from "@sinclair/typebox";
|
|
|
1050
1051
|
import {
|
|
1051
1052
|
AgentPluginToolInputError,
|
|
1052
1053
|
agentPluginCredentialSubjectSchema as agentPluginCredentialSubjectSchema2,
|
|
1053
|
-
destinationSchema as destinationSchema2
|
|
1054
|
+
destinationSchema as destinationSchema2,
|
|
1055
|
+
isSlackDestination as isSlackDestination2
|
|
1054
1056
|
} from "@sentry/junior-plugin-api";
|
|
1055
1057
|
var TASK_ID_PREFIX = "sched";
|
|
1056
1058
|
var MAX_LISTED_TASKS = 50;
|
|
@@ -1058,30 +1060,36 @@ var DEFAULT_SCHEDULE_TIMEZONE = "America/Los_Angeles";
|
|
|
1058
1060
|
function throwToolInputError(error) {
|
|
1059
1061
|
throw new AgentPluginToolInputError(error);
|
|
1060
1062
|
}
|
|
1061
|
-
function
|
|
1062
|
-
const parsed = destinationSchema2.safeParse(context.
|
|
1063
|
+
function requireActiveConversation(context) {
|
|
1064
|
+
const parsed = destinationSchema2.safeParse(context.source);
|
|
1063
1065
|
if (!parsed.success) {
|
|
1064
|
-
const
|
|
1066
|
+
const source = context.source;
|
|
1065
1067
|
const issues = parsed.error.issues;
|
|
1066
|
-
if (!
|
|
1067
|
-
throwToolInputError("No active Slack
|
|
1068
|
+
if (!source || source.platform !== "slack") {
|
|
1069
|
+
throwToolInputError("No active Slack conversation is available.");
|
|
1068
1070
|
}
|
|
1069
1071
|
if (issues.some((issue) => issue.code === "unrecognized_keys")) {
|
|
1070
1072
|
throwToolInputError(
|
|
1071
|
-
"Active Slack
|
|
1073
|
+
"Active Slack conversation must not include unknown fields."
|
|
1072
1074
|
);
|
|
1073
1075
|
}
|
|
1074
1076
|
if (issues.some((issue) => issue.path[0] === "channelId")) {
|
|
1075
|
-
throwToolInputError("Active Slack
|
|
1077
|
+
throwToolInputError("Active Slack conversation channel is invalid.");
|
|
1076
1078
|
}
|
|
1077
1079
|
if (issues.some((issue) => issue.path[0] === "teamId")) {
|
|
1078
|
-
throwToolInputError("Active Slack
|
|
1080
|
+
throwToolInputError("Active Slack conversation workspace is invalid.");
|
|
1079
1081
|
}
|
|
1080
|
-
throwToolInputError("No active Slack
|
|
1082
|
+
throwToolInputError("No active Slack conversation is available.");
|
|
1083
|
+
}
|
|
1084
|
+
if (!isSlackDestination2(parsed.data)) {
|
|
1085
|
+
throwToolInputError("No active Slack conversation is available.");
|
|
1081
1086
|
}
|
|
1082
1087
|
return parsed.data;
|
|
1083
1088
|
}
|
|
1084
1089
|
function requireRequester(context) {
|
|
1090
|
+
if (context.requester?.platform !== "slack") {
|
|
1091
|
+
throwToolInputError("No active Slack requester context is available.");
|
|
1092
|
+
}
|
|
1085
1093
|
const userId = context.requester?.userId?.trim();
|
|
1086
1094
|
if (!userId || userId.toLowerCase() === "unknown") {
|
|
1087
1095
|
throwToolInputError("No active Slack requester context is available.");
|
|
@@ -1132,13 +1140,13 @@ function sameDestination(task, destination) {
|
|
|
1132
1140
|
return taskDestination.platform === "slack" && taskDestination.teamId === destination.teamId && taskDestination.channelId === destination.channelId;
|
|
1133
1141
|
}
|
|
1134
1142
|
async function getWritableTask(args) {
|
|
1135
|
-
const destination =
|
|
1143
|
+
const destination = requireActiveConversation(args.context);
|
|
1136
1144
|
const task = await createSchedulerStore(args.context.state).getTask(
|
|
1137
1145
|
args.taskId
|
|
1138
1146
|
);
|
|
1139
1147
|
if (!task || task.status === "deleted") {
|
|
1140
1148
|
throwToolInputError(
|
|
1141
|
-
"Scheduled task was not found in the active
|
|
1149
|
+
"Scheduled task was not found in the active Slack conversation."
|
|
1142
1150
|
);
|
|
1143
1151
|
}
|
|
1144
1152
|
if (!sameDestination(task, destination)) {
|
|
@@ -1281,7 +1289,7 @@ function createSlackScheduleCreateTaskTool(context) {
|
|
|
1281
1289
|
)
|
|
1282
1290
|
}),
|
|
1283
1291
|
execute: async (input) => {
|
|
1284
|
-
const destination =
|
|
1292
|
+
const destination = requireActiveConversation(context);
|
|
1285
1293
|
const requester = requireRequester(context);
|
|
1286
1294
|
const nowMs = Date.now();
|
|
1287
1295
|
const timezone = input.timezone ?? getDefaultScheduleTimezone();
|
|
@@ -1340,7 +1348,7 @@ function createSlackScheduleListTasksTool(context) {
|
|
|
1340
1348
|
annotations: { readOnlyHint: true, destructiveHint: false },
|
|
1341
1349
|
inputSchema: Type.Object({}),
|
|
1342
1350
|
execute: async () => {
|
|
1343
|
-
const destination =
|
|
1351
|
+
const destination = requireActiveConversation(context);
|
|
1344
1352
|
const tasks = await createSchedulerStore(context.state).listTasksForTeam(
|
|
1345
1353
|
destination.teamId
|
|
1346
1354
|
);
|
|
@@ -1358,12 +1366,12 @@ function createSlackScheduleListTasksTool(context) {
|
|
|
1358
1366
|
}
|
|
1359
1367
|
function createSlackScheduleUpdateTaskTool(context) {
|
|
1360
1368
|
return tool({
|
|
1361
|
-
description: "Edit, pause, resume, or reschedule an existing Junior scheduled task in the active Slack conversation. Use only task IDs returned for this
|
|
1369
|
+
description: "Edit, pause, resume, or reschedule an existing Junior scheduled task in the active Slack conversation. Use only task IDs returned for this conversation. Do not move scheduled tasks across conversations.",
|
|
1362
1370
|
executionMode: "sequential",
|
|
1363
1371
|
inputSchema: Type.Object({
|
|
1364
1372
|
task_id: Type.String({
|
|
1365
1373
|
minLength: 1,
|
|
1366
|
-
description: "ID of the task to update. Must be from this active Slack
|
|
1374
|
+
description: "ID of the task to update. Must be from this active Slack conversation."
|
|
1367
1375
|
}),
|
|
1368
1376
|
task: Type.Optional(Type.String({ minLength: 1, maxLength: 4e3 })),
|
|
1369
1377
|
schedule: Type.Optional(Type.String({ minLength: 1, maxLength: 300 })),
|
|
@@ -1459,12 +1467,12 @@ function createSlackScheduleUpdateTaskTool(context) {
|
|
|
1459
1467
|
}
|
|
1460
1468
|
function createSlackScheduleDeleteTaskTool(context) {
|
|
1461
1469
|
return tool({
|
|
1462
|
-
description: "Delete one scheduled Junior task from the active Slack conversation. Use only task IDs returned for this
|
|
1470
|
+
description: "Delete one scheduled Junior task from the active Slack conversation. Use only task IDs returned for this conversation. Do not delete schedules from threads, other channels, or another user's DM.",
|
|
1463
1471
|
executionMode: "sequential",
|
|
1464
1472
|
inputSchema: Type.Object({
|
|
1465
1473
|
task_id: Type.String({
|
|
1466
1474
|
minLength: 1,
|
|
1467
|
-
description: "ID of the task to delete. Must be from this active Slack
|
|
1475
|
+
description: "ID of the task to delete. Must be from this active Slack conversation."
|
|
1468
1476
|
})
|
|
1469
1477
|
}),
|
|
1470
1478
|
execute: async ({ task_id }) => {
|
|
@@ -1487,12 +1495,12 @@ function createSlackScheduleDeleteTaskTool(context) {
|
|
|
1487
1495
|
}
|
|
1488
1496
|
function createSlackScheduleRunTaskNowTool(context) {
|
|
1489
1497
|
return tool({
|
|
1490
|
-
description: "Queue an existing active scheduled Junior task to run as soon as possible, without changing its cadence. Use when the user asks to run an existing scheduled task now. Use only task IDs returned for this
|
|
1498
|
+
description: "Queue an existing active scheduled Junior task to run as soon as possible, without changing its cadence. Use when the user asks to run an existing scheduled task now. Use only task IDs returned for this conversation.",
|
|
1491
1499
|
executionMode: "sequential",
|
|
1492
1500
|
inputSchema: Type.Object({
|
|
1493
1501
|
task_id: Type.String({
|
|
1494
1502
|
minLength: 1,
|
|
1495
|
-
description: "ID of the active task to run now. Must be from this active Slack
|
|
1503
|
+
description: "ID of the active task to run now. Must be from this active Slack conversation."
|
|
1496
1504
|
})
|
|
1497
1505
|
}),
|
|
1498
1506
|
execute: async ({ task_id }) => {
|
|
@@ -1535,9 +1543,13 @@ function shouldSkipRun(task, run) {
|
|
|
1535
1543
|
}
|
|
1536
1544
|
function createSchedulerToolContext(ctx) {
|
|
1537
1545
|
return {
|
|
1538
|
-
credentialSubject: ctx.credentialSubject,
|
|
1539
|
-
|
|
1540
|
-
|
|
1546
|
+
credentialSubject: ctx.slack?.credentialSubject,
|
|
1547
|
+
source: ctx.source.platform === "slack" ? {
|
|
1548
|
+
platform: "slack",
|
|
1549
|
+
teamId: ctx.source.teamId,
|
|
1550
|
+
channelId: ctx.source.channelId
|
|
1551
|
+
} : void 0,
|
|
1552
|
+
requester: ctx.requester?.platform === "slack" ? ctx.requester : void 0,
|
|
1541
1553
|
state: ctx.state,
|
|
1542
1554
|
userText: ctx.userText
|
|
1543
1555
|
};
|
|
@@ -1785,12 +1797,13 @@ function createSchedulerPlugin() {
|
|
|
1785
1797
|
return defineJuniorPlugin({
|
|
1786
1798
|
manifest: {
|
|
1787
1799
|
name: "scheduler",
|
|
1800
|
+
displayName: "Scheduler",
|
|
1788
1801
|
description: "Scheduled Junior task management and heartbeat dispatch"
|
|
1789
1802
|
},
|
|
1790
1803
|
legacyStatePrefixes: ["junior:scheduler"],
|
|
1791
1804
|
hooks: {
|
|
1792
1805
|
tools(ctx) {
|
|
1793
|
-
if (
|
|
1806
|
+
if (ctx.source.platform !== "slack" || ctx.requester?.platform !== "slack") {
|
|
1794
1807
|
return {};
|
|
1795
1808
|
}
|
|
1796
1809
|
const context = createSchedulerToolContext(ctx);
|
package/dist/schedule-tools.d.ts
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
import { type AgentPluginCredentialSubject, type
|
|
1
|
+
import { type AgentPluginCredentialSubject, type AgentPluginState, type AgentPluginToolDefinition, type SlackDestination, type SlackRequester } from "@sentry/junior-plugin-api";
|
|
2
2
|
export interface SchedulerToolContext {
|
|
3
3
|
credentialSubject?: AgentPluginCredentialSubject;
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
requester?: SlackRequester;
|
|
5
|
+
source?: SlackDestination;
|
|
6
6
|
state: AgentPluginState;
|
|
7
7
|
userText?: string;
|
|
8
8
|
}
|
|
9
9
|
/** Create a tool that stores a scheduled task for the active Slack context. */
|
|
10
10
|
export declare function createSlackScheduleCreateTaskTool(context: SchedulerToolContext): AgentPluginToolDefinition<any>;
|
|
11
|
-
/** Create a tool that lists scheduled tasks for the active Slack
|
|
11
|
+
/** Create a tool that lists scheduled tasks for the active Slack conversation. */
|
|
12
12
|
export declare function createSlackScheduleListTasksTool(context: SchedulerToolContext): AgentPluginToolDefinition<any>;
|
|
13
|
-
/** Create a tool that edits a scheduled task in the active Slack
|
|
13
|
+
/** Create a tool that edits a scheduled task in the active Slack conversation. */
|
|
14
14
|
export declare function createSlackScheduleUpdateTaskTool(context: SchedulerToolContext): AgentPluginToolDefinition<any>;
|
|
15
|
-
/** Create a tool that removes a scheduled task from the active Slack
|
|
15
|
+
/** Create a tool that removes a scheduled task from the active Slack conversation. */
|
|
16
16
|
export declare function createSlackScheduleDeleteTaskTool(context: SchedulerToolContext): AgentPluginToolDefinition<any>;
|
|
17
17
|
/** Create a tool that marks an existing scheduled task due immediately. */
|
|
18
18
|
export declare function createSlackScheduleRunTaskNowTool(context: SchedulerToolContext): AgentPluginToolDefinition<any>;
|
package/dist/types.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AgentPluginCredentialSubject,
|
|
1
|
+
import type { AgentPluginCredentialSubject, SlackDestination } from "@sentry/junior-plugin-api";
|
|
2
2
|
export type ScheduledTaskStatus = "active" | "paused" | "blocked" | "deleted";
|
|
3
3
|
export type ScheduledRunStatus = "pending" | "running" | "completed" | "failed" | "blocked" | "skipped";
|
|
4
4
|
export interface ScheduledTaskPrincipal {
|
|
@@ -47,7 +47,7 @@ export interface ScheduledTask {
|
|
|
47
47
|
createdBy: ScheduledTaskPrincipal;
|
|
48
48
|
conversationAccess?: ScheduledTaskConversationAccess;
|
|
49
49
|
credentialSubject?: AgentPluginCredentialSubject;
|
|
50
|
-
destination:
|
|
50
|
+
destination: SlackDestination;
|
|
51
51
|
executionActor?: ScheduledTaskExecutionActor;
|
|
52
52
|
lastRunAtMs?: number;
|
|
53
53
|
nextRunAtMs?: number;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sentry/junior-scheduler",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.73.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
],
|
|
24
24
|
"dependencies": {
|
|
25
25
|
"@sinclair/typebox": "^0.34.49",
|
|
26
|
-
"@sentry/junior-plugin-api": "0.
|
|
26
|
+
"@sentry/junior-plugin-api": "0.73.0"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
29
|
"@types/node": "^25.9.1",
|
package/src/plugin.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
defineJuniorPlugin,
|
|
3
|
-
type Destination,
|
|
4
3
|
type Dispatch,
|
|
5
4
|
type AgentPluginToolDefinition,
|
|
6
5
|
type PluginOperationalReportContent,
|
|
6
|
+
type SlackDestination,
|
|
7
7
|
type ToolRegistrationHookContext,
|
|
8
8
|
} from "@sentry/junior-plugin-api";
|
|
9
9
|
import { buildScheduledTaskRunPrompt } from "./prompt";
|
|
@@ -54,10 +54,16 @@ function createSchedulerToolContext(
|
|
|
54
54
|
ctx: ToolRegistrationHookContext,
|
|
55
55
|
): SchedulerToolContext {
|
|
56
56
|
return {
|
|
57
|
-
credentialSubject: ctx.credentialSubject,
|
|
58
|
-
|
|
59
|
-
ctx.
|
|
60
|
-
|
|
57
|
+
credentialSubject: ctx.slack?.credentialSubject,
|
|
58
|
+
source:
|
|
59
|
+
ctx.source.platform === "slack"
|
|
60
|
+
? {
|
|
61
|
+
platform: "slack",
|
|
62
|
+
teamId: ctx.source.teamId,
|
|
63
|
+
channelId: ctx.source.channelId,
|
|
64
|
+
}
|
|
65
|
+
: undefined,
|
|
66
|
+
requester: ctx.requester?.platform === "slack" ? ctx.requester : undefined,
|
|
61
67
|
state: ctx.state,
|
|
62
68
|
userText: ctx.userText,
|
|
63
69
|
};
|
|
@@ -183,7 +189,7 @@ function formatTimestamp(timestampMs: number | undefined): string {
|
|
|
183
189
|
: "none";
|
|
184
190
|
}
|
|
185
191
|
|
|
186
|
-
function destinationLabel(destination:
|
|
192
|
+
function destinationLabel(destination: SlackDestination): string {
|
|
187
193
|
if (destination.channelId.startsWith("D")) {
|
|
188
194
|
return "Direct Message";
|
|
189
195
|
}
|
|
@@ -358,15 +364,15 @@ export function createSchedulerPlugin() {
|
|
|
358
364
|
return defineJuniorPlugin({
|
|
359
365
|
manifest: {
|
|
360
366
|
name: "scheduler",
|
|
367
|
+
displayName: "Scheduler",
|
|
361
368
|
description: "Scheduled Junior task management and heartbeat dispatch",
|
|
362
369
|
},
|
|
363
370
|
legacyStatePrefixes: ["junior:scheduler"],
|
|
364
371
|
hooks: {
|
|
365
372
|
tools(ctx) {
|
|
366
373
|
if (
|
|
367
|
-
|
|
368
|
-
ctx.
|
|
369
|
-
!ctx.requester?.userId
|
|
374
|
+
ctx.source.platform !== "slack" ||
|
|
375
|
+
ctx.requester?.platform !== "slack"
|
|
370
376
|
) {
|
|
371
377
|
return {} as Record<string, AgentPluginToolDefinition<any>>;
|
|
372
378
|
}
|
package/src/schedule-tools.ts
CHANGED
|
@@ -4,11 +4,12 @@ import {
|
|
|
4
4
|
AgentPluginToolInputError,
|
|
5
5
|
agentPluginCredentialSubjectSchema,
|
|
6
6
|
destinationSchema,
|
|
7
|
+
isSlackDestination,
|
|
7
8
|
type AgentPluginCredentialSubject,
|
|
8
|
-
type Destination,
|
|
9
|
-
type Requester,
|
|
10
9
|
type AgentPluginState,
|
|
11
10
|
type AgentPluginToolDefinition,
|
|
11
|
+
type SlackDestination,
|
|
12
|
+
type SlackRequester,
|
|
12
13
|
} from "@sentry/junior-plugin-api";
|
|
13
14
|
import { buildCalendarRecurrence, parseScheduleTimestamp } from "./cadence";
|
|
14
15
|
import { sanitizeScheduledTaskPrincipal } from "./identity";
|
|
@@ -25,8 +26,8 @@ import type {
|
|
|
25
26
|
|
|
26
27
|
export interface SchedulerToolContext {
|
|
27
28
|
credentialSubject?: AgentPluginCredentialSubject;
|
|
28
|
-
|
|
29
|
-
|
|
29
|
+
requester?: SlackRequester;
|
|
30
|
+
source?: SlackDestination;
|
|
30
31
|
state: AgentPluginState;
|
|
31
32
|
userText?: string;
|
|
32
33
|
}
|
|
@@ -44,26 +45,32 @@ function throwToolInputError(error: string): never {
|
|
|
44
45
|
throw new AgentPluginToolInputError(error);
|
|
45
46
|
}
|
|
46
47
|
|
|
47
|
-
function
|
|
48
|
-
|
|
48
|
+
function requireActiveConversation(
|
|
49
|
+
context: SchedulerToolContext,
|
|
50
|
+
): SlackDestination {
|
|
51
|
+
const parsed = destinationSchema.safeParse(context.source);
|
|
49
52
|
if (!parsed.success) {
|
|
50
|
-
const
|
|
53
|
+
const source = context.source as Partial<SlackDestination> | undefined;
|
|
51
54
|
const issues = parsed.error.issues as readonly SchemaIssue[];
|
|
52
|
-
if (!
|
|
53
|
-
throwToolInputError("No active Slack
|
|
55
|
+
if (!source || source.platform !== "slack") {
|
|
56
|
+
throwToolInputError("No active Slack conversation is available.");
|
|
54
57
|
}
|
|
55
58
|
if (issues.some((issue) => issue.code === "unrecognized_keys")) {
|
|
56
59
|
throwToolInputError(
|
|
57
|
-
"Active Slack
|
|
60
|
+
"Active Slack conversation must not include unknown fields.",
|
|
58
61
|
);
|
|
59
62
|
}
|
|
60
63
|
if (issues.some((issue) => issue.path[0] === "channelId")) {
|
|
61
|
-
throwToolInputError("Active Slack
|
|
64
|
+
throwToolInputError("Active Slack conversation channel is invalid.");
|
|
62
65
|
}
|
|
63
66
|
if (issues.some((issue) => issue.path[0] === "teamId")) {
|
|
64
|
-
throwToolInputError("Active Slack
|
|
67
|
+
throwToolInputError("Active Slack conversation workspace is invalid.");
|
|
65
68
|
}
|
|
66
|
-
throwToolInputError("No active Slack
|
|
69
|
+
throwToolInputError("No active Slack conversation is available.");
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (!isSlackDestination(parsed.data)) {
|
|
73
|
+
throwToolInputError("No active Slack conversation is available.");
|
|
67
74
|
}
|
|
68
75
|
|
|
69
76
|
return parsed.data;
|
|
@@ -72,6 +79,9 @@ function requireActiveDestination(context: SchedulerToolContext): Destination {
|
|
|
72
79
|
function requireRequester(
|
|
73
80
|
context: SchedulerToolContext,
|
|
74
81
|
): ScheduledTaskPrincipal {
|
|
82
|
+
if (context.requester?.platform !== "slack") {
|
|
83
|
+
throwToolInputError("No active Slack requester context is available.");
|
|
84
|
+
}
|
|
75
85
|
const userId = context.requester?.userId?.trim();
|
|
76
86
|
if (!userId || userId.toLowerCase() === "unknown") {
|
|
77
87
|
throwToolInputError("No active Slack requester context is available.");
|
|
@@ -99,7 +109,7 @@ function isDmChannel(channelId: string): boolean {
|
|
|
99
109
|
}
|
|
100
110
|
|
|
101
111
|
function getConversationAccess(
|
|
102
|
-
destination:
|
|
112
|
+
destination: SlackDestination,
|
|
103
113
|
): ScheduledTaskConversationAccess {
|
|
104
114
|
if (isDmChannel(destination.channelId)) {
|
|
105
115
|
return { audience: "direct", visibility: "private" };
|
|
@@ -139,7 +149,7 @@ function getCredentialSubject(args: {
|
|
|
139
149
|
|
|
140
150
|
function sameDestination(
|
|
141
151
|
task: ScheduledTask,
|
|
142
|
-
destination:
|
|
152
|
+
destination: SlackDestination,
|
|
143
153
|
): boolean {
|
|
144
154
|
const taskDestination = task.destination;
|
|
145
155
|
return (
|
|
@@ -153,14 +163,14 @@ async function getWritableTask(args: {
|
|
|
153
163
|
context: SchedulerToolContext;
|
|
154
164
|
taskId: string;
|
|
155
165
|
}): Promise<ScheduledTask> {
|
|
156
|
-
const destination =
|
|
166
|
+
const destination = requireActiveConversation(args.context);
|
|
157
167
|
|
|
158
168
|
const task = await createSchedulerStore(args.context.state).getTask(
|
|
159
169
|
args.taskId,
|
|
160
170
|
);
|
|
161
171
|
if (!task || task.status === "deleted") {
|
|
162
172
|
throwToolInputError(
|
|
163
|
-
"Scheduled task was not found in the active
|
|
173
|
+
"Scheduled task was not found in the active Slack conversation.",
|
|
164
174
|
);
|
|
165
175
|
}
|
|
166
176
|
|
|
@@ -369,7 +379,7 @@ export function createSlackScheduleCreateTaskTool(
|
|
|
369
379
|
),
|
|
370
380
|
}),
|
|
371
381
|
execute: async (input) => {
|
|
372
|
-
const destination =
|
|
382
|
+
const destination = requireActiveConversation(context);
|
|
373
383
|
const requester = requireRequester(context);
|
|
374
384
|
|
|
375
385
|
const nowMs = Date.now();
|
|
@@ -426,7 +436,7 @@ export function createSlackScheduleCreateTaskTool(
|
|
|
426
436
|
});
|
|
427
437
|
}
|
|
428
438
|
|
|
429
|
-
/** Create a tool that lists scheduled tasks for the active Slack
|
|
439
|
+
/** Create a tool that lists scheduled tasks for the active Slack conversation. */
|
|
430
440
|
export function createSlackScheduleListTasksTool(
|
|
431
441
|
context: SchedulerToolContext,
|
|
432
442
|
) {
|
|
@@ -436,7 +446,7 @@ export function createSlackScheduleListTasksTool(
|
|
|
436
446
|
annotations: { readOnlyHint: true, destructiveHint: false },
|
|
437
447
|
inputSchema: Type.Object({}),
|
|
438
448
|
execute: async () => {
|
|
439
|
-
const destination =
|
|
449
|
+
const destination = requireActiveConversation(context);
|
|
440
450
|
|
|
441
451
|
const tasks = await createSchedulerStore(context.state).listTasksForTeam(
|
|
442
452
|
destination.teamId,
|
|
@@ -455,19 +465,19 @@ export function createSlackScheduleListTasksTool(
|
|
|
455
465
|
});
|
|
456
466
|
}
|
|
457
467
|
|
|
458
|
-
/** Create a tool that edits a scheduled task in the active Slack
|
|
468
|
+
/** Create a tool that edits a scheduled task in the active Slack conversation. */
|
|
459
469
|
export function createSlackScheduleUpdateTaskTool(
|
|
460
470
|
context: SchedulerToolContext,
|
|
461
471
|
) {
|
|
462
472
|
return tool({
|
|
463
473
|
description:
|
|
464
|
-
"Edit, pause, resume, or reschedule an existing Junior scheduled task in the active Slack conversation. Use only task IDs returned for this
|
|
474
|
+
"Edit, pause, resume, or reschedule an existing Junior scheduled task in the active Slack conversation. Use only task IDs returned for this conversation. Do not move scheduled tasks across conversations.",
|
|
465
475
|
executionMode: "sequential",
|
|
466
476
|
inputSchema: Type.Object({
|
|
467
477
|
task_id: Type.String({
|
|
468
478
|
minLength: 1,
|
|
469
479
|
description:
|
|
470
|
-
"ID of the task to update. Must be from this active Slack
|
|
480
|
+
"ID of the task to update. Must be from this active Slack conversation.",
|
|
471
481
|
}),
|
|
472
482
|
task: Type.Optional(Type.String({ minLength: 1, maxLength: 4000 })),
|
|
473
483
|
schedule: Type.Optional(Type.String({ minLength: 1, maxLength: 300 })),
|
|
@@ -573,19 +583,19 @@ export function createSlackScheduleUpdateTaskTool(
|
|
|
573
583
|
});
|
|
574
584
|
}
|
|
575
585
|
|
|
576
|
-
/** Create a tool that removes a scheduled task from the active Slack
|
|
586
|
+
/** Create a tool that removes a scheduled task from the active Slack conversation. */
|
|
577
587
|
export function createSlackScheduleDeleteTaskTool(
|
|
578
588
|
context: SchedulerToolContext,
|
|
579
589
|
) {
|
|
580
590
|
return tool({
|
|
581
591
|
description:
|
|
582
|
-
"Delete one scheduled Junior task from the active Slack conversation. Use only task IDs returned for this
|
|
592
|
+
"Delete one scheduled Junior task from the active Slack conversation. Use only task IDs returned for this conversation. Do not delete schedules from threads, other channels, or another user's DM.",
|
|
583
593
|
executionMode: "sequential",
|
|
584
594
|
inputSchema: Type.Object({
|
|
585
595
|
task_id: Type.String({
|
|
586
596
|
minLength: 1,
|
|
587
597
|
description:
|
|
588
|
-
"ID of the task to delete. Must be from this active Slack
|
|
598
|
+
"ID of the task to delete. Must be from this active Slack conversation.",
|
|
589
599
|
}),
|
|
590
600
|
}),
|
|
591
601
|
execute: async ({ task_id }) => {
|
|
@@ -615,13 +625,13 @@ export function createSlackScheduleRunTaskNowTool(
|
|
|
615
625
|
) {
|
|
616
626
|
return tool({
|
|
617
627
|
description:
|
|
618
|
-
"Queue an existing active scheduled Junior task to run as soon as possible, without changing its cadence. Use when the user asks to run an existing scheduled task now. Use only task IDs returned for this
|
|
628
|
+
"Queue an existing active scheduled Junior task to run as soon as possible, without changing its cadence. Use when the user asks to run an existing scheduled task now. Use only task IDs returned for this conversation.",
|
|
619
629
|
executionMode: "sequential",
|
|
620
630
|
inputSchema: Type.Object({
|
|
621
631
|
task_id: Type.String({
|
|
622
632
|
minLength: 1,
|
|
623
633
|
description:
|
|
624
|
-
"ID of the active task to run now. Must be from this active Slack
|
|
634
|
+
"ID of the active task to run now. Must be from this active Slack conversation.",
|
|
625
635
|
}),
|
|
626
636
|
}),
|
|
627
637
|
execute: async ({ task_id }) => {
|
package/src/store.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
agentPluginCredentialSubjectSchema,
|
|
3
3
|
destinationSchema,
|
|
4
|
+
isSlackDestination,
|
|
4
5
|
type AgentPluginReadState,
|
|
5
6
|
type AgentPluginState,
|
|
6
7
|
} from "@sentry/junior-plugin-api";
|
|
@@ -363,7 +364,7 @@ function parseStoredTask(value: unknown): ScheduledTask | undefined {
|
|
|
363
364
|
}
|
|
364
365
|
const record = value as Partial<ScheduledTask>;
|
|
365
366
|
const destination = destinationSchema.safeParse(record.destination);
|
|
366
|
-
if (!destination.success) {
|
|
367
|
+
if (!destination.success || !isSlackDestination(destination.data)) {
|
|
367
368
|
return undefined;
|
|
368
369
|
}
|
|
369
370
|
const credentialSubject =
|
package/src/types.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
AgentPluginCredentialSubject,
|
|
3
|
-
|
|
3
|
+
SlackDestination,
|
|
4
4
|
} from "@sentry/junior-plugin-api";
|
|
5
5
|
|
|
6
6
|
export type ScheduledTaskStatus = "active" | "paused" | "blocked" | "deleted";
|
|
@@ -72,7 +72,7 @@ export interface ScheduledTask {
|
|
|
72
72
|
createdBy: ScheduledTaskPrincipal;
|
|
73
73
|
conversationAccess?: ScheduledTaskConversationAccess;
|
|
74
74
|
credentialSubject?: AgentPluginCredentialSubject;
|
|
75
|
-
destination:
|
|
75
|
+
destination: SlackDestination;
|
|
76
76
|
executionActor?: ScheduledTaskExecutionActor;
|
|
77
77
|
lastRunAtMs?: number;
|
|
78
78
|
nextRunAtMs?: number;
|