@sentry/junior 0.68.0 → 0.70.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/app.js +1779 -746
- package/dist/build/virtual-config.d.ts +2 -2
- package/dist/chat/agent-dispatch/heartbeat.d.ts +2 -2
- package/dist/chat/agent-dispatch/store.d.ts +4 -1
- package/dist/chat/agent-dispatch/types.d.ts +2 -4
- package/dist/chat/agent-dispatch/validation.d.ts +3 -2
- package/dist/chat/credentials/context.d.ts +49 -24
- package/dist/chat/credentials/user-token-store.d.ts +6 -0
- package/dist/chat/destination.d.ts +12 -0
- package/dist/chat/ingress/message-router.d.ts +1 -1
- package/dist/chat/mcp/auth-store.d.ts +2 -0
- package/dist/chat/mcp/oauth.d.ts +2 -0
- package/dist/chat/oauth-flow.d.ts +7 -0
- package/dist/chat/plugins/agent-hooks.d.ts +9 -9
- package/dist/chat/plugins/auth/auth-token-placeholder.d.ts +2 -2
- package/dist/chat/plugins/auth/oauth-request.d.ts +3 -1
- package/dist/chat/plugins/credential-hooks.d.ts +53 -0
- package/dist/chat/plugins/logging.d.ts +1 -1
- package/dist/chat/plugins/state.d.ts +1 -1
- package/dist/chat/plugins/types.d.ts +19 -23
- package/dist/chat/respond.d.ts +2 -0
- package/dist/chat/runtime/reply-executor.d.ts +3 -1
- package/dist/chat/runtime/slack-runtime.d.ts +8 -3
- package/dist/chat/sandbox/egress-credentials.d.ts +34 -0
- package/dist/chat/sandbox/egress-schemas.d.ts +105 -0
- package/dist/chat/sandbox/egress-session.d.ts +17 -17
- package/dist/chat/sandbox/sandbox.d.ts +3 -0
- package/dist/chat/sandbox/session.d.ts +1 -0
- package/dist/chat/services/mcp-auth-orchestration.d.ts +2 -0
- package/dist/chat/services/pending-auth.d.ts +2 -0
- package/dist/chat/services/plugin-auth-orchestration.d.ts +2 -0
- package/dist/chat/services/provider-retry.d.ts +13 -4
- package/dist/chat/services/timeout-resume.d.ts +2 -0
- package/dist/chat/services/turn-session-record.d.ts +6 -0
- package/dist/chat/slack/attachment-fetchers.d.ts +11 -0
- package/dist/chat/state/conversation-details.d.ts +46 -0
- package/dist/chat/state/conversation.d.ts +1 -0
- package/dist/chat/state/turn-session.d.ts +4 -3
- package/dist/chat/task-execution/queue.d.ts +2 -0
- package/dist/chat/task-execution/store.d.ts +5 -0
- package/dist/chat/task-execution/vercel-callback.d.ts +4 -0
- package/dist/chat/task-execution/vercel-queue.d.ts +2 -0
- package/dist/chat/task-execution/worker.d.ts +4 -2
- package/dist/chat/tools/slack/context.d.ts +3 -0
- package/dist/chat/tools/types.d.ts +21 -2
- package/dist/chunk-76YMBKW7.js +326 -0
- package/dist/{chunk-PIVOJIUD.js → chunk-B5HKWWQB.js} +9 -5
- package/dist/chunk-BBXYXOJW.js +1858 -0
- package/dist/{chunk-V47RLIO2.js → chunk-GT67ZWZQ.js} +4 -4
- package/dist/{chunk-UQQSW7QB.js → chunk-HOGQL2H6.js} +197 -343
- package/dist/{chunk-75UZ4JLC.js → chunk-IGLNC5H6.js} +21 -9
- package/dist/{chunk-EBVQXCD2.js → chunk-JS4HURDT.js} +362 -280
- package/dist/chunk-R62YWUNO.js +264 -0
- package/dist/{chunk-OIIXZOOC.js → chunk-UXG6TU2U.js} +311 -2015
- package/dist/cli/check.js +4 -4
- package/dist/cli/init.js +18 -1
- package/dist/cli/snapshot-warmup.js +5 -4
- package/dist/nitro.d.ts +1 -1
- package/dist/nitro.js +21 -19
- package/dist/plugins.d.ts +2 -2
- package/dist/reporting.d.ts +8 -4
- package/dist/reporting.js +72 -29
- package/package.json +6 -4
- package/dist/chat/plugins/auth/github-app-broker.d.ts +0 -4
- package/dist/chat/plugins/github-permissions.d.ts +0 -11
- package/dist/chat/queue/thread-message-dispatcher.d.ts +0 -33
- package/dist/chunk-KVZL5NZS.js +0 -519
|
@@ -1,30 +1,40 @@
|
|
|
1
1
|
import {
|
|
2
2
|
SANDBOX_DATA_ROOT,
|
|
3
3
|
SANDBOX_WORKSPACE_ROOT,
|
|
4
|
-
botConfig,
|
|
5
|
-
getChatConfig,
|
|
6
4
|
getConnectedStateContext,
|
|
7
|
-
getSlackBotToken,
|
|
8
5
|
getStateAdapter,
|
|
9
|
-
parseSlackThreadId,
|
|
10
6
|
sandboxSkillDir
|
|
11
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-R62YWUNO.js";
|
|
12
8
|
import {
|
|
13
9
|
isActorUserId,
|
|
10
|
+
parseActorUserId
|
|
11
|
+
} from "./chunk-UXG6TU2U.js";
|
|
12
|
+
import {
|
|
13
|
+
isConversationChannel,
|
|
14
|
+
isConversationScopedChannel,
|
|
15
|
+
isDmChannel,
|
|
16
|
+
normalizeSlackConversationId,
|
|
17
|
+
parseDestination
|
|
18
|
+
} from "./chunk-76YMBKW7.js";
|
|
19
|
+
import {
|
|
20
|
+
TURN_CONTEXT_TAG,
|
|
21
|
+
botConfig,
|
|
22
|
+
getChatConfig,
|
|
23
|
+
parseSlackThreadId
|
|
24
|
+
} from "./chunk-JS4HURDT.js";
|
|
25
|
+
import {
|
|
14
26
|
isRecord,
|
|
27
|
+
listReferenceFiles,
|
|
15
28
|
logException,
|
|
16
29
|
logInfo,
|
|
17
30
|
logWarn,
|
|
18
|
-
|
|
19
|
-
|
|
31
|
+
soulPathCandidates,
|
|
32
|
+
toOptionalNumber,
|
|
33
|
+
worldPathCandidates
|
|
34
|
+
} from "./chunk-BBXYXOJW.js";
|
|
20
35
|
import {
|
|
21
36
|
sentry_exports
|
|
22
37
|
} from "./chunk-Z3YD6NHK.js";
|
|
23
|
-
import {
|
|
24
|
-
listReferenceFiles,
|
|
25
|
-
soulPathCandidates,
|
|
26
|
-
worldPathCandidates
|
|
27
|
-
} from "./chunk-KVZL5NZS.js";
|
|
28
38
|
|
|
29
39
|
// src/chat/plugins/logging.ts
|
|
30
40
|
function createAgentPluginLogger(plugin) {
|
|
@@ -152,277 +162,6 @@ function createPluginState(plugin, options) {
|
|
|
152
162
|
|
|
153
163
|
// src/chat/credentials/subject.ts
|
|
154
164
|
import { createHmac, timingSafeEqual } from "crypto";
|
|
155
|
-
|
|
156
|
-
// src/chat/slack/client.ts
|
|
157
|
-
import { WebClient } from "@slack/web-api";
|
|
158
|
-
var SlackActionError = class extends Error {
|
|
159
|
-
code;
|
|
160
|
-
apiError;
|
|
161
|
-
needed;
|
|
162
|
-
provided;
|
|
163
|
-
statusCode;
|
|
164
|
-
requestId;
|
|
165
|
-
errorData;
|
|
166
|
-
retryAfterSeconds;
|
|
167
|
-
detail;
|
|
168
|
-
detailLine;
|
|
169
|
-
detailRule;
|
|
170
|
-
constructor(message, code, options = {}) {
|
|
171
|
-
super(message);
|
|
172
|
-
this.name = "SlackActionError";
|
|
173
|
-
this.code = code;
|
|
174
|
-
this.apiError = options.apiError;
|
|
175
|
-
this.needed = options.needed;
|
|
176
|
-
this.provided = options.provided;
|
|
177
|
-
this.statusCode = options.statusCode;
|
|
178
|
-
this.requestId = options.requestId;
|
|
179
|
-
this.errorData = options.errorData;
|
|
180
|
-
this.retryAfterSeconds = options.retryAfterSeconds;
|
|
181
|
-
this.detail = options.detail;
|
|
182
|
-
this.detailLine = options.detailLine;
|
|
183
|
-
this.detailRule = options.detailRule;
|
|
184
|
-
}
|
|
185
|
-
};
|
|
186
|
-
function serializeSlackErrorData(data) {
|
|
187
|
-
if (!data || typeof data !== "object") {
|
|
188
|
-
return void 0;
|
|
189
|
-
}
|
|
190
|
-
const filtered = Object.fromEntries(
|
|
191
|
-
Object.entries(data).filter(
|
|
192
|
-
([key2]) => key2 !== "error"
|
|
193
|
-
)
|
|
194
|
-
);
|
|
195
|
-
if (Object.keys(filtered).length === 0) {
|
|
196
|
-
return void 0;
|
|
197
|
-
}
|
|
198
|
-
try {
|
|
199
|
-
const serialized = JSON.stringify(filtered);
|
|
200
|
-
return serialized.length <= 600 ? serialized : `${serialized.slice(0, 597)}...`;
|
|
201
|
-
} catch {
|
|
202
|
-
return void 0;
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
function getHeaderString(headers, name) {
|
|
206
|
-
if (!headers || typeof headers !== "object") {
|
|
207
|
-
return void 0;
|
|
208
|
-
}
|
|
209
|
-
const key2 = name.toLowerCase();
|
|
210
|
-
const entries = headers;
|
|
211
|
-
for (const [entryKey, value] of Object.entries(entries)) {
|
|
212
|
-
if (entryKey.toLowerCase() !== key2) continue;
|
|
213
|
-
if (typeof value === "string") return value;
|
|
214
|
-
if (Array.isArray(value)) {
|
|
215
|
-
const first = value.find((entry) => typeof entry === "string");
|
|
216
|
-
return typeof first === "string" ? first : void 0;
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
return void 0;
|
|
220
|
-
}
|
|
221
|
-
function parseSlackCanvasDetail(detail) {
|
|
222
|
-
if (typeof detail !== "string") {
|
|
223
|
-
return {};
|
|
224
|
-
}
|
|
225
|
-
const trimmed = detail.trim();
|
|
226
|
-
if (!trimmed) {
|
|
227
|
-
return {};
|
|
228
|
-
}
|
|
229
|
-
const parsed = {
|
|
230
|
-
detail: trimmed
|
|
231
|
-
};
|
|
232
|
-
const lineMatch = trimmed.match(/line\s+(\d+):/i);
|
|
233
|
-
if (lineMatch) {
|
|
234
|
-
const line = Number.parseInt(lineMatch[1] ?? "", 10);
|
|
235
|
-
if (Number.isFinite(line)) {
|
|
236
|
-
parsed.detailLine = line;
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
if (/unsupported heading depth/i.test(trimmed)) {
|
|
240
|
-
parsed.detailRule = "unsupported_heading_depth";
|
|
241
|
-
}
|
|
242
|
-
return parsed;
|
|
243
|
-
}
|
|
244
|
-
var client = null;
|
|
245
|
-
function normalizeSlackConversationId(channelId) {
|
|
246
|
-
if (!channelId) return void 0;
|
|
247
|
-
const trimmed = channelId.trim();
|
|
248
|
-
if (!trimmed) return void 0;
|
|
249
|
-
if (!trimmed.startsWith("slack:")) {
|
|
250
|
-
return trimmed;
|
|
251
|
-
}
|
|
252
|
-
const parts = trimmed.split(":");
|
|
253
|
-
return parts[1]?.trim() || void 0;
|
|
254
|
-
}
|
|
255
|
-
function getClient() {
|
|
256
|
-
if (client) return client;
|
|
257
|
-
const token = getSlackBotToken();
|
|
258
|
-
if (!token) {
|
|
259
|
-
throw new SlackActionError(
|
|
260
|
-
"SLACK_BOT_TOKEN (or SLACK_BOT_USER_TOKEN) is required for Slack canvas/list actions in this service",
|
|
261
|
-
"missing_token"
|
|
262
|
-
);
|
|
263
|
-
}
|
|
264
|
-
client = new WebClient(token);
|
|
265
|
-
return client;
|
|
266
|
-
}
|
|
267
|
-
function mapSlackError(error) {
|
|
268
|
-
if (error instanceof SlackActionError) {
|
|
269
|
-
return error;
|
|
270
|
-
}
|
|
271
|
-
const candidate = error;
|
|
272
|
-
const apiError = candidate.data?.error;
|
|
273
|
-
const message = candidate.message ?? "Slack action failed";
|
|
274
|
-
const baseOptions = {
|
|
275
|
-
apiError,
|
|
276
|
-
statusCode: candidate.statusCode,
|
|
277
|
-
requestId: getHeaderString(candidate.headers, "x-slack-req-id"),
|
|
278
|
-
errorData: serializeSlackErrorData(candidate.data),
|
|
279
|
-
...parseSlackCanvasDetail(candidate.data?.detail)
|
|
280
|
-
};
|
|
281
|
-
if (apiError === "missing_scope") {
|
|
282
|
-
return new SlackActionError(message, "missing_scope", {
|
|
283
|
-
...baseOptions,
|
|
284
|
-
needed: candidate.data?.needed,
|
|
285
|
-
provided: candidate.data?.provided
|
|
286
|
-
});
|
|
287
|
-
}
|
|
288
|
-
if (apiError === "not_in_channel") {
|
|
289
|
-
return new SlackActionError(message, "not_in_channel", baseOptions);
|
|
290
|
-
}
|
|
291
|
-
if (apiError === "already_reacted") {
|
|
292
|
-
return new SlackActionError(message, "already_reacted", baseOptions);
|
|
293
|
-
}
|
|
294
|
-
if (apiError === "no_reaction") {
|
|
295
|
-
return new SlackActionError(message, "no_reaction", baseOptions);
|
|
296
|
-
}
|
|
297
|
-
if (apiError === "invalid_arguments") {
|
|
298
|
-
return new SlackActionError(message, "invalid_arguments", baseOptions);
|
|
299
|
-
}
|
|
300
|
-
if (apiError === "invalid_cursor") {
|
|
301
|
-
return new SlackActionError(message, "invalid_arguments", baseOptions);
|
|
302
|
-
}
|
|
303
|
-
if (apiError === "invalid_name") {
|
|
304
|
-
return new SlackActionError(message, "invalid_arguments", baseOptions);
|
|
305
|
-
}
|
|
306
|
-
if (apiError === "not_found" || apiError === "channel_not_found" || apiError === "message_not_found") {
|
|
307
|
-
return new SlackActionError(message, "not_found", baseOptions);
|
|
308
|
-
}
|
|
309
|
-
if (apiError === "feature_not_enabled" || apiError === "not_allowed_token_type") {
|
|
310
|
-
return new SlackActionError(message, "feature_unavailable", baseOptions);
|
|
311
|
-
}
|
|
312
|
-
if (apiError === "canvas_creation_failed") {
|
|
313
|
-
return new SlackActionError(message, "canvas_creation_failed", baseOptions);
|
|
314
|
-
}
|
|
315
|
-
if (apiError === "canvas_editing_failed") {
|
|
316
|
-
return new SlackActionError(message, "canvas_editing_failed", baseOptions);
|
|
317
|
-
}
|
|
318
|
-
if (candidate.code === "slack_webapi_rate_limited_error" || candidate.statusCode === 429) {
|
|
319
|
-
return new SlackActionError(message, "rate_limited", {
|
|
320
|
-
...baseOptions,
|
|
321
|
-
retryAfterSeconds: candidate.retryAfter
|
|
322
|
-
});
|
|
323
|
-
}
|
|
324
|
-
return new SlackActionError(message, "internal_error", baseOptions);
|
|
325
|
-
}
|
|
326
|
-
function sleep(ms) {
|
|
327
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
328
|
-
}
|
|
329
|
-
async function withSlackRetries(task, maxAttempts = 3, context = {}) {
|
|
330
|
-
let attempt = 0;
|
|
331
|
-
while (attempt < maxAttempts) {
|
|
332
|
-
attempt += 1;
|
|
333
|
-
try {
|
|
334
|
-
return await task();
|
|
335
|
-
} catch (error) {
|
|
336
|
-
const mapped = mapSlackError(error);
|
|
337
|
-
const isRetryable = mapped.code === "rate_limited";
|
|
338
|
-
const baseLogAttributes = {
|
|
339
|
-
"app.slack.action": context.action ?? "unknown",
|
|
340
|
-
"app.slack.error_code": mapped.code,
|
|
341
|
-
...mapped.apiError ? { "app.slack.api_error": mapped.apiError } : {},
|
|
342
|
-
...mapped.detail ? { "app.slack.detail": mapped.detail } : {},
|
|
343
|
-
...mapped.detailLine !== void 0 ? { "app.slack.detail_line": mapped.detailLine } : {},
|
|
344
|
-
...mapped.detailRule ? { "app.slack.detail_rule": mapped.detailRule } : {},
|
|
345
|
-
...mapped.requestId ? { "app.slack.request_id": mapped.requestId } : {},
|
|
346
|
-
...mapped.statusCode !== void 0 ? { "http.response.status_code": mapped.statusCode } : {},
|
|
347
|
-
...context.attributes ?? {}
|
|
348
|
-
};
|
|
349
|
-
if (!isRetryable || attempt >= maxAttempts) {
|
|
350
|
-
logWarn(
|
|
351
|
-
"slack_action_failed",
|
|
352
|
-
{},
|
|
353
|
-
{
|
|
354
|
-
...baseLogAttributes,
|
|
355
|
-
...mapped.errorData ? { "app.slack.error_data": mapped.errorData } : {}
|
|
356
|
-
},
|
|
357
|
-
"Slack action failed"
|
|
358
|
-
);
|
|
359
|
-
throw mapped;
|
|
360
|
-
}
|
|
361
|
-
logWarn(
|
|
362
|
-
"slack_action_retrying",
|
|
363
|
-
{},
|
|
364
|
-
{
|
|
365
|
-
...baseLogAttributes,
|
|
366
|
-
"app.slack.retry_attempt": attempt
|
|
367
|
-
},
|
|
368
|
-
"Retrying Slack action after transient failure"
|
|
369
|
-
);
|
|
370
|
-
const retryAfterMs = mapped.code === "rate_limited" && mapped.retryAfterSeconds && mapped.retryAfterSeconds > 0 ? mapped.retryAfterSeconds * 1e3 : void 0;
|
|
371
|
-
const backoffMs = Math.min(2e3, 250 * 2 ** (attempt - 1));
|
|
372
|
-
await sleep(retryAfterMs ?? backoffMs);
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
|
-
throw new SlackActionError(
|
|
376
|
-
"Slack action exhausted retries",
|
|
377
|
-
"internal_error"
|
|
378
|
-
);
|
|
379
|
-
}
|
|
380
|
-
function getSlackClient() {
|
|
381
|
-
return getClient();
|
|
382
|
-
}
|
|
383
|
-
function isDmChannel(channelId) {
|
|
384
|
-
const normalized = normalizeSlackConversationId(channelId);
|
|
385
|
-
return Boolean(normalized && normalized.startsWith("D"));
|
|
386
|
-
}
|
|
387
|
-
function isConversationScopedChannel(channelId) {
|
|
388
|
-
const normalized = normalizeSlackConversationId(channelId);
|
|
389
|
-
if (!normalized) return false;
|
|
390
|
-
return normalized.startsWith("C") || normalized.startsWith("G") || normalized.startsWith("D");
|
|
391
|
-
}
|
|
392
|
-
function isConversationChannel(channelId) {
|
|
393
|
-
const normalized = normalizeSlackConversationId(channelId);
|
|
394
|
-
if (!normalized) return false;
|
|
395
|
-
return normalized.startsWith("C") || normalized.startsWith("G");
|
|
396
|
-
}
|
|
397
|
-
async function getFilePermalink(fileId) {
|
|
398
|
-
const client2 = getClient();
|
|
399
|
-
const response = await withSlackRetries(
|
|
400
|
-
() => client2.files.info({
|
|
401
|
-
file: fileId
|
|
402
|
-
})
|
|
403
|
-
);
|
|
404
|
-
return response.file?.permalink;
|
|
405
|
-
}
|
|
406
|
-
async function downloadPrivateSlackFile(url) {
|
|
407
|
-
const token = getSlackBotToken();
|
|
408
|
-
if (!token) {
|
|
409
|
-
throw new SlackActionError(
|
|
410
|
-
"SLACK_BOT_TOKEN (or SLACK_BOT_USER_TOKEN) is required for Slack file downloads in this service",
|
|
411
|
-
"missing_token"
|
|
412
|
-
);
|
|
413
|
-
}
|
|
414
|
-
const response = await fetch(url, {
|
|
415
|
-
headers: {
|
|
416
|
-
Authorization: `Bearer ${token}`
|
|
417
|
-
}
|
|
418
|
-
});
|
|
419
|
-
if (!response.ok) {
|
|
420
|
-
throw new Error(`Slack file download failed: ${response.status}`);
|
|
421
|
-
}
|
|
422
|
-
return Buffer.from(await response.arrayBuffer());
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
// src/chat/credentials/subject.ts
|
|
426
165
|
var CREDENTIAL_SUBJECT_HMAC_CONTEXT = "junior.credential_subject.v1";
|
|
427
166
|
var CREDENTIAL_SUBJECT_SIGNATURE_VERSION = "v1";
|
|
428
167
|
function getCredentialSubjectSecret() {
|
|
@@ -514,6 +253,15 @@ function verifySlackDirectCredentialSubject(input) {
|
|
|
514
253
|
return timingSafeMatch(expected, binding.signature);
|
|
515
254
|
}
|
|
516
255
|
|
|
256
|
+
// src/chat/tools/channel-capabilities.ts
|
|
257
|
+
function resolveChannelCapabilities(channelId) {
|
|
258
|
+
return {
|
|
259
|
+
canCreateCanvas: isConversationScopedChannel(channelId),
|
|
260
|
+
canPostToChannel: isConversationChannel(channelId),
|
|
261
|
+
canAddReactions: isConversationScopedChannel(channelId)
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
|
|
517
265
|
// src/chat/plugins/agent-hooks.ts
|
|
518
266
|
var AgentPluginHookDeniedError = class extends Error {
|
|
519
267
|
constructor(message) {
|
|
@@ -540,6 +288,9 @@ var AGENT_PLUGIN_ROUTE_METHODS = /* @__PURE__ */ new Set([
|
|
|
540
288
|
"OPTIONS",
|
|
541
289
|
"ALL"
|
|
542
290
|
]);
|
|
291
|
+
function isRecord2(value) {
|
|
292
|
+
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
293
|
+
}
|
|
543
294
|
function validateLegacyStatePrefixes(plugin) {
|
|
544
295
|
const prefixes = plugin.legacyStatePrefixes;
|
|
545
296
|
if (prefixes === void 0) {
|
|
@@ -547,7 +298,7 @@ function validateLegacyStatePrefixes(plugin) {
|
|
|
547
298
|
}
|
|
548
299
|
if (!Array.isArray(prefixes)) {
|
|
549
300
|
throw new Error(
|
|
550
|
-
`
|
|
301
|
+
`Plugin "${plugin.name}" legacyStatePrefixes must be an array`
|
|
551
302
|
);
|
|
552
303
|
}
|
|
553
304
|
const allowedPrefix = `junior:${plugin.name}`;
|
|
@@ -555,12 +306,12 @@ function validateLegacyStatePrefixes(plugin) {
|
|
|
555
306
|
const prefix = typeof rawPrefix === "string" ? rawPrefix.trim() : "";
|
|
556
307
|
if (!prefix) {
|
|
557
308
|
throw new Error(
|
|
558
|
-
`
|
|
309
|
+
`Plugin "${plugin.name}" legacy state prefixes must be non-empty strings`
|
|
559
310
|
);
|
|
560
311
|
}
|
|
561
312
|
if (prefix !== allowedPrefix && !prefix.startsWith(`${allowedPrefix}:`)) {
|
|
562
313
|
throw new Error(
|
|
563
|
-
`
|
|
314
|
+
`Plugin "${plugin.name}" legacy state prefix "${prefix}" must stay under "${allowedPrefix}"`
|
|
564
315
|
);
|
|
565
316
|
}
|
|
566
317
|
}
|
|
@@ -570,11 +321,11 @@ function validateAgentPlugins(plugins) {
|
|
|
570
321
|
for (const plugin of plugins) {
|
|
571
322
|
if (!AGENT_PLUGIN_NAME_RE.test(plugin.name)) {
|
|
572
323
|
throw new Error(
|
|
573
|
-
`
|
|
324
|
+
`Plugin name "${plugin.name}" must be a lowercase plugin identifier`
|
|
574
325
|
);
|
|
575
326
|
}
|
|
576
327
|
if (seen.has(plugin.name)) {
|
|
577
|
-
throw new Error(`Duplicate
|
|
328
|
+
throw new Error(`Duplicate plugin name "${plugin.name}"`);
|
|
578
329
|
}
|
|
579
330
|
seen.add(plugin.name);
|
|
580
331
|
validateLegacyStatePrefixes(plugin);
|
|
@@ -599,18 +350,22 @@ function getAgentPluginTools(context) {
|
|
|
599
350
|
continue;
|
|
600
351
|
}
|
|
601
352
|
const log = createAgentPluginLogger(plugin.name);
|
|
353
|
+
const destination = context.destination;
|
|
602
354
|
const credentialSubject = createSlackDirectCredentialSubject({
|
|
603
355
|
channelId: context.channelId,
|
|
604
356
|
teamId: context.teamId,
|
|
605
357
|
userId: context.requester?.userId
|
|
606
358
|
});
|
|
359
|
+
const pluginCapabilities = resolveChannelCapabilities(context.channelId);
|
|
607
360
|
const pluginTools = hook({
|
|
608
361
|
plugin: { name: plugin.name },
|
|
609
362
|
log,
|
|
610
363
|
requester: context.requester,
|
|
611
|
-
channelCapabilities:
|
|
364
|
+
channelCapabilities: pluginCapabilities,
|
|
612
365
|
channelId: context.channelId,
|
|
366
|
+
conversationId: context.conversationId,
|
|
613
367
|
...credentialSubject ? { credentialSubject } : {},
|
|
368
|
+
...destination ? { destination } : {},
|
|
614
369
|
teamId: context.teamId,
|
|
615
370
|
messageTs: context.messageTs,
|
|
616
371
|
threadTs: context.threadTs,
|
|
@@ -622,12 +377,12 @@ function getAgentPluginTools(context) {
|
|
|
622
377
|
for (const [name, tool] of Object.entries(pluginTools)) {
|
|
623
378
|
if (!AGENT_PLUGIN_TOOL_NAME_RE.test(name)) {
|
|
624
379
|
throw new Error(
|
|
625
|
-
`
|
|
380
|
+
`Plugin tool "${name}" from plugin "${plugin.name}" must be a camelCase identifier`
|
|
626
381
|
);
|
|
627
382
|
}
|
|
628
383
|
if (tools[name]) {
|
|
629
384
|
throw new Error(
|
|
630
|
-
`Duplicate
|
|
385
|
+
`Duplicate plugin tool "${name}" from plugin "${plugin.name}"`
|
|
631
386
|
);
|
|
632
387
|
}
|
|
633
388
|
tools[name] = tool;
|
|
@@ -639,19 +394,19 @@ function routeMethods(route, pluginName) {
|
|
|
639
394
|
const methods = Array.isArray(route.method) ? route.method : [route.method ?? "ALL"];
|
|
640
395
|
if (methods.length === 0) {
|
|
641
396
|
throw new Error(
|
|
642
|
-
`
|
|
397
|
+
`Plugin route "${route.path}" from plugin "${pluginName}" must declare at least one method`
|
|
643
398
|
);
|
|
644
399
|
}
|
|
645
400
|
for (const method of methods) {
|
|
646
401
|
if (!AGENT_PLUGIN_ROUTE_METHODS.has(method)) {
|
|
647
402
|
throw new Error(
|
|
648
|
-
`
|
|
403
|
+
`Plugin route "${route.path}" from plugin "${pluginName}" has invalid method "${String(method)}"`
|
|
649
404
|
);
|
|
650
405
|
}
|
|
651
406
|
}
|
|
652
407
|
if (methods.includes("ALL") && methods.length > 1) {
|
|
653
408
|
throw new Error(
|
|
654
|
-
`
|
|
409
|
+
`Plugin route "${route.path}" from plugin "${pluginName}" must not combine ALL with explicit methods`
|
|
655
410
|
);
|
|
656
411
|
}
|
|
657
412
|
return methods;
|
|
@@ -672,38 +427,36 @@ function getAgentPluginRoutes() {
|
|
|
672
427
|
});
|
|
673
428
|
if (!Array.isArray(pluginRoutes)) {
|
|
674
429
|
throw new Error(
|
|
675
|
-
`
|
|
430
|
+
`Plugin routes hook from plugin "${plugin.name}" must return an array`
|
|
676
431
|
);
|
|
677
432
|
}
|
|
678
433
|
for (const route of pluginRoutes) {
|
|
679
434
|
if (!isRecord2(route)) {
|
|
680
435
|
throw new Error(
|
|
681
|
-
`
|
|
436
|
+
`Plugin route from plugin "${plugin.name}" must be an object`
|
|
682
437
|
);
|
|
683
438
|
}
|
|
684
439
|
if (typeof route.path !== "string" || !route.path.startsWith("/")) {
|
|
685
440
|
throw new Error(
|
|
686
|
-
`
|
|
441
|
+
`Plugin route "${route.path}" from plugin "${plugin.name}" must start with /`
|
|
687
442
|
);
|
|
688
443
|
}
|
|
689
444
|
if (typeof route.handler !== "function") {
|
|
690
445
|
throw new Error(
|
|
691
|
-
`
|
|
446
|
+
`Plugin route "${route.path}" from plugin "${plugin.name}" must provide a handler`
|
|
692
447
|
);
|
|
693
448
|
}
|
|
694
449
|
const methods = routeMethods(route, plugin.name);
|
|
695
450
|
const pathMethods = methodsByPath.get(route.path) ?? /* @__PURE__ */ new Set();
|
|
696
451
|
if (pathMethods.has("ALL") || methods.includes("ALL") && pathMethods.size > 0) {
|
|
697
452
|
throw new Error(
|
|
698
|
-
`
|
|
453
|
+
`Plugin route "${route.path}" conflicts with an ALL route for the same path`
|
|
699
454
|
);
|
|
700
455
|
}
|
|
701
456
|
for (const method of methods) {
|
|
702
457
|
const key2 = `${method}:${route.path}`;
|
|
703
458
|
if (seen.has(key2)) {
|
|
704
|
-
throw new Error(
|
|
705
|
-
`Duplicate trusted plugin route "${method} ${route.path}"`
|
|
706
|
-
);
|
|
459
|
+
throw new Error(`Duplicate plugin route "${method} ${route.path}"`);
|
|
707
460
|
}
|
|
708
461
|
seen.add(key2);
|
|
709
462
|
pathMethods.add(method);
|
|
@@ -727,13 +480,13 @@ function trustedSlackConversationUrl(pluginName, link) {
|
|
|
727
480
|
parsed = new URL(url);
|
|
728
481
|
} catch (error) {
|
|
729
482
|
throw new Error(
|
|
730
|
-
`
|
|
483
|
+
`Plugin "${pluginName}" slackConversationLink must return an absolute http(s) URL`,
|
|
731
484
|
{ cause: error }
|
|
732
485
|
);
|
|
733
486
|
}
|
|
734
487
|
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
735
488
|
throw new Error(
|
|
736
|
-
`
|
|
489
|
+
`Plugin "${pluginName}" slackConversationLink must return an absolute http(s) URL`
|
|
737
490
|
);
|
|
738
491
|
}
|
|
739
492
|
return parsed.toString();
|
|
@@ -923,7 +676,7 @@ async function getAgentPluginOperationalReports(nowMs = Date.now()) {
|
|
|
923
676
|
})
|
|
924
677
|
);
|
|
925
678
|
} catch (error) {
|
|
926
|
-
log.error("
|
|
679
|
+
log.error("Plugin operational report failed", {
|
|
927
680
|
error: error instanceof Error ? error.message : String(error)
|
|
928
681
|
});
|
|
929
682
|
reports.push(failedOperationalReport({ nowMs, pluginName: plugin.name }));
|
|
@@ -931,9 +684,6 @@ async function getAgentPluginOperationalReports(nowMs = Date.now()) {
|
|
|
931
684
|
}
|
|
932
685
|
return reports;
|
|
933
686
|
}
|
|
934
|
-
function isRecord2(value) {
|
|
935
|
-
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
936
|
-
}
|
|
937
687
|
function normalizeEnv(value) {
|
|
938
688
|
if (!isRecord2(value)) {
|
|
939
689
|
return {};
|
|
@@ -1072,9 +822,6 @@ function GET() {
|
|
|
1072
822
|
import fs from "fs";
|
|
1073
823
|
import path from "path";
|
|
1074
824
|
|
|
1075
|
-
// src/chat/turn-context-tag.ts
|
|
1076
|
-
var TURN_CONTEXT_TAG = "runtime-turn-context";
|
|
1077
|
-
|
|
1078
825
|
// src/chat/interruption-marker.ts
|
|
1079
826
|
var INTERRUPTED_MARKER = "\n\n[Response interrupted before completion]";
|
|
1080
827
|
function getInterruptionMarker() {
|
|
@@ -2202,20 +1949,20 @@ function commitEntries(existingMessages, nextMessages, sessionId, entries) {
|
|
|
2202
1949
|
return [resetEntry(nextMessages, nextSessionId(entries))];
|
|
2203
1950
|
}
|
|
2204
1951
|
function redisStore(redisStateAdapter) {
|
|
2205
|
-
const
|
|
1952
|
+
const client = redisStateAdapter.getClient();
|
|
2206
1953
|
return {
|
|
2207
1954
|
async append({ entries, scope, ttlMs }) {
|
|
2208
1955
|
const listKey = key(scope);
|
|
2209
1956
|
if (entries.length > 0) {
|
|
2210
|
-
await
|
|
1957
|
+
await client.rPush(
|
|
2211
1958
|
listKey,
|
|
2212
1959
|
entries.map((entry) => JSON.stringify(entry))
|
|
2213
1960
|
);
|
|
2214
1961
|
}
|
|
2215
|
-
await
|
|
1962
|
+
await client.pExpire(listKey, Math.max(1, ttlMs));
|
|
2216
1963
|
},
|
|
2217
1964
|
async read(scope) {
|
|
2218
|
-
const values = await
|
|
1965
|
+
const values = await client.lRange(key(scope), 0, -1);
|
|
2219
1966
|
return values.map(decode);
|
|
2220
1967
|
}
|
|
2221
1968
|
};
|
|
@@ -2428,7 +2175,6 @@ function parseAgentTurnSessionFields(parsed) {
|
|
|
2428
2175
|
return void 0;
|
|
2429
2176
|
}
|
|
2430
2177
|
const channelName = typeof parsed.channelName === "string" && parsed.channelName.trim() ? parsed.channelName.trim() : void 0;
|
|
2431
|
-
const conversationTitle = typeof parsed.conversationTitle === "string" && parsed.conversationTitle.trim() ? parsed.conversationTitle.trim() : void 0;
|
|
2432
2178
|
const conversationId = parsed.conversationId;
|
|
2433
2179
|
const sessionId = parsed.sessionId;
|
|
2434
2180
|
const sliceId = toFiniteNonNegativeNumber(parsed.sliceId);
|
|
@@ -2441,13 +2187,13 @@ function parseAgentTurnSessionFields(parsed) {
|
|
|
2441
2187
|
const requester = parseAgentTurnRequester(parsed.requester);
|
|
2442
2188
|
const startedAtMs = toFiniteNonNegativeNumber(parsed.startedAtMs);
|
|
2443
2189
|
const surface = parseAgentTurnSurface(parsed.surface);
|
|
2444
|
-
|
|
2190
|
+
const destination = parsed.destination === void 0 ? void 0 : parseDestination(parsed.destination);
|
|
2191
|
+
if (typeof conversationId !== "string" || typeof sessionId !== "string" || sliceId === void 0 || version === void 0 || updatedAtMs === void 0 || parsed.destination !== void 0 && !destination) {
|
|
2445
2192
|
return void 0;
|
|
2446
2193
|
}
|
|
2447
2194
|
return {
|
|
2448
2195
|
version,
|
|
2449
2196
|
...channelName ? { channelName } : {},
|
|
2450
|
-
...conversationTitle ? { conversationTitle } : {},
|
|
2451
2197
|
conversationId,
|
|
2452
2198
|
sessionId,
|
|
2453
2199
|
sliceId,
|
|
@@ -2458,6 +2204,7 @@ function parseAgentTurnSessionFields(parsed) {
|
|
|
2458
2204
|
cumulativeDurationMs,
|
|
2459
2205
|
...logSessionId ? { logSessionId } : {},
|
|
2460
2206
|
...cumulativeUsage ? { cumulativeUsage } : {},
|
|
2207
|
+
...destination ? { destination } : {},
|
|
2461
2208
|
...requester ? { requester } : {},
|
|
2462
2209
|
...Array.isArray(parsed.loadedSkillNames) ? {
|
|
2463
2210
|
loadedSkillNames: parsed.loadedSkillNames.filter(
|
|
@@ -2537,7 +2284,6 @@ function materializeAgentTurnSessionRecord(stored, piMessages) {
|
|
|
2537
2284
|
return {
|
|
2538
2285
|
version: stored.version,
|
|
2539
2286
|
...stored.channelName ? { channelName: stored.channelName } : {},
|
|
2540
|
-
...stored.conversationTitle ? { conversationTitle: stored.conversationTitle } : {},
|
|
2541
2287
|
conversationId: stored.conversationId,
|
|
2542
2288
|
sessionId: stored.sessionId,
|
|
2543
2289
|
sliceId: stored.sliceId,
|
|
@@ -2547,6 +2293,7 @@ function materializeAgentTurnSessionRecord(stored, piMessages) {
|
|
|
2547
2293
|
updatedAtMs: stored.updatedAtMs,
|
|
2548
2294
|
piMessages,
|
|
2549
2295
|
cumulativeDurationMs: stored.cumulativeDurationMs,
|
|
2296
|
+
...stored.destination ? { destination: stored.destination } : {},
|
|
2550
2297
|
...stored.cumulativeUsage ? { cumulativeUsage: stored.cumulativeUsage } : {},
|
|
2551
2298
|
...stored.resumeReason ? { resumeReason: stored.resumeReason } : {},
|
|
2552
2299
|
...stored.errorMessage ? { errorMessage: stored.errorMessage } : {},
|
|
@@ -2598,7 +2345,6 @@ function buildStoredRecord(args) {
|
|
|
2598
2345
|
return {
|
|
2599
2346
|
version: (args.previousVersion ?? 0) + 1,
|
|
2600
2347
|
...args.channelName ? { channelName: args.channelName } : {},
|
|
2601
|
-
...args.conversationTitle ? { conversationTitle: args.conversationTitle } : {},
|
|
2602
2348
|
conversationId: args.conversationId,
|
|
2603
2349
|
sessionId: args.sessionId,
|
|
2604
2350
|
sliceId: args.sliceId,
|
|
@@ -2610,6 +2356,7 @@ function buildStoredRecord(args) {
|
|
|
2610
2356
|
...args.logSessionId ? { logSessionId: args.logSessionId } : {},
|
|
2611
2357
|
cumulativeDurationMs: args.cumulativeDurationMs,
|
|
2612
2358
|
...args.cumulativeUsage ? { cumulativeUsage: args.cumulativeUsage } : {},
|
|
2359
|
+
...args.destination ? { destination: args.destination } : {},
|
|
2613
2360
|
...args.requester ? { requester: args.requester } : {},
|
|
2614
2361
|
...Array.isArray(args.loadedSkillNames) ? {
|
|
2615
2362
|
loadedSkillNames: args.loadedSkillNames.filter(
|
|
@@ -2658,13 +2405,13 @@ async function updateAgentTurnSessionState(args) {
|
|
|
2658
2405
|
state: args.state,
|
|
2659
2406
|
committedMessageCount: parsed.committedMessageCount,
|
|
2660
2407
|
...parsed.channelName ? { channelName: parsed.channelName } : {},
|
|
2661
|
-
...parsed.conversationTitle ? { conversationTitle: parsed.conversationTitle } : {},
|
|
2662
2408
|
startedAtMs: parsed.startedAtMs,
|
|
2663
2409
|
lastProgressAtMs: parsed.lastProgressAtMs,
|
|
2664
2410
|
previousVersion: parsed.version,
|
|
2665
2411
|
...parsed.logSessionId ? { logSessionId: parsed.logSessionId } : {},
|
|
2666
2412
|
cumulativeDurationMs: args.existing.cumulativeDurationMs,
|
|
2667
2413
|
...args.existing.cumulativeUsage ? { cumulativeUsage: args.existing.cumulativeUsage } : {},
|
|
2414
|
+
...args.existing.destination ? { destination: args.existing.destination } : {},
|
|
2668
2415
|
...args.existing.loadedSkillNames ? { loadedSkillNames: args.existing.loadedSkillNames } : {},
|
|
2669
2416
|
...args.existing.requester ? { requester: args.existing.requester } : {},
|
|
2670
2417
|
...args.existing.resumeReason ? { resumeReason: args.existing.resumeReason } : {},
|
|
@@ -2691,9 +2438,6 @@ async function upsertAgentTurnSessionRecord(args) {
|
|
|
2691
2438
|
ttlMs,
|
|
2692
2439
|
record: buildStoredRecord({
|
|
2693
2440
|
...args.channelName ?? existingRecord?.channelName ? { channelName: args.channelName ?? existingRecord?.channelName } : {},
|
|
2694
|
-
...args.conversationTitle ?? existingRecord?.conversationTitle ? {
|
|
2695
|
-
conversationTitle: args.conversationTitle ?? existingRecord?.conversationTitle
|
|
2696
|
-
} : {},
|
|
2697
2441
|
conversationId: args.conversationId,
|
|
2698
2442
|
sessionId: args.sessionId,
|
|
2699
2443
|
sliceId: args.sliceId,
|
|
@@ -2705,6 +2449,7 @@ async function upsertAgentTurnSessionRecord(args) {
|
|
|
2705
2449
|
previousVersion: existingRecord?.version,
|
|
2706
2450
|
cumulativeDurationMs: toFiniteNonNegativeNumber(args.cumulativeDurationMs) ?? existingRecord?.cumulativeDurationMs ?? 0,
|
|
2707
2451
|
...args.cumulativeUsage ? { cumulativeUsage: args.cumulativeUsage } : {},
|
|
2452
|
+
...args.destination ?? existingRecord?.destination ? { destination: args.destination ?? existingRecord?.destination } : {},
|
|
2708
2453
|
...args.loadedSkillNames ? { loadedSkillNames: args.loadedSkillNames } : {},
|
|
2709
2454
|
...args.requester ?? existingRecord?.requester ? { requester: args.requester ?? existingRecord?.requester } : {},
|
|
2710
2455
|
...args.resumeReason ? { resumeReason: args.resumeReason } : {},
|
|
@@ -2726,9 +2471,6 @@ async function recordAgentTurnSessionSummary(args) {
|
|
|
2726
2471
|
{
|
|
2727
2472
|
version: existing?.version ?? 0,
|
|
2728
2473
|
...args.channelName ?? existing?.channelName ? { channelName: args.channelName ?? existing?.channelName } : {},
|
|
2729
|
-
...args.conversationTitle ?? existing?.conversationTitle ? {
|
|
2730
|
-
conversationTitle: args.conversationTitle ?? existing?.conversationTitle
|
|
2731
|
-
} : {},
|
|
2732
2474
|
conversationId: args.conversationId,
|
|
2733
2475
|
sessionId: args.sessionId,
|
|
2734
2476
|
sliceId: args.sliceId,
|
|
@@ -2738,6 +2480,7 @@ async function recordAgentTurnSessionSummary(args) {
|
|
|
2738
2480
|
updatedAtMs: nowMs,
|
|
2739
2481
|
cumulativeDurationMs: toFiniteNonNegativeNumber(args.cumulativeDurationMs) ?? existing?.cumulativeDurationMs ?? 0,
|
|
2740
2482
|
...args.cumulativeUsage ?? existing?.cumulativeUsage ? { cumulativeUsage: args.cumulativeUsage ?? existing?.cumulativeUsage } : {},
|
|
2483
|
+
...args.destination ?? existing?.destination ? { destination: args.destination ?? existing?.destination } : {},
|
|
2741
2484
|
...args.requester ?? existing?.requester ? { requester: args.requester ?? existing?.requester } : {},
|
|
2742
2485
|
...Array.isArray(args.loadedSkillNames) ? {
|
|
2743
2486
|
loadedSkillNames: args.loadedSkillNames.filter(
|
|
@@ -2828,8 +2571,8 @@ function buildSentryWebBaseUrl(dsn) {
|
|
|
2828
2571
|
return `${dsn.protocol}://${dsn.host}${port}${path2}`;
|
|
2829
2572
|
}
|
|
2830
2573
|
function buildSentryConversationUrl(conversationId) {
|
|
2831
|
-
const
|
|
2832
|
-
const dsn =
|
|
2574
|
+
const client = sentry_exports.getClient();
|
|
2575
|
+
const dsn = client?.getDsn();
|
|
2833
2576
|
if (!dsn?.host || !dsn.projectId) {
|
|
2834
2577
|
return void 0;
|
|
2835
2578
|
}
|
|
@@ -2847,8 +2590,8 @@ function buildSentryConversationUrl(conversationId) {
|
|
|
2847
2590
|
return `${buildSentryWebBaseUrl(dsn)}/organizations/${orgSlug}/${path2}`;
|
|
2848
2591
|
}
|
|
2849
2592
|
function buildSentryTraceUrl(traceId) {
|
|
2850
|
-
const
|
|
2851
|
-
const dsn =
|
|
2593
|
+
const client = sentry_exports.getClient();
|
|
2594
|
+
const dsn = client?.getDsn();
|
|
2852
2595
|
if (!dsn?.host || !dsn.projectId) {
|
|
2853
2596
|
return void 0;
|
|
2854
2597
|
}
|
|
@@ -2934,21 +2677,129 @@ function formatSlackConversationRedactedLabel(context) {
|
|
|
2934
2677
|
return formatSlackConversationTypeLabel(context.type);
|
|
2935
2678
|
}
|
|
2936
2679
|
|
|
2680
|
+
// src/chat/state/conversation-details.ts
|
|
2681
|
+
import { THREAD_STATE_TTL_MS as THREAD_STATE_TTL_MS2 } from "chat";
|
|
2682
|
+
var CONVERSATION_PREFIX = "junior:conversation";
|
|
2683
|
+
var CONVERSATION_DETAILS_TTL_MS = THREAD_STATE_TTL_MS2;
|
|
2684
|
+
function conversationContextKey(conversationId) {
|
|
2685
|
+
return `${CONVERSATION_PREFIX}:${conversationId}:context`;
|
|
2686
|
+
}
|
|
2687
|
+
function conversationTitleKey(conversationId) {
|
|
2688
|
+
return `${CONVERSATION_PREFIX}:${conversationId}:title`;
|
|
2689
|
+
}
|
|
2690
|
+
function parseAgentTurnRequester2(value) {
|
|
2691
|
+
if (!isRecord(value)) return void 0;
|
|
2692
|
+
const requester = {
|
|
2693
|
+
...typeof value.email === "string" ? { email: value.email } : {},
|
|
2694
|
+
...typeof value.fullName === "string" ? { fullName: value.fullName } : {},
|
|
2695
|
+
...typeof value.slackUserId === "string" ? { slackUserId: value.slackUserId } : {},
|
|
2696
|
+
...typeof value.slackUserName === "string" ? { slackUserName: value.slackUserName } : {}
|
|
2697
|
+
};
|
|
2698
|
+
return Object.keys(requester).length > 0 ? requester : void 0;
|
|
2699
|
+
}
|
|
2700
|
+
function parseOriginSurface(value) {
|
|
2701
|
+
if (value === "slack" || value === "api" || value === "scheduler" || value === "internal") {
|
|
2702
|
+
return value;
|
|
2703
|
+
}
|
|
2704
|
+
return void 0;
|
|
2705
|
+
}
|
|
2706
|
+
function storedContextFromInput(context) {
|
|
2707
|
+
return {
|
|
2708
|
+
...context.channelName ? { channelName: context.channelName } : {},
|
|
2709
|
+
...context.originSurface ? { originSurface: context.originSurface } : {},
|
|
2710
|
+
...context.originRequester ? { originRequester: context.originRequester } : {},
|
|
2711
|
+
startedAtMs: context.startedAtMs
|
|
2712
|
+
};
|
|
2713
|
+
}
|
|
2714
|
+
function parseContext(value) {
|
|
2715
|
+
if (!isRecord(value)) return void 0;
|
|
2716
|
+
const startedAtMs = toOptionalNumber(value.startedAtMs);
|
|
2717
|
+
if (startedAtMs === void 0) return void 0;
|
|
2718
|
+
return {
|
|
2719
|
+
...typeof value.channelName === "string" && value.channelName.trim() ? { channelName: value.channelName.trim() } : {},
|
|
2720
|
+
...parseOriginSurface(value.originSurface) ? { originSurface: parseOriginSurface(value.originSurface) } : {},
|
|
2721
|
+
...parseAgentTurnRequester2(value.originRequester) ? { originRequester: parseAgentTurnRequester2(value.originRequester) } : {},
|
|
2722
|
+
startedAtMs
|
|
2723
|
+
};
|
|
2724
|
+
}
|
|
2725
|
+
function parseTitle(value) {
|
|
2726
|
+
if (!isRecord(value)) return void 0;
|
|
2727
|
+
const displayTitle = typeof value.displayTitle === "string" && value.displayTitle.trim() ? value.displayTitle.trim() : void 0;
|
|
2728
|
+
if (!displayTitle) return void 0;
|
|
2729
|
+
return {
|
|
2730
|
+
displayTitle,
|
|
2731
|
+
...typeof value.titleSourceMessageId === "string" ? { titleSourceMessageId: value.titleSourceMessageId } : {}
|
|
2732
|
+
};
|
|
2733
|
+
}
|
|
2734
|
+
async function initConversationContext(conversationId, context) {
|
|
2735
|
+
const stateAdapter = getStateAdapter();
|
|
2736
|
+
await stateAdapter.connect();
|
|
2737
|
+
const key2 = conversationContextKey(conversationId);
|
|
2738
|
+
const inserted = await stateAdapter.setIfNotExists(
|
|
2739
|
+
key2,
|
|
2740
|
+
storedContextFromInput(context),
|
|
2741
|
+
CONVERSATION_DETAILS_TTL_MS
|
|
2742
|
+
);
|
|
2743
|
+
if (inserted) return;
|
|
2744
|
+
const existing = parseContext(await stateAdapter.get(key2));
|
|
2745
|
+
if (!existing) {
|
|
2746
|
+
return;
|
|
2747
|
+
}
|
|
2748
|
+
await stateAdapter.set(key2, existing, CONVERSATION_DETAILS_TTL_MS);
|
|
2749
|
+
}
|
|
2750
|
+
async function setConversationTitle(conversationId, title) {
|
|
2751
|
+
const stateAdapter = getStateAdapter();
|
|
2752
|
+
await stateAdapter.connect();
|
|
2753
|
+
await stateAdapter.set(
|
|
2754
|
+
conversationTitleKey(conversationId),
|
|
2755
|
+
{
|
|
2756
|
+
displayTitle: title.displayTitle,
|
|
2757
|
+
...title.titleSourceMessageId ? { titleSourceMessageId: title.titleSourceMessageId } : {}
|
|
2758
|
+
},
|
|
2759
|
+
CONVERSATION_DETAILS_TTL_MS
|
|
2760
|
+
);
|
|
2761
|
+
}
|
|
2762
|
+
async function getConversationDetails(conversationId) {
|
|
2763
|
+
const stateAdapter = getStateAdapter();
|
|
2764
|
+
await stateAdapter.connect();
|
|
2765
|
+
const [rawContext, rawTitle] = await Promise.all([
|
|
2766
|
+
stateAdapter.get(conversationContextKey(conversationId)),
|
|
2767
|
+
stateAdapter.get(conversationTitleKey(conversationId))
|
|
2768
|
+
]);
|
|
2769
|
+
const context = parseContext(rawContext);
|
|
2770
|
+
const title = parseTitle(rawTitle);
|
|
2771
|
+
if (!context && !title) return void 0;
|
|
2772
|
+
return {
|
|
2773
|
+
conversationId,
|
|
2774
|
+
...title?.displayTitle ? { displayTitle: title.displayTitle } : {},
|
|
2775
|
+
...title?.titleSourceMessageId ? { titleSourceMessageId: title.titleSourceMessageId } : {},
|
|
2776
|
+
...context?.channelName ? { channelName: context.channelName } : {},
|
|
2777
|
+
...context?.originSurface ? { originSurface: context.originSurface } : {},
|
|
2778
|
+
...context?.originRequester ? { originRequester: context.originRequester } : {},
|
|
2779
|
+
...context?.startedAtMs !== void 0 ? { startedAtMs: context.startedAtMs } : {}
|
|
2780
|
+
};
|
|
2781
|
+
}
|
|
2782
|
+
async function getConversationDetailsForIds(conversationIds) {
|
|
2783
|
+
const uniqueIds = [...new Set(conversationIds)].filter(Boolean);
|
|
2784
|
+
const entries = await Promise.all(
|
|
2785
|
+
uniqueIds.map(async (id) => {
|
|
2786
|
+
const details = await getConversationDetails(id);
|
|
2787
|
+
return details ? [id, details] : void 0;
|
|
2788
|
+
})
|
|
2789
|
+
);
|
|
2790
|
+
const result = /* @__PURE__ */ new Map();
|
|
2791
|
+
for (const entry of entries) {
|
|
2792
|
+
if (entry) result.set(entry[0], entry[1]);
|
|
2793
|
+
}
|
|
2794
|
+
return result;
|
|
2795
|
+
}
|
|
2796
|
+
|
|
2937
2797
|
export {
|
|
2938
2798
|
createAgentPluginLogger,
|
|
2939
2799
|
createPluginState,
|
|
2940
|
-
SlackActionError,
|
|
2941
|
-
getHeaderString,
|
|
2942
|
-
normalizeSlackConversationId,
|
|
2943
|
-
withSlackRetries,
|
|
2944
|
-
getSlackClient,
|
|
2945
|
-
isDmChannel,
|
|
2946
|
-
isConversationScopedChannel,
|
|
2947
|
-
isConversationChannel,
|
|
2948
|
-
getFilePermalink,
|
|
2949
|
-
downloadPrivateSlackFile,
|
|
2950
2800
|
bindSlackDirectCredentialSubject,
|
|
2951
2801
|
verifySlackDirectCredentialSubject,
|
|
2802
|
+
resolveChannelCapabilities,
|
|
2952
2803
|
validateAgentPlugins,
|
|
2953
2804
|
setAgentPlugins,
|
|
2954
2805
|
getAgentPlugins,
|
|
@@ -2958,7 +2809,6 @@ export {
|
|
|
2958
2809
|
getAgentPluginOperationalReports,
|
|
2959
2810
|
createAgentPluginHookRunner,
|
|
2960
2811
|
GET,
|
|
2961
|
-
TURN_CONTEXT_TAG,
|
|
2962
2812
|
getInterruptionMarker,
|
|
2963
2813
|
truncateStatusText,
|
|
2964
2814
|
normalizeSlackStatusText,
|
|
@@ -2986,5 +2836,9 @@ export {
|
|
|
2986
2836
|
resolveSlackChannelTypeFromMessage,
|
|
2987
2837
|
resolveSlackConversationContext,
|
|
2988
2838
|
resolveSlackConversationContextFromThreadId,
|
|
2989
|
-
formatSlackConversationRedactedLabel
|
|
2839
|
+
formatSlackConversationRedactedLabel,
|
|
2840
|
+
initConversationContext,
|
|
2841
|
+
setConversationTitle,
|
|
2842
|
+
getConversationDetails,
|
|
2843
|
+
getConversationDetailsForIds
|
|
2990
2844
|
};
|