@sentry/junior 0.202.0 → 0.204.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-CMyTD4DD.js +17509 -0
- package/dist/agent-hooks-Bbcp9e33.js +4040 -0
- package/dist/agent-runner-DNb1A49M.js +678 -0
- package/dist/api/schema.d.ts +2728 -2639
- package/dist/api/schema.js +4 -169
- package/dist/api.d.ts +23 -17
- package/dist/api.js +3881 -5326
- package/dist/app-B1TOqBI8.d.ts +246 -0
- package/dist/app.d.ts +4 -520
- package/dist/app.js +9522 -11875
- package/dist/auth-pause-state-DosEalIG.js +168 -0
- package/dist/catalog-runtime-BReos-D4.js +7 -0
- package/dist/checkpoint-CNrPyRJN.js +2450 -0
- package/dist/cli/chat.d.ts +20 -0
- package/dist/cli/chat.js +229 -336
- package/dist/cli/check.d.ts +8 -0
- package/dist/cli/check.js +513 -806
- package/dist/cli/env.d.ts +13 -0
- package/dist/cli/env.js +63 -12
- package/dist/cli/init.d.ts +3 -0
- package/dist/cli/init.js +90 -159
- package/dist/cli/main.d.ts +6 -0
- package/dist/cli/main.js +43 -64
- package/dist/cli/plugins.d.ts +13 -0
- package/dist/cli/plugins.js +148 -227
- package/dist/cli/run.d.ts +16 -0
- package/dist/cli/run.js +52 -8
- package/dist/cli/snapshot-create.d.ts +4 -0
- package/dist/cli/snapshot-create.js +71 -125
- package/dist/cli/upgrade.d.ts +15 -0
- package/dist/cli/upgrade.js +232 -335
- package/dist/config-nGCW1OTG.js +941 -0
- package/dist/context-B45_WqVX.js +298 -0
- package/dist/conversation-privacy-B4voFRSm.js +182 -0
- package/dist/conversation-work-C6y3T5Hx.js +51 -0
- package/dist/credential-sync-kXr1hvO1.js +2660 -0
- package/dist/db-BeyXKJOI.d.ts +5 -0
- package/dist/destinations-BeBiJeEM.js +29 -0
- package/dist/execution-stats-DWfSihcH.js +373 -0
- package/dist/executor-DcMSlI5c.js +721 -0
- package/dist/experimental-CIXf7Uye.js +46 -0
- package/dist/history-ClE4toxe.d.ts +32 -0
- package/dist/history-CqTuSAdI.js +441 -0
- package/dist/instrumentation.d.ts +3 -3
- package/dist/instrumentation.js +130 -176
- package/dist/job-queue-Drn_LXlM.js +63 -0
- package/dist/logging-BzAk1S_s.js +1210 -0
- package/dist/model-profile-CZmVoGdX.js +49 -0
- package/dist/nitro.d.ts +31 -36
- package/dist/nitro.js +275 -456
- package/dist/oauth-callback-server-JiftokvA.js +130 -0
- package/dist/oauth-relay-CdCnu80W.js +62 -0
- package/dist/package-discovery-7a9YqLhE.js +455 -0
- package/dist/pending-auth-CWmSdZVg.js +185 -0
- package/dist/plugin-module-BKGOXca2.js +81 -0
- package/dist/plugins-BI9A1vKA.d.ts +95 -0
- package/dist/plugins-egKWjgue.js +99 -0
- package/dist/private-trace-result-BLvBjy_e.js +16 -0
- package/dist/profile-CrT5nXbw.js +861 -0
- package/dist/registry-DH1xUo2N.js +1419 -0
- package/dist/reporting-schema-DosTN__Q.js +105 -0
- package/dist/resolve-CZHnfxaS.js +546 -0
- package/dist/rolldown-runtime-B4FMCO8f.js +28 -0
- package/dist/runner-CZV2sC46.js +392 -0
- package/dist/sandbox-egress-signals-bHZfmhbd.js +46 -0
- package/dist/schema-Rn8-XEaN.js +1140 -0
- package/dist/sentry-CD3SdJl-.js +26 -0
- package/dist/skills-CIcDQSgM.js +316 -0
- package/dist/spawn-DdkUFRmq.js +29 -0
- package/dist/stats-DTUbAb88.js +2634 -0
- package/dist/store-C5qxF2ac.d.ts +208 -0
- package/dist/task-queue-CJIR4RF7.js +136 -0
- package/dist/task-runner-D-O3A-Cp.js +639 -0
- package/dist/thread-state-CRc9jTJS.js +431 -0
- package/dist/turn-execution-BkinIdJF.js +47 -0
- package/dist/turn-lifecycle-DQV19VTW.js +54 -0
- package/dist/usage-D3EbSO7w.js +296 -0
- package/dist/usage-schema-CKaDkH_j.js +20 -0
- package/dist/validation-C2CR-OX3.js +40 -0
- package/dist/vercel-queue-DIkVcfK4.js +167 -0
- package/dist/vercel.d.ts +6 -6
- package/dist/vercel.js +14 -6
- package/dist/version-CnXZ614E.d.ts +5 -0
- package/dist/version-DxcWdoKa.js +8 -0
- package/dist/version.d.ts +2 -4
- package/dist/version.js +2 -6
- package/dist/web-authorization-RMBxAR_t.js +76 -0
- package/dist/web-input-3EPfpf55.js +494 -0
- package/dist/work-fGofI7Op.js +509 -0
- package/dist/worker-CsOLq-mR.js +625 -0
- package/package.json +9 -9
- package/dist/agent-hooks-UXITLYOK.js +0 -51
- package/dist/catalog-runtime-BG3JLLK2.js +0 -14
- package/dist/chunk-2LYHWMR4.js +0 -46
- package/dist/chunk-2MK3QBGA.js +0 -321
- package/dist/chunk-3PGQSKJV.js +0 -692
- package/dist/chunk-3UI3WFTX.js +0 -519
- package/dist/chunk-3Y47VMHV.js +0 -6
- package/dist/chunk-4UO6FK4G.js +0 -64
- package/dist/chunk-5NOPO64K.js +0 -198
- package/dist/chunk-5PKWYPFT.js +0 -2943
- package/dist/chunk-63NKKFJL.js +0 -1228
- package/dist/chunk-6AYH6252.js +0 -787
- package/dist/chunk-6Y5B5PEX.js +0 -80
- package/dist/chunk-7DHZP5KJ.js +0 -333
- package/dist/chunk-7H2VZTWN.js +0 -103
- package/dist/chunk-7NL7T6VU.js +0 -406
- package/dist/chunk-A76OIMYN.js +0 -102
- package/dist/chunk-AWMS3SPP.js +0 -58
- package/dist/chunk-B3LY5RCL.js +0 -229
- package/dist/chunk-BD2KT3OB.js +0 -36
- package/dist/chunk-BXCX5QKA.js +0 -2086
- package/dist/chunk-C6VVF43U.js +0 -81
- package/dist/chunk-CEMMLV5L.js +0 -98
- package/dist/chunk-CM5HNV2W.js +0 -131
- package/dist/chunk-DA2KGZZI.js +0 -13
- package/dist/chunk-DBVY6HLX.js +0 -64
- package/dist/chunk-DIB4GX3G.js +0 -8
- package/dist/chunk-DKIJ2RP5.js +0 -68
- package/dist/chunk-DL2KLKVH.js +0 -931
- package/dist/chunk-DWPN6SCH.js +0 -172
- package/dist/chunk-ELWOYVOY.js +0 -206
- package/dist/chunk-EWT7H65X.js +0 -506
- package/dist/chunk-FA6POGLH.js +0 -70
- package/dist/chunk-HMREVIO2.js +0 -135
- package/dist/chunk-IIWUT4FO.js +0 -820
- package/dist/chunk-JAL3CH4G.js +0 -27
- package/dist/chunk-JSJQEWBJ.js +0 -3295
- package/dist/chunk-KHKKHDLD.js +0 -387
- package/dist/chunk-LA6R4A7Q.js +0 -706
- package/dist/chunk-LOOU2DUR.js +0 -20428
- package/dist/chunk-M6FHWXE3.js +0 -700
- package/dist/chunk-M76HMB7M.js +0 -1856
- package/dist/chunk-MAGNK5J4.js +0 -1520
- package/dist/chunk-MTM5IFCY.js +0 -1190
- package/dist/chunk-N7TMSOZH.js +0 -235
- package/dist/chunk-NHJU2ZAL.js +0 -56
- package/dist/chunk-NSXKRGRT.js +0 -717
- package/dist/chunk-OWMPFXJA.js +0 -1764
- package/dist/chunk-PDO5BLNM.js +0 -22
- package/dist/chunk-PEQXYSSE.js +0 -45
- package/dist/chunk-PW4P4JYF.js +0 -1135
- package/dist/chunk-QB54UQUS.js +0 -320
- package/dist/chunk-QP3OGJXF.js +0 -105
- package/dist/chunk-RC745GGZ.js +0 -122
- package/dist/chunk-REOIRYPR.js +0 -37
- package/dist/chunk-SCOZRLZ4.js +0 -164
- package/dist/chunk-TXJSXBV5.js +0 -1433
- package/dist/chunk-TXKUKMVO.js +0 -417
- package/dist/chunk-U2GPUYAL.js +0 -3656
- package/dist/chunk-UIE3R5XU.js +0 -17
- package/dist/chunk-UXPG6ZIN.js +0 -84
- package/dist/chunk-VFUK3X5B.js +0 -50
- package/dist/chunk-WQSHDTTI.js +0 -1163
- package/dist/chunk-X6GDDWQH.js +0 -60
- package/dist/chunk-Y2CM7HXH.js +0 -111
- package/dist/chunk-Y7X25LFY.js +0 -15
- package/dist/chunk-YDUR3ZYW.js +0 -10
- package/dist/conversation-work-VIOQ5ZF3.js +0 -54
- package/dist/db-3L2MCVRI.js +0 -26
- package/dist/discovery-DWVDM7UK.js +0 -44
- package/dist/experimental-P5FZM4CU.js +0 -12
- package/dist/oauth-callback-server-YVV6C6T2.js +0 -243
- package/dist/oauth-relay-5XPVRPYB.js +0 -8
- package/dist/plugins-YTYJMMJF.js +0 -14
- package/dist/runner-LQ7RETDP.js +0 -522
- package/dist/sandbox-egress-signals-FIL7EGPR.js +0 -73
- package/dist/sentry-MB3NL3IR.js +0 -42
- package/dist/skills-XRWYEDCD.js +0 -27
- package/dist/spawn-RC6SJUAI.js +0 -42
- package/dist/task-runner-7DY7ARYH.js +0 -36
- package/dist/validation-7MNQGCJA.js +0 -17
- package/dist/work-COALHUCG.js +0 -51
- package/dist/worker-6MURZIPD.js +0 -24
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import "@sentry/junior-plugin-api";
|
|
3
|
+
//#region src/chat/slack/timestamp.ts
|
|
4
|
+
/** Native Slack message timestamp, safe to pass as Slack Web API `message_ts`. */
|
|
5
|
+
const slackMessageTsSchema = z.string().trim().regex(/^\d+(?:\.\d+)?$/).brand();
|
|
6
|
+
/** Parse a native Slack message timestamp from untrusted message metadata. */
|
|
7
|
+
function parseSlackMessageTs(value) {
|
|
8
|
+
const parsed = slackMessageTsSchema.safeParse(value);
|
|
9
|
+
return parsed.success ? parsed.data : void 0;
|
|
10
|
+
}
|
|
11
|
+
//#endregion
|
|
12
|
+
//#region src/chat/slack/ids.ts
|
|
13
|
+
const slackChannelIdSchema = z.string().regex(/^[CDG][A-Z0-9]+$/).brand();
|
|
14
|
+
const slackTeamIdSchema = z.string().regex(/^T[A-Z0-9]+$/).brand();
|
|
15
|
+
const slackUserIdSchema = z.string().regex(/^[UW][A-Z0-9]+$/).brand();
|
|
16
|
+
const SLACK_CHANNEL_MENTION_RE = /^<#([CDG][A-Z0-9]+)(?:\|[^>]*)?>$/;
|
|
17
|
+
function slackChannelReferenceCandidate(value) {
|
|
18
|
+
const trimmed = value.trim();
|
|
19
|
+
if (!trimmed.startsWith("slack:")) return trimmed;
|
|
20
|
+
const parts = trimmed.split(":");
|
|
21
|
+
if (parts.length === 2) return parts[1]?.trim() ?? "";
|
|
22
|
+
if (parts.length === 3 && parseSlackMessageTs(parts[2])) return parts[1]?.trim() ?? "";
|
|
23
|
+
return "";
|
|
24
|
+
}
|
|
25
|
+
/** Parse an exact Slack channel/conversation ID from untrusted input. */
|
|
26
|
+
function parseSlackChannelId(value) {
|
|
27
|
+
if (typeof value !== "string") return void 0;
|
|
28
|
+
const parsed = slackChannelIdSchema.safeParse(value.trim());
|
|
29
|
+
return parsed.success ? parsed.data : void 0;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Parse a channel id from common tool/model reference forms.
|
|
33
|
+
*
|
|
34
|
+
* Accepts exact ids (`C123`), Slack mentions (`<#C123>` / `<#C123|name>`),
|
|
35
|
+
* and Junior slack references (`slack:C123`, `slack:C123:ts`). Plain channel
|
|
36
|
+
* names are not ids and are rejected here.
|
|
37
|
+
*/
|
|
38
|
+
function parseSlackChannelReferenceId(value) {
|
|
39
|
+
if (typeof value !== "string") return void 0;
|
|
40
|
+
const trimmed = value.trim();
|
|
41
|
+
const mentionMatch = SLACK_CHANNEL_MENTION_RE.exec(trimmed);
|
|
42
|
+
if (mentionMatch?.[1]) return parseSlackChannelId(mentionMatch[1]);
|
|
43
|
+
return parseSlackChannelId(slackChannelReferenceCandidate(trimmed));
|
|
44
|
+
}
|
|
45
|
+
/** Parse a Slack workspace/team ID from untrusted metadata. */
|
|
46
|
+
function parseSlackTeamId(value) {
|
|
47
|
+
if (typeof value !== "string") return void 0;
|
|
48
|
+
const parsed = slackTeamIdSchema.safeParse(value.trim());
|
|
49
|
+
return parsed.success ? parsed.data : void 0;
|
|
50
|
+
}
|
|
51
|
+
/** Parse a Slack user ID from untrusted metadata. */
|
|
52
|
+
function parseSlackUserId(value) {
|
|
53
|
+
if (typeof value !== "string") return void 0;
|
|
54
|
+
const parsed = slackUserIdSchema.safeParse(value.trim());
|
|
55
|
+
return parsed.success ? parsed.data : void 0;
|
|
56
|
+
}
|
|
57
|
+
//#endregion
|
|
58
|
+
//#region src/chat/actor.ts
|
|
59
|
+
/**
|
|
60
|
+
* Canonical actor identity.
|
|
61
|
+
*
|
|
62
|
+
* Runtime actors are platform-scoped actors. Stored Slack actor parsing
|
|
63
|
+
* remains explicit so durable conversation metadata is not repaired on read.
|
|
64
|
+
*/
|
|
65
|
+
const SLACK_USER_ID_DISPLAY_PATTERN = /^[UW][A-Z0-9]{5,}$/;
|
|
66
|
+
const EMAIL_PATTERN = /^[^\s@<>]+@[^\s@<>]+\.[^\s@<>]+$/;
|
|
67
|
+
const exactStoredStringSchema = z.string().min(1).refine((value) => value === value.trim());
|
|
68
|
+
const storedSlackActorSchema = z.object({
|
|
69
|
+
email: exactStoredStringSchema.optional(),
|
|
70
|
+
fullName: exactStoredStringSchema.optional(),
|
|
71
|
+
platform: z.literal("slack").optional(),
|
|
72
|
+
slackUserId: exactStoredStringSchema.optional(),
|
|
73
|
+
slackUserName: exactStoredStringSchema.optional(),
|
|
74
|
+
teamId: exactStoredStringSchema.optional()
|
|
75
|
+
}).strict();
|
|
76
|
+
/** Return whether an actor is a platform-scoped user actor. */
|
|
77
|
+
function isUserActor(actor) {
|
|
78
|
+
return Boolean(actor && "userId" in actor);
|
|
79
|
+
}
|
|
80
|
+
function clean(value) {
|
|
81
|
+
const trimmed = value?.trim();
|
|
82
|
+
return trimmed ? trimmed : void 0;
|
|
83
|
+
}
|
|
84
|
+
function isSyntheticActorUserId(value) {
|
|
85
|
+
return value.toLowerCase() === "unknown";
|
|
86
|
+
}
|
|
87
|
+
function isSlackUserId(value) {
|
|
88
|
+
return SLACK_USER_ID_DISPLAY_PATTERN.test(value);
|
|
89
|
+
}
|
|
90
|
+
function cleanActorDisplayName(value, userId) {
|
|
91
|
+
const displayName = clean(value);
|
|
92
|
+
if (!displayName) return;
|
|
93
|
+
if (displayName.toLowerCase() === "unknown") return;
|
|
94
|
+
if (userId && displayName === userId) return;
|
|
95
|
+
return isSlackUserId(displayName) ? void 0 : displayName;
|
|
96
|
+
}
|
|
97
|
+
function cleanActorEmail(value) {
|
|
98
|
+
const email = clean(value);
|
|
99
|
+
return email && EMAIL_PATTERN.test(email) ? email : void 0;
|
|
100
|
+
}
|
|
101
|
+
/** Keep actor ids exact at platform boundaries before they enter owned state. */
|
|
102
|
+
function parseActorUserId(value) {
|
|
103
|
+
if (typeof value !== "string" || value.length === 0) return;
|
|
104
|
+
if (value !== value.trim() || isSyntheticActorUserId(value)) return;
|
|
105
|
+
return value;
|
|
106
|
+
}
|
|
107
|
+
/** Assert persisted actor ids without read-side repair. */
|
|
108
|
+
function isActorUserId(value) {
|
|
109
|
+
return parseActorUserId(value) === value;
|
|
110
|
+
}
|
|
111
|
+
/** Build Junior's canonical platform actor from exact actor ids and profile data. */
|
|
112
|
+
function createActor(input, context) {
|
|
113
|
+
const platform = context.platform ?? input?.platform;
|
|
114
|
+
if (!platform) return;
|
|
115
|
+
const contextUserId = parseActorUserId(context.userId);
|
|
116
|
+
if (context.userId !== void 0 && !contextUserId) return;
|
|
117
|
+
const inputUserId = parseActorUserId(input?.userId);
|
|
118
|
+
if (input?.userId !== void 0 && !inputUserId) return;
|
|
119
|
+
const actorUserId = contextUserId ?? inputUserId;
|
|
120
|
+
if (!actorUserId) return;
|
|
121
|
+
const contextTeamId = parseSlackTeamId(context.teamId);
|
|
122
|
+
if (context.teamId !== void 0 && !contextTeamId) return;
|
|
123
|
+
const inputTeamId = parseSlackTeamId(input?.teamId);
|
|
124
|
+
if (input?.teamId !== void 0 && !inputTeamId) return;
|
|
125
|
+
const actorTeamId = contextTeamId ?? inputTeamId;
|
|
126
|
+
if (platform === "slack" && !actorTeamId) return;
|
|
127
|
+
const canUseInputProfile = (!contextUserId || !inputUserId || contextUserId === inputUserId) && (platform !== "slack" || !contextTeamId || !inputTeamId || contextTeamId === inputTeamId);
|
|
128
|
+
const actor = {
|
|
129
|
+
...canUseInputProfile && cleanActorEmail(input?.email) ? { email: cleanActorEmail(input?.email) } : void 0,
|
|
130
|
+
...canUseInputProfile && cleanActorDisplayName(input?.fullName, actorUserId) ? { fullName: cleanActorDisplayName(input?.fullName, actorUserId) } : void 0,
|
|
131
|
+
platform,
|
|
132
|
+
userId: actorUserId,
|
|
133
|
+
...canUseInputProfile && cleanActorDisplayName(input?.userName, actorUserId) ? { userName: cleanActorDisplayName(input?.userName, actorUserId) } : void 0
|
|
134
|
+
};
|
|
135
|
+
if (platform === "slack") return {
|
|
136
|
+
...actor,
|
|
137
|
+
platform,
|
|
138
|
+
teamId: actorTeamId
|
|
139
|
+
};
|
|
140
|
+
return {
|
|
141
|
+
...actor,
|
|
142
|
+
platform
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
/** Build Junior's canonical actor from Slack profile data. */
|
|
146
|
+
function createSlackActor(teamId, userId, profile) {
|
|
147
|
+
const actorUserId = parseActorUserId(userId);
|
|
148
|
+
const actorTeamId = parseSlackTeamId(teamId);
|
|
149
|
+
if (!actorTeamId || !actorUserId) throw new Error("Slack actor requires team and user ids");
|
|
150
|
+
const actor = createActor({
|
|
151
|
+
email: profile?.email,
|
|
152
|
+
fullName: profile?.fullName,
|
|
153
|
+
platform: "slack",
|
|
154
|
+
teamId: actorTeamId,
|
|
155
|
+
userId: actorUserId,
|
|
156
|
+
userName: profile?.userName
|
|
157
|
+
}, {
|
|
158
|
+
teamId: actorTeamId,
|
|
159
|
+
userId: actorUserId
|
|
160
|
+
});
|
|
161
|
+
if (!actor || actor.platform !== "slack") throw new Error("Slack actor requires team and user ids");
|
|
162
|
+
return actor;
|
|
163
|
+
}
|
|
164
|
+
/** Parse a serialized Slack actor that crossed a runtime boundary. */
|
|
165
|
+
function parseStoredSlackActor(value) {
|
|
166
|
+
const parsed = storedSlackActorSchema.safeParse(value);
|
|
167
|
+
if (!parsed.success) return;
|
|
168
|
+
if (parsed.data.slackUserId !== void 0 && !parseActorUserId(parsed.data.slackUserId)) return;
|
|
169
|
+
if (parsed.data.teamId !== void 0 && !parseSlackTeamId(parsed.data.teamId)) return;
|
|
170
|
+
if ((parsed.data.platform !== void 0 || parsed.data.teamId !== void 0) && (!parsed.data.platform || !parsed.data.teamId)) return;
|
|
171
|
+
return parsed.data;
|
|
172
|
+
}
|
|
173
|
+
/** Convert a runtime Slack actor into its durable session shape. */
|
|
174
|
+
function toStoredSlackActor(actor) {
|
|
175
|
+
return {
|
|
176
|
+
...actor.email ? { email: actor.email } : void 0,
|
|
177
|
+
...actor.fullName ? { fullName: actor.fullName } : void 0,
|
|
178
|
+
platform: actor.platform,
|
|
179
|
+
slackUserId: actor.userId,
|
|
180
|
+
...actor.userName ? { slackUserName: actor.userName } : void 0,
|
|
181
|
+
teamId: actor.teamId
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Resolve a Slack resume actor from stored profile data and the active actor.
|
|
186
|
+
*
|
|
187
|
+
* TODO(dcramer): Require Actor and remove ID-only construction after no
|
|
188
|
+
* deployed Turn cursor can omit Actor.
|
|
189
|
+
*/
|
|
190
|
+
function createSlackResumeActor(args) {
|
|
191
|
+
if (args.actor) {
|
|
192
|
+
if (args.actor.platform !== "slack" || args.actor.teamId !== args.teamId || args.actor.userId !== args.userId) throw new Error("Stored Slack actor did not match resume actor");
|
|
193
|
+
}
|
|
194
|
+
const actor = createActor(args.actor, {
|
|
195
|
+
platform: "slack",
|
|
196
|
+
teamId: args.teamId,
|
|
197
|
+
userId: args.userId
|
|
198
|
+
});
|
|
199
|
+
if (!actor || actor.platform !== "slack") throw new Error("Slack actor requires team and user ids");
|
|
200
|
+
return actor;
|
|
201
|
+
}
|
|
202
|
+
//#endregion
|
|
203
|
+
//#region src/chat/credentials/context.ts
|
|
204
|
+
const exactActorIdSchema = z.string().refine((value) => parseActorUserId(value) === value);
|
|
205
|
+
const exactNonBlankStringSchema = z.string().min(1).refine((value) => value === value.trim());
|
|
206
|
+
const slackDirectCredentialSubjectBindingSchema = z.object({
|
|
207
|
+
type: z.literal("slack-direct-conversation"),
|
|
208
|
+
teamId: z.string().min(1),
|
|
209
|
+
channelId: z.string().min(1),
|
|
210
|
+
signature: z.string().min(1)
|
|
211
|
+
}).strict();
|
|
212
|
+
const scheduledTaskCredentialSubjectBindingSchema = z.object({
|
|
213
|
+
type: z.literal("scheduled-task"),
|
|
214
|
+
plugin: z.string().min(1),
|
|
215
|
+
taskId: exactNonBlankStringSchema,
|
|
216
|
+
signature: z.string().min(1)
|
|
217
|
+
}).strict();
|
|
218
|
+
const eventTaskCredentialSubjectBindingSchema = z.object({
|
|
219
|
+
type: z.literal("event-task"),
|
|
220
|
+
plugin: z.string().min(1),
|
|
221
|
+
taskId: exactNonBlankStringSchema,
|
|
222
|
+
signature: z.string().min(1)
|
|
223
|
+
}).strict();
|
|
224
|
+
z.discriminatedUnion("type", [
|
|
225
|
+
slackDirectCredentialSubjectBindingSchema,
|
|
226
|
+
scheduledTaskCredentialSubjectBindingSchema,
|
|
227
|
+
eventTaskCredentialSubjectBindingSchema
|
|
228
|
+
]);
|
|
229
|
+
const credentialUserActorSchema = z.object({
|
|
230
|
+
type: z.literal("user"),
|
|
231
|
+
userId: exactActorIdSchema
|
|
232
|
+
}).strict();
|
|
233
|
+
const credentialSystemActorSchema = z.object({
|
|
234
|
+
platform: z.literal("system"),
|
|
235
|
+
name: exactActorIdSchema
|
|
236
|
+
}).strict();
|
|
237
|
+
const credentialSubjectSchema = z.discriminatedUnion("allowedWhen", [
|
|
238
|
+
z.object({
|
|
239
|
+
type: z.literal("user"),
|
|
240
|
+
userId: exactActorIdSchema,
|
|
241
|
+
allowedWhen: z.literal("private-direct-conversation"),
|
|
242
|
+
binding: slackDirectCredentialSubjectBindingSchema
|
|
243
|
+
}).strict(),
|
|
244
|
+
z.object({
|
|
245
|
+
type: z.literal("user"),
|
|
246
|
+
userId: exactActorIdSchema,
|
|
247
|
+
allowedWhen: z.literal("scheduled-task"),
|
|
248
|
+
taskId: exactNonBlankStringSchema,
|
|
249
|
+
binding: scheduledTaskCredentialSubjectBindingSchema
|
|
250
|
+
}).strict().refine((subject) => subject.binding.taskId === subject.taskId, {
|
|
251
|
+
message: "Scheduled task credential subject requires task binding",
|
|
252
|
+
path: ["binding"]
|
|
253
|
+
}),
|
|
254
|
+
z.object({
|
|
255
|
+
type: z.literal("user"),
|
|
256
|
+
userId: exactActorIdSchema,
|
|
257
|
+
allowedWhen: z.literal("event-task"),
|
|
258
|
+
taskId: exactNonBlankStringSchema,
|
|
259
|
+
binding: eventTaskCredentialSubjectBindingSchema
|
|
260
|
+
}).strict().refine((subject) => subject.binding.taskId === subject.taskId, {
|
|
261
|
+
message: "Event task credential subject requires task binding",
|
|
262
|
+
path: ["binding"]
|
|
263
|
+
})
|
|
264
|
+
]);
|
|
265
|
+
const credentialContextSchema = z.union([z.object({ actor: credentialUserActorSchema }).strict(), z.object({
|
|
266
|
+
actor: credentialSystemActorSchema,
|
|
267
|
+
subject: credentialSubjectSchema.optional()
|
|
268
|
+
}).strict()]);
|
|
269
|
+
/**
|
|
270
|
+
* Build credential authority from the run actor.
|
|
271
|
+
*
|
|
272
|
+
* `actor` is the rich execution principal. This projects the credential stub
|
|
273
|
+
* tools/auth need from it:
|
|
274
|
+
* - user actor → `{ actor: { type: "user", userId } }`
|
|
275
|
+
* - system actor → `{ actor: systemActor, subject? }`
|
|
276
|
+
*
|
|
277
|
+
* They only diverge when a system run carries an explicit delegated `subject`
|
|
278
|
+
* (scheduled/event-task creator credentials). Callers should set `actor` first,
|
|
279
|
+
* then derive this — do not hand-build parallel shapes.
|
|
280
|
+
*/
|
|
281
|
+
function credentialContextForActor(actor, subject) {
|
|
282
|
+
if (actor.platform === "system") return subject ? {
|
|
283
|
+
actor,
|
|
284
|
+
subject
|
|
285
|
+
} : { actor };
|
|
286
|
+
if (subject) throw new TypeError("Delegated credential subjects require a system actor");
|
|
287
|
+
return { actor: {
|
|
288
|
+
type: "user",
|
|
289
|
+
userId: actor.userId
|
|
290
|
+
} };
|
|
291
|
+
}
|
|
292
|
+
/** Return the user whose OAuth token may satisfy this credential request. */
|
|
293
|
+
function credentialUserSubjectId(context) {
|
|
294
|
+
if ("type" in context.actor) return context.actor.userId;
|
|
295
|
+
return "subject" in context ? context.subject?.userId : void 0;
|
|
296
|
+
}
|
|
297
|
+
//#endregion
|
|
298
|
+
export { parseSlackMessageTs as _, createActor as a, isActorUserId as c, parseStoredSlackActor as d, toStoredSlackActor as f, parseSlackUserId as g, parseSlackTeamId as h, credentialUserSubjectId as i, isUserActor as l, parseSlackChannelReferenceId as m, credentialContextSchema as n, createSlackActor as o, parseSlackChannelId as p, credentialSubjectSchema as r, createSlackResumeActor as s, credentialContextForActor as t, parseActorUserId as u };
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import { f as logWarn } from "./logging-BzAk1S_s.js";
|
|
2
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
3
|
+
//#region src/chat/conversation-privacy.ts
|
|
4
|
+
const SAFE_METADATA_KEY_LIMIT = 20;
|
|
5
|
+
const conversationPrivacyStorage = new AsyncLocalStorage();
|
|
6
|
+
/**
|
|
7
|
+
* Resolve whether a Conversation may expose full transcript and tool data.
|
|
8
|
+
*
|
|
9
|
+
* Read visibility from the stored Conversation. If it is missing, warn and
|
|
10
|
+
* treat the Conversation as private. Do not infer visibility from identifiers.
|
|
11
|
+
*/
|
|
12
|
+
function resolveConversationPrivacy(input) {
|
|
13
|
+
if (input.visibility === void 0) logWarn("conversation.visibility.defaulted");
|
|
14
|
+
return input.visibility === "public" ? "public" : "private";
|
|
15
|
+
}
|
|
16
|
+
/** Return whether a public Conversation may expose transcript and tool data. */
|
|
17
|
+
function canExposeConversationPayload(input) {
|
|
18
|
+
return resolveConversationPrivacy(input) === "public";
|
|
19
|
+
}
|
|
20
|
+
/** Return privacy for the current agent Turn. */
|
|
21
|
+
function getCurrentConversationPrivacy() {
|
|
22
|
+
return conversationPrivacyStorage.getStore();
|
|
23
|
+
}
|
|
24
|
+
/** Bind one conversation privacy mode to all async work in a turn. */
|
|
25
|
+
function runWithConversationPrivacy(privacy, callback) {
|
|
26
|
+
return conversationPrivacyStorage.run(privacy, callback);
|
|
27
|
+
}
|
|
28
|
+
function payloadType(payload) {
|
|
29
|
+
return Array.isArray(payload) ? "array" : typeof payload;
|
|
30
|
+
}
|
|
31
|
+
function payloadKeys(payload) {
|
|
32
|
+
if (!payload || typeof payload !== "object" || Array.isArray(payload)) return;
|
|
33
|
+
const keys = Object.keys(payload).slice(0, SAFE_METADATA_KEY_LIMIT);
|
|
34
|
+
return keys.length > 0 ? keys : void 0;
|
|
35
|
+
}
|
|
36
|
+
function serializedLength(payload) {
|
|
37
|
+
return (typeof payload === "string" ? payload : JSON.stringify(payload))?.length ?? 0;
|
|
38
|
+
}
|
|
39
|
+
/** Convert an arbitrary payload into safe structured metadata for trace data fields. */
|
|
40
|
+
function toGenAiPayloadMetadata(payload) {
|
|
41
|
+
const base = {
|
|
42
|
+
type: payloadType(payload),
|
|
43
|
+
chars: serializedLength(payload)
|
|
44
|
+
};
|
|
45
|
+
if (!payload || typeof payload !== "object" || Array.isArray(payload)) return base;
|
|
46
|
+
const keys = payloadKeys(payload);
|
|
47
|
+
return {
|
|
48
|
+
...base,
|
|
49
|
+
...keys ? { keys } : void 0
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
/** Convert an arbitrary payload into safe flattened trace attributes. */
|
|
53
|
+
function toGenAiPayloadTraceAttributes(prefix, payload) {
|
|
54
|
+
const size = serializedLength(payload);
|
|
55
|
+
const attributes = {
|
|
56
|
+
[`${prefix}.type`]: payloadType(payload),
|
|
57
|
+
[`${prefix}.size_chars`]: size,
|
|
58
|
+
[`${prefix}.size`]: size
|
|
59
|
+
};
|
|
60
|
+
const keys = payloadKeys(payload);
|
|
61
|
+
if (keys) attributes[`${prefix}.keys`] = keys;
|
|
62
|
+
return attributes;
|
|
63
|
+
}
|
|
64
|
+
function summarizeContent(content) {
|
|
65
|
+
if (typeof content === "string") return {
|
|
66
|
+
chars: content.length,
|
|
67
|
+
partTypes: ["text"]
|
|
68
|
+
};
|
|
69
|
+
if (!Array.isArray(content)) return {
|
|
70
|
+
chars: serializedLength(content),
|
|
71
|
+
partTypes: [payloadType(content)]
|
|
72
|
+
};
|
|
73
|
+
let chars = 0;
|
|
74
|
+
const partTypes = /* @__PURE__ */ new Set();
|
|
75
|
+
for (const part of content) {
|
|
76
|
+
if (!part || typeof part !== "object") {
|
|
77
|
+
chars += serializedLength(part);
|
|
78
|
+
partTypes.add(payloadType(part));
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
const record = part;
|
|
82
|
+
const type = canonicalContentPartType(typeof record.type === "string" ? record.type : "unknown");
|
|
83
|
+
partTypes.add(type);
|
|
84
|
+
if (typeof record.text === "string") chars += record.text.length;
|
|
85
|
+
else if (typeof record.thinking === "string") chars += record.thinking.length;
|
|
86
|
+
else if (typeof record.data === "string") chars += record.data.length;
|
|
87
|
+
else chars += serializedLength(part);
|
|
88
|
+
}
|
|
89
|
+
return {
|
|
90
|
+
chars,
|
|
91
|
+
partTypes: [...partTypes]
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
function normalizeFinishReason(reason) {
|
|
95
|
+
return reason === "toolUse" ? "tool_call" : reason;
|
|
96
|
+
}
|
|
97
|
+
function canonicalContentPartType(type) {
|
|
98
|
+
if (type === "thinking") return "reasoning";
|
|
99
|
+
if (type === "toolCall") return "tool_call";
|
|
100
|
+
return type;
|
|
101
|
+
}
|
|
102
|
+
function toCanonicalPart(part) {
|
|
103
|
+
if (part.type === "text") return {
|
|
104
|
+
type: "text",
|
|
105
|
+
content: part.text
|
|
106
|
+
};
|
|
107
|
+
if (part.type === "thinking") {
|
|
108
|
+
if (part.redacted) return;
|
|
109
|
+
return {
|
|
110
|
+
type: "reasoning",
|
|
111
|
+
content: part.thinking
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
if (part.type === "toolCall") return {
|
|
115
|
+
type: "tool_call",
|
|
116
|
+
id: part.id,
|
|
117
|
+
name: part.name,
|
|
118
|
+
arguments: part.arguments
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
function toCanonicalParts(parts) {
|
|
122
|
+
return parts.map(toCanonicalPart).filter((part) => part !== void 0);
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Map a pi-ai AssistantMessage to the canonical gen_ai.output.messages shape:
|
|
126
|
+
* `{ role, parts: [...], finish_reason }` — drops provider noise fields.
|
|
127
|
+
*/
|
|
128
|
+
function toCanonicalOutputMessage(message) {
|
|
129
|
+
return {
|
|
130
|
+
role: "assistant",
|
|
131
|
+
parts: toCanonicalParts(message.content),
|
|
132
|
+
finish_reason: normalizeFinishReason(message.stopReason)
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Map a pi-ai Message (user/assistant/toolResult) to the canonical
|
|
137
|
+
* gen_ai.input.messages shape: `{ role, parts: [...] }`.
|
|
138
|
+
*/
|
|
139
|
+
function toCanonicalInputMessage(message) {
|
|
140
|
+
if (message.role === "user") return {
|
|
141
|
+
role: "user",
|
|
142
|
+
parts: typeof message.content === "string" ? [{
|
|
143
|
+
type: "text",
|
|
144
|
+
content: message.content
|
|
145
|
+
}] : toCanonicalParts(message.content)
|
|
146
|
+
};
|
|
147
|
+
if (message.role === "toolResult") return {
|
|
148
|
+
role: "tool",
|
|
149
|
+
parts: [{
|
|
150
|
+
type: "tool_call_response",
|
|
151
|
+
id: message.toolCallId,
|
|
152
|
+
response: toCanonicalParts(message.content)
|
|
153
|
+
}]
|
|
154
|
+
};
|
|
155
|
+
return toCanonicalOutputMessage(message);
|
|
156
|
+
}
|
|
157
|
+
/** Summarize a message list without exposing raw message content. */
|
|
158
|
+
function toGenAiMessagesTraceAttributes(prefix, messages) {
|
|
159
|
+
let contentChars = 0;
|
|
160
|
+
const roles = /* @__PURE__ */ new Set();
|
|
161
|
+
const partTypes = /* @__PURE__ */ new Set();
|
|
162
|
+
for (const message of messages) {
|
|
163
|
+
if (!message || typeof message !== "object") {
|
|
164
|
+
contentChars += serializedLength(message);
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
const record = message;
|
|
168
|
+
if (typeof record.role === "string") roles.add(record.role);
|
|
169
|
+
const summary = summarizeContent(record.content);
|
|
170
|
+
contentChars += summary.chars;
|
|
171
|
+
for (const partType of summary.partTypes) partTypes.add(partType);
|
|
172
|
+
}
|
|
173
|
+
return {
|
|
174
|
+
[`${prefix}.message_count`]: messages.length,
|
|
175
|
+
[`${prefix}.content_chars`]: contentChars,
|
|
176
|
+
[`${prefix}.messages.size`]: contentChars,
|
|
177
|
+
...roles.size > 0 ? { [`${prefix}.roles`]: [...roles] } : void 0,
|
|
178
|
+
...partTypes.size > 0 ? { [`${prefix}.part_types`]: [...partTypes] } : void 0
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
//#endregion
|
|
182
|
+
export { toCanonicalInputMessage as a, toGenAiPayloadMetadata as c, runWithConversationPrivacy as i, toGenAiPayloadTraceAttributes as l, getCurrentConversationPrivacy as n, toCanonicalOutputMessage as o, resolveConversationPrivacy as r, toGenAiMessagesTraceAttributes as s, canExposeConversationPayload as t };
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
//#region src/chat/local/conversation-work.ts
|
|
2
|
+
/**
|
|
3
|
+
* Run local conversation work in this process and wait for every accepted wake.
|
|
4
|
+
*
|
|
5
|
+
* Wakes start on a later event-loop turn so their producer can persist the
|
|
6
|
+
* accepted marker first. Idempotent, delayed, and follow-up wakes remain
|
|
7
|
+
* tracked so CLI shutdown cannot abandon accepted child work.
|
|
8
|
+
*/
|
|
9
|
+
function createLocalConversationWork(processMessage) {
|
|
10
|
+
const acceptedWakeIds = /* @__PURE__ */ new Map();
|
|
11
|
+
const pending = /* @__PURE__ */ new Set();
|
|
12
|
+
let firstError;
|
|
13
|
+
let nextWakeId = 1;
|
|
14
|
+
function schedule(message, options) {
|
|
15
|
+
const delayMs = Math.max(0, options?.delayMs ?? 0);
|
|
16
|
+
let work;
|
|
17
|
+
work = (async () => {
|
|
18
|
+
await new Promise((resolve) => {
|
|
19
|
+
setTimeout(resolve, delayMs);
|
|
20
|
+
});
|
|
21
|
+
await processMessage(message);
|
|
22
|
+
})().catch((error) => {
|
|
23
|
+
firstError ??= error;
|
|
24
|
+
}).finally(() => {
|
|
25
|
+
pending.delete(work);
|
|
26
|
+
});
|
|
27
|
+
pending.add(work);
|
|
28
|
+
}
|
|
29
|
+
return {
|
|
30
|
+
queue: { async send(message, options) {
|
|
31
|
+
const idempotencyKey = options?.idempotencyKey;
|
|
32
|
+
const acceptedWakeId = idempotencyKey ? acceptedWakeIds.get(idempotencyKey) : void 0;
|
|
33
|
+
if (acceptedWakeId) return { messageId: acceptedWakeId };
|
|
34
|
+
const messageId = `local-conversation-work:${nextWakeId}`;
|
|
35
|
+
nextWakeId += 1;
|
|
36
|
+
if (idempotencyKey) acceptedWakeIds.set(idempotencyKey, messageId);
|
|
37
|
+
schedule(message, options);
|
|
38
|
+
return { messageId };
|
|
39
|
+
} },
|
|
40
|
+
async drain() {
|
|
41
|
+
while (pending.size > 0) await Promise.all(pending);
|
|
42
|
+
if (firstError !== void 0) {
|
|
43
|
+
const error = firstError;
|
|
44
|
+
firstError = void 0;
|
|
45
|
+
throw error;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
//#endregion
|
|
51
|
+
export { createLocalConversationWork };
|