@sentry/junior 0.203.0 → 0.205.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.
Files changed (174) hide show
  1. package/dist/agent-D4nu8MQV.js +17521 -0
  2. package/dist/agent-hooks-DXHpTJ4m.js +4042 -0
  3. package/dist/agent-runner-C04colea.js +678 -0
  4. package/dist/api/schema.d.ts +2736 -2639
  5. package/dist/api/schema.js +4 -169
  6. package/dist/api.d.ts +23 -17
  7. package/dist/api.js +3881 -5326
  8. package/dist/app-Cb776lL8.d.ts +247 -0
  9. package/dist/app.d.ts +4 -520
  10. package/dist/app.js +9524 -11875
  11. package/dist/auth-pause-state-C2P3guS1.js +168 -0
  12. package/dist/catalog-runtime-CXw3asJD.js +7 -0
  13. package/dist/checkpoint-CrViJ8Ps.js +2450 -0
  14. package/dist/cli/chat.d.ts +20 -0
  15. package/dist/cli/chat.js +229 -336
  16. package/dist/cli/check.d.ts +8 -0
  17. package/dist/cli/check.js +513 -806
  18. package/dist/cli/env.d.ts +13 -0
  19. package/dist/cli/env.js +63 -12
  20. package/dist/cli/init.d.ts +3 -0
  21. package/dist/cli/init.js +90 -159
  22. package/dist/cli/main.d.ts +6 -0
  23. package/dist/cli/main.js +43 -64
  24. package/dist/cli/plugins.d.ts +13 -0
  25. package/dist/cli/plugins.js +148 -227
  26. package/dist/cli/run.d.ts +16 -0
  27. package/dist/cli/run.js +52 -8
  28. package/dist/cli/snapshot-create.d.ts +4 -0
  29. package/dist/cli/snapshot-create.js +71 -125
  30. package/dist/cli/upgrade.d.ts +15 -0
  31. package/dist/cli/upgrade.js +232 -335
  32. package/dist/config-BOtJQ7Pc.js +941 -0
  33. package/dist/context-B45_WqVX.js +298 -0
  34. package/dist/conversation-privacy-BZRA6Pes.js +182 -0
  35. package/dist/conversation-work-C6y3T5Hx.js +51 -0
  36. package/dist/credential-sync-Bep34IB_.js +2661 -0
  37. package/dist/db-BeyXKJOI.d.ts +5 -0
  38. package/dist/destinations-BeBiJeEM.js +29 -0
  39. package/dist/execution-stats-B6lgWxCK.js +373 -0
  40. package/dist/executor-BlUhFL7_.js +721 -0
  41. package/dist/experimental-CIXf7Uye.js +46 -0
  42. package/dist/history-ClE4toxe.d.ts +32 -0
  43. package/dist/history-CqTuSAdI.js +441 -0
  44. package/dist/instrumentation.d.ts +3 -3
  45. package/dist/instrumentation.js +130 -176
  46. package/dist/job-queue-DLMqIK74.js +63 -0
  47. package/dist/logging-BMJzdDlP.js +1210 -0
  48. package/dist/model-profile-CZmVoGdX.js +49 -0
  49. package/dist/nitro.d.ts +31 -36
  50. package/dist/nitro.js +275 -456
  51. package/dist/oauth-callback-server-WwG5_Zgm.js +130 -0
  52. package/dist/oauth-relay-CdCnu80W.js +62 -0
  53. package/dist/package-discovery-7a9YqLhE.js +455 -0
  54. package/dist/pending-auth-CUbXq06G.js +185 -0
  55. package/dist/plugin-module-BKGOXca2.js +81 -0
  56. package/dist/plugins-BI9A1vKA.d.ts +95 -0
  57. package/dist/plugins-egKWjgue.js +99 -0
  58. package/dist/private-trace-result-BLvBjy_e.js +16 -0
  59. package/dist/profile-T0tXE4zu.js +861 -0
  60. package/dist/registry-BA0__8ai.js +1419 -0
  61. package/dist/reporting-schema-DosTN__Q.js +105 -0
  62. package/dist/resolve-bvD1ORdv.js +546 -0
  63. package/dist/rolldown-runtime-B4FMCO8f.js +28 -0
  64. package/dist/runner-BXYxfIUL.js +392 -0
  65. package/dist/sandbox-egress-signals-ngEPjSEW.js +46 -0
  66. package/dist/schema-Rn8-XEaN.js +1140 -0
  67. package/dist/sentry-CD3SdJl-.js +26 -0
  68. package/dist/skills-DJOlYdBs.js +316 -0
  69. package/dist/spawn-h0R1bTEo.js +29 -0
  70. package/dist/stats-3YZn-Swi.js +2648 -0
  71. package/dist/store-C5qxF2ac.d.ts +208 -0
  72. package/dist/task-queue-CoXwd2eq.js +136 -0
  73. package/dist/task-runner-B2_mJZj0.js +639 -0
  74. package/dist/thread-state-CqZ1m-es.js +431 -0
  75. package/dist/turn-execution-fI6PZ0iI.js +47 -0
  76. package/dist/turn-lifecycle-CcnwrOcp.js +54 -0
  77. package/dist/usage-B5SfMb3H.js +296 -0
  78. package/dist/usage-schema-CKaDkH_j.js +20 -0
  79. package/dist/validation-DfWcvhuS.js +40 -0
  80. package/dist/vercel-queue-DIkVcfK4.js +167 -0
  81. package/dist/vercel.d.ts +6 -6
  82. package/dist/vercel.js +14 -6
  83. package/dist/version-CnXZ614E.d.ts +5 -0
  84. package/dist/version-oD-oPrbO.js +8 -0
  85. package/dist/version.d.ts +2 -4
  86. package/dist/version.js +2 -6
  87. package/dist/web-authorization-Crbzlmzo.js +76 -0
  88. package/dist/web-input-BOuq3oKK.js +494 -0
  89. package/dist/work-B91LQKHr.js +509 -0
  90. package/dist/worker-BcRRTe6k.js +625 -0
  91. package/package.json +9 -9
  92. package/dist/agent-hooks-GB2VPTNA.js +0 -51
  93. package/dist/catalog-runtime-UBLIWD3O.js +0 -14
  94. package/dist/chunk-2LYHWMR4.js +0 -46
  95. package/dist/chunk-352OWAZH.js +0 -320
  96. package/dist/chunk-3Y47VMHV.js +0 -6
  97. package/dist/chunk-3YJSKOWF.js +0 -164
  98. package/dist/chunk-4KSSKTQ5.js +0 -229
  99. package/dist/chunk-4UO6FK4G.js +0 -64
  100. package/dist/chunk-5AHX53NQ.js +0 -717
  101. package/dist/chunk-5J3E5FWA.js +0 -700
  102. package/dist/chunk-5PDAG6O3.js +0 -206
  103. package/dist/chunk-6Y5B5PEX.js +0 -80
  104. package/dist/chunk-7GWQ5S5R.js +0 -2086
  105. package/dist/chunk-7H2VZTWN.js +0 -103
  106. package/dist/chunk-7NL7T6VU.js +0 -406
  107. package/dist/chunk-A5L27LE4.js +0 -387
  108. package/dist/chunk-ADIAWL34.js +0 -81
  109. package/dist/chunk-ASTEMBKJ.js +0 -519
  110. package/dist/chunk-CEMMLV5L.js +0 -98
  111. package/dist/chunk-CM5HNV2W.js +0 -131
  112. package/dist/chunk-CRTRBBRI.js +0 -105
  113. package/dist/chunk-DA2KGZZI.js +0 -13
  114. package/dist/chunk-DIB4GX3G.js +0 -8
  115. package/dist/chunk-DKIJ2RP5.js +0 -68
  116. package/dist/chunk-DWPN6SCH.js +0 -172
  117. package/dist/chunk-EDKUFGPL.js +0 -64
  118. package/dist/chunk-ENY6SKIU.js +0 -1228
  119. package/dist/chunk-F4MGCZOX.js +0 -2943
  120. package/dist/chunk-FA6POGLH.js +0 -70
  121. package/dist/chunk-FSUR7GTG.js +0 -20475
  122. package/dist/chunk-GKEOHJL5.js +0 -1856
  123. package/dist/chunk-GMCB6W5Y.js +0 -333
  124. package/dist/chunk-IE2VPG7O.js +0 -1135
  125. package/dist/chunk-IZ5B5IHQ.js +0 -3656
  126. package/dist/chunk-JAL3CH4G.js +0 -27
  127. package/dist/chunk-KIIEUXD3.js +0 -1764
  128. package/dist/chunk-KXU4NIL7.js +0 -692
  129. package/dist/chunk-MTM5IFCY.js +0 -1190
  130. package/dist/chunk-N7TMSOZH.js +0 -235
  131. package/dist/chunk-NCEBK6PH.js +0 -36
  132. package/dist/chunk-NHJU2ZAL.js +0 -56
  133. package/dist/chunk-P6KTRNVC.js +0 -321
  134. package/dist/chunk-PDO5BLNM.js +0 -22
  135. package/dist/chunk-PDRNLLFT.js +0 -3295
  136. package/dist/chunk-PEQXYSSE.js +0 -45
  137. package/dist/chunk-PKEX2AQX.js +0 -198
  138. package/dist/chunk-PSJCGIGO.js +0 -1163
  139. package/dist/chunk-PZUSUL55.js +0 -506
  140. package/dist/chunk-R45M4TUS.js +0 -37
  141. package/dist/chunk-RC745GGZ.js +0 -122
  142. package/dist/chunk-SP3QKZXJ.js +0 -820
  143. package/dist/chunk-TXKUKMVO.js +0 -417
  144. package/dist/chunk-UE4GPWSD.js +0 -931
  145. package/dist/chunk-UIE3R5XU.js +0 -17
  146. package/dist/chunk-UXPG6ZIN.js +0 -84
  147. package/dist/chunk-VFUK3X5B.js +0 -50
  148. package/dist/chunk-VNMJWREK.js +0 -787
  149. package/dist/chunk-VZ7CSOX2.js +0 -706
  150. package/dist/chunk-WCNQJKFT.js +0 -10
  151. package/dist/chunk-WDZR3QQM.js +0 -135
  152. package/dist/chunk-WLYVJCHV.js +0 -1433
  153. package/dist/chunk-WS7NAFTM.js +0 -1520
  154. package/dist/chunk-X6GDDWQH.js +0 -60
  155. package/dist/chunk-XPDEYNQI.js +0 -102
  156. package/dist/chunk-XRW44VGM.js +0 -58
  157. package/dist/chunk-Y2CM7HXH.js +0 -111
  158. package/dist/chunk-Y7X25LFY.js +0 -15
  159. package/dist/conversation-work-VIOQ5ZF3.js +0 -54
  160. package/dist/db-NGDJV7YH.js +0 -26
  161. package/dist/discovery-DWVDM7UK.js +0 -44
  162. package/dist/experimental-P5FZM4CU.js +0 -12
  163. package/dist/oauth-callback-server-YFY7YEGK.js +0 -243
  164. package/dist/oauth-relay-5XPVRPYB.js +0 -8
  165. package/dist/plugins-YTYJMMJF.js +0 -14
  166. package/dist/runner-ORTNSB2Q.js +0 -522
  167. package/dist/sandbox-egress-signals-FIL7EGPR.js +0 -73
  168. package/dist/sentry-MB3NL3IR.js +0 -42
  169. package/dist/skills-H376WQOH.js +0 -27
  170. package/dist/spawn-T43WHLOS.js +0 -42
  171. package/dist/task-runner-LBZWF32V.js +0 -36
  172. package/dist/validation-REJLRKI6.js +0 -17
  173. package/dist/work-3KJ3RE76.js +0 -51
  174. package/dist/worker-QFEBU72E.js +0 -24
@@ -0,0 +1,1210 @@
1
+ import { d as setTag, f as setUser, h as startSpan, i as getActiveSpan, l as logger, n as captureMessage, p as spanToJSON, s as getTraceData, t as captureException, v as withScope } from "./sentry-CD3SdJl-.js";
2
+ import { t as JUNIOR_VERSION } from "./version-oD-oPrbO.js";
3
+ import path from "node:path";
4
+ import { styleText } from "node:util";
5
+ import { ConfigError, configureSync, getConfig, getLogger } from "@logtape/logtape";
6
+ import { AsyncLocalStorage } from "node:async_hooks";
7
+ //#region src/chat/coerce.ts
8
+ /** Narrow an unknown value to a non-empty string, or undefined. */
9
+ function toOptionalString(value) {
10
+ return typeof value === "string" && value.trim() ? value : void 0;
11
+ }
12
+ /** Narrow an unknown value to a finite number, or undefined. */
13
+ function toOptionalNumber(value) {
14
+ return typeof value === "number" && Number.isFinite(value) ? value : void 0;
15
+ }
16
+ /** Type-guard: true when value is a non-null object (usable as Record). */
17
+ function isRecord(value) {
18
+ return typeof value === "object" && value !== null;
19
+ }
20
+ //#endregion
21
+ //#region src/chat/log-context.ts
22
+ /** Async attribute domain consumed directly by LogTape. */
23
+ const logContextStorage = new AsyncLocalStorage();
24
+ /** Typed context domain retained for consumers such as native Sentry scope fields. */
25
+ const typedLogContextStorage = new AsyncLocalStorage();
26
+ function definedLogContext(context) {
27
+ return Object.fromEntries(Object.entries(context).filter(([, value]) => value !== void 0));
28
+ }
29
+ function definedAttributes(attributes) {
30
+ return Object.fromEntries(Object.entries(attributes).filter((entry) => entry[1] !== void 0));
31
+ }
32
+ /** Convert provider-neutral domain context to stable telemetry attributes. */
33
+ function logContextToAttributes(context) {
34
+ return definedAttributes({
35
+ "gen_ai.conversation.id": context.conversationId,
36
+ "app.platform": context.platform,
37
+ "app.request.id": context.requestId,
38
+ "messaging.system": context.platform === "slack" ? "slack" : context.platform,
39
+ "messaging.message.conversation_id": context.messageConversationId,
40
+ "messaging.destination.name": context.destinationName,
41
+ "enduser.id": context.userId,
42
+ "enduser.pseudo.id": context.userName,
43
+ "app.run.id": context.runId,
44
+ "app.actor.type": context.actorType,
45
+ "app.actor.id": context.actorId,
46
+ "gen_ai.agent.name": context.assistantUserName,
47
+ "gen_ai.request.model": context.modelId,
48
+ "app.skill.name": context.skillName,
49
+ "http.request.method": context.httpMethod,
50
+ "url.path": context.httpPath,
51
+ "url.full": context.urlFull,
52
+ "user_agent.original": context.userAgent
53
+ });
54
+ }
55
+ /** Run an operation with merged context, restoring its parent on completion. */
56
+ function runWithLogContext(context, attributes, callback) {
57
+ return typedLogContextStorage.run({
58
+ ...typedLogContextStorage.getStore(),
59
+ ...definedLogContext(context)
60
+ }, () => logContextStorage.run({
61
+ ...logContextStorage.getStore(),
62
+ ...attributes
63
+ }, callback));
64
+ }
65
+ /** Merge context and attributes into the current scoped operation. */
66
+ function updateLogContext(context, attributes) {
67
+ const currentContext = typedLogContextStorage.getStore();
68
+ if (currentContext) Object.assign(currentContext, definedLogContext(context));
69
+ const currentAttributes = logContextStorage.getStore();
70
+ if (currentAttributes) Object.assign(currentAttributes, attributes);
71
+ }
72
+ /** Read the typed context bound to the current operation. */
73
+ function getBoundLogContext() {
74
+ return typedLogContextStorage.getStore() ?? {};
75
+ }
76
+ /** Read the attributes bound to the current operation. */
77
+ function getBoundLogAttributes() {
78
+ return logContextStorage.getStore() ?? {};
79
+ }
80
+ //#endregion
81
+ //#region src/chat/identities/identity.ts
82
+ /** Canonicalize email addresses for identity lookup and linking. */
83
+ function normalizeIdentityEmail(email) {
84
+ return email?.trim().toLowerCase() || void 0;
85
+ }
86
+ //#endregion
87
+ //#region src/deployment.ts
88
+ const JUNIOR_HEARTBEAT_ROUTE = "/api/internal/heartbeat";
89
+ const JUNIOR_HEARTBEAT_CRON_SCHEDULE = "* * * * *";
90
+ const JUNIOR_RETENTION_ROUTE = "/api/internal/retention";
91
+ const JUNIOR_RETENTION_CRON_SCHEDULE = "0 4 * * *";
92
+ const JUNIOR_CONVERSATION_WORK_CALLBACK_ROUTE = "/api/internal/agent/continue";
93
+ const JUNIOR_PLUGIN_TASK_CALLBACK_ROUTE = "/api/internal/plugin/tasks";
94
+ const JUNIOR_WORKSPACE_SNAPSHOT_JOB_CALLBACK_ROUTE = "/api/internal/workspace/snapshots";
95
+ const LEGACY_JUNIOR_CONVERSATION_WORK_FUNCTION = "api/internal/agent/continue.ts";
96
+ function toOptionalTrimmed(value) {
97
+ const trimmed = value?.trim();
98
+ return trimmed ? trimmed : void 0;
99
+ }
100
+ /** Resolve the deployment version used for release and telemetry correlation. */
101
+ function getDeploymentServiceVersion() {
102
+ const configuredRelease = toOptionalTrimmed(process.env.SENTRY_RELEASE);
103
+ if (configuredRelease) return configuredRelease;
104
+ const deploymentRevision = toOptionalTrimmed(process.env.VERCEL_GIT_COMMIT_SHA);
105
+ return deploymentRevision ? `${JUNIOR_VERSION}+${deploymentRevision}` : void 0;
106
+ }
107
+ /** Resolve deployment-scoped telemetry attributes from host environment. */
108
+ function getDeploymentTelemetryAttributes() {
109
+ const attributes = {};
110
+ const serviceVersion = getDeploymentServiceVersion();
111
+ const deploymentId = toOptionalTrimmed(process.env.VERCEL_DEPLOYMENT_ID);
112
+ attributes["app.junior.version"] = JUNIOR_VERSION;
113
+ if (serviceVersion) attributes["service.version"] = serviceVersion;
114
+ if (deploymentId) attributes["deployment.id"] = deploymentId;
115
+ return attributes;
116
+ }
117
+ //#endregion
118
+ //#region src/chat/logging.ts
119
+ /**
120
+ * Structured logging for Junior runtime events.
121
+ *
122
+ * Application code should call `logInfo`, `logWarn`, `logError`, or
123
+ * `logException` with a stable dot-namespaced event name and only attributes
124
+ * specific to that occurrence:
125
+ *
126
+ * `logWarn("agent.turn.empty_output.exhausted", {
127
+ * "app.ai.empty_output.attempt": 1,
128
+ * })`
129
+ *
130
+ * Event names describe the semantic domain, operation, and outcome. They are
131
+ * lowercase, use dots for namespaces, use snake case within a namespace
132
+ * component, and never contain identifiers or other occurrence-specific data.
133
+ * Use singular domain and operation nouns unless one event represents a real
134
+ * collection. End completed events with a past participle such as `completed`,
135
+ * `failed`, or `skipped`; reserve present participles such as `retrying` for
136
+ * work currently underway, and adjectives such as `busy` for observed states.
137
+ *
138
+ * Correlation context is implicit. Bind authoritative request, conversation,
139
+ * actor, destination, and run context once with `withContext`,
140
+ * `withLogContext`, or `withSpan`; nested logs inherit it through
141
+ * AsyncLocalStorage, and active trace/span IDs are attached during emission.
142
+ * Durable boundaries such as queues and callbacks must still carry and
143
+ * reconstruct their context explicitly before binding it.
144
+ *
145
+ * Internal event calls do not provide a human-readable body. Export adapters
146
+ * derive any required display message from the event name. Free-form messages
147
+ * received from libraries or plugins belong in safe attributes at the adapter
148
+ * boundary.
149
+ */
150
+ const MAX_STRING_VALUE = 1200;
151
+ const EVENT_NAME_PATTERN = /^[a-z][a-z0-9_]*(?:\.[a-z][a-z0-9_]*)+$/;
152
+ const SECRETS_RE = [
153
+ /\b(sk-[A-Za-z0-9_-]{20,})\b/g,
154
+ /\b(xox[baprs]-[A-Za-z0-9-]{10,})\b/g,
155
+ /\bBearer\s+([A-Za-z0-9._\-+=]{20,})\b/gi,
156
+ /\b[A-Z0-9_]+(?:KEY|TOKEN|SECRET|PASSWORD|PASSWD)\s*[=:]\s*([^\s"']{8,})/gi
157
+ ];
158
+ const LEGACY_KEY_MAP = {
159
+ error: "exception.message",
160
+ "error.stack": "exception.stacktrace",
161
+ "gen_ai.system": "gen_ai.provider.name",
162
+ "gen_ai.request.messages": "gen_ai.input.messages",
163
+ "gen_ai.response.text": "gen_ai.output.messages",
164
+ "messaging.conversation.id": "messaging.message.conversation_id",
165
+ bytes: "file.size",
166
+ media_type: "app.file.mime_type",
167
+ skillDir: "file.path",
168
+ root: "file.directory",
169
+ originalLength: "app.output.original_length",
170
+ parsedLength: "app.output.parsed_length",
171
+ directiveMode: "app.output.directive_mode",
172
+ fileCount: "app.output.file_count",
173
+ attempt: "app.retry.attempt",
174
+ steps: "app.ai.steps",
175
+ toolCalls: "app.ai.tool_calls",
176
+ toolResults: "app.ai.tool_results",
177
+ finishReason: "gen_ai.response.finish_reasons",
178
+ sources: "app.ai.sources",
179
+ generatedFiles: "app.ai.generated_files",
180
+ resultFiles: "app.ai.result_files",
181
+ responseMessages: "app.ai.response_messages",
182
+ stepDiagnostics: "app.ai.step_diagnostics",
183
+ inferredSkill: "app.skill.name",
184
+ inferredScore: "app.skill.score"
185
+ };
186
+ /** Normalize runtime finish reasons to the telemetry spelling we emit. */
187
+ function normalizeGenAiFinishReason(reason) {
188
+ return reason === "toolUse" ? "tool_call" : reason;
189
+ }
190
+ /** Truncate message text for log attributes. */
191
+ function summarizeMessageText(text) {
192
+ const normalized = text.trim().replace(/\s+/g, " ");
193
+ if (!normalized) return "[empty]";
194
+ return normalized.length > 1200 ? `${normalized.slice(0, 1200)}...` : normalized;
195
+ }
196
+ function normalizeGenAiFinishReasons(value) {
197
+ if (typeof value === "string" && value.trim()) return [normalizeGenAiFinishReason(value)];
198
+ if (!Array.isArray(value)) return value;
199
+ return value.map((reason) => typeof reason === "string" ? normalizeGenAiFinishReason(reason) : reason);
200
+ }
201
+ const logRecordSinks = /* @__PURE__ */ new Set();
202
+ const deploymentLogAttributes = getDeploymentTelemetryAttributes();
203
+ const LOGTAPE_BODY_KEY = "__logtape_body";
204
+ const ROOT_LOGGER_CATEGORY = ["junior"];
205
+ const CONSOLE_PRIORITY_INDEX = new Map([
206
+ "gen_ai.conversation.id",
207
+ "event.name",
208
+ "app.log.source",
209
+ "exception.message",
210
+ "messaging.message.id",
211
+ "trace_id",
212
+ "span_id",
213
+ "messaging.message.conversation_id",
214
+ "messaging.destination.name",
215
+ "app.run.id",
216
+ "app.message.kind"
217
+ ].map((key, index) => [key, index]));
218
+ const CONSOLE_ALWAYS_HIDDEN_KEYS = /* @__PURE__ */ new Set([
219
+ "gen_ai.agent.name",
220
+ "app.platform",
221
+ "enduser.id",
222
+ "enduser.pseudo.id",
223
+ "http.request.method",
224
+ "messaging.system",
225
+ "url.full",
226
+ "url.path",
227
+ "user_agent.original"
228
+ ]);
229
+ const CONSOLE_DROP_WHEN_COUNTED_KEYS = /* @__PURE__ */ new Set(["app.config.keys"]);
230
+ const CONSOLE_PREVIEW_KEYS = /* @__PURE__ */ new Set([
231
+ "gen_ai.input.messages",
232
+ "gen_ai.output.messages",
233
+ "gen_ai.tool.call.arguments",
234
+ "gen_ai.tool.call.result"
235
+ ]);
236
+ const SENTRY_TAG_ATTRIBUTE_KEYS = /* @__PURE__ */ new Set([
237
+ "app.platform",
238
+ "messaging.system",
239
+ "app.actor.type",
240
+ "gen_ai.agent.name",
241
+ "gen_ai.request.model",
242
+ "app.skill.name",
243
+ "http.request.method",
244
+ "url.path"
245
+ ]);
246
+ function getSentryEnvironment() {
247
+ return (process.env.SENTRY_ENVIRONMENT ?? process.env.VERCEL_ENV ?? process.env.NODE_ENV ?? "").trim().toLowerCase();
248
+ }
249
+ function shouldSuppressInfoLog(level) {
250
+ return getSentryEnvironment() === "production" && level === "info";
251
+ }
252
+ function shouldEmitConsole(level) {
253
+ if (process.env.NODE_ENV === "test") return level === "error";
254
+ return true;
255
+ }
256
+ function isDevelopmentLoggingMode() {
257
+ if (process.env.NODE_ENV !== "development") return false;
258
+ if (process.env.CI) return false;
259
+ return true;
260
+ }
261
+ function shouldUseDevelopmentConsoleFormat() {
262
+ if (!isDevelopmentLoggingMode()) return false;
263
+ return process.env.JUNIOR_LOG_FORMAT?.trim().toLowerCase() !== "structured";
264
+ }
265
+ function shouldUsePrettyConsole(level) {
266
+ if (level === "warn" || level === "error") return false;
267
+ return shouldUseDevelopmentConsoleFormat();
268
+ }
269
+ function shouldUseConsoleColor() {
270
+ if (!shouldUseDevelopmentConsoleFormat()) return false;
271
+ if (process.env.NO_COLOR) return false;
272
+ return process.env.FORCE_COLOR?.trim() === "1" || Boolean(process.stdout?.isTTY) || Boolean(process.stderr?.isTTY);
273
+ }
274
+ function formatConsoleTimestamp(timestamp) {
275
+ if (shouldUseDevelopmentConsoleFormat()) return timestamp.toTimeString().slice(0, 8);
276
+ return timestamp.toISOString();
277
+ }
278
+ function findNextBlankLineBoundary(input, start) {
279
+ const lfBoundary = input.indexOf("\n\n", start);
280
+ const crlfBoundary = input.indexOf("\r\n\r\n", start);
281
+ if (lfBoundary === -1 && crlfBoundary === -1) return null;
282
+ if (lfBoundary === -1) return {
283
+ start: crlfBoundary,
284
+ end: crlfBoundary + 4
285
+ };
286
+ if (crlfBoundary === -1 || lfBoundary < crlfBoundary) return {
287
+ start: lfBoundary,
288
+ end: lfBoundary + 2
289
+ };
290
+ return {
291
+ start: crlfBoundary,
292
+ end: crlfBoundary + 4
293
+ };
294
+ }
295
+ function redactPrivateKeyBlocks(input) {
296
+ const beginPrefix = "-----BEGIN ";
297
+ const footerMarker = "-----";
298
+ let cursor = 0;
299
+ let output = "";
300
+ while (cursor < input.length) {
301
+ const begin = input.indexOf(beginPrefix, cursor);
302
+ if (begin === -1) {
303
+ output += input.slice(cursor);
304
+ break;
305
+ }
306
+ const labelStart = begin + 11;
307
+ const labelEnd = input.indexOf(footerMarker, labelStart);
308
+ if (labelEnd === -1) {
309
+ output += input.slice(cursor);
310
+ break;
311
+ }
312
+ const label = input.slice(labelStart, labelEnd);
313
+ if (!label.endsWith("PRIVATE KEY")) {
314
+ output += input.slice(cursor, labelEnd + 5);
315
+ cursor = labelEnd + 5;
316
+ continue;
317
+ }
318
+ const header = input.slice(begin, labelEnd + 5);
319
+ const footer = `-----END ${label}-----`;
320
+ const footerStart = input.indexOf(footer, labelEnd + 5);
321
+ if (footerStart === -1) {
322
+ const resumeBoundary = findNextBlankLineBoundary(input, labelEnd + 5);
323
+ output += input.slice(cursor, begin);
324
+ output += `${header}\n...redacted...`;
325
+ if (!resumeBoundary) break;
326
+ output += input.slice(resumeBoundary.start, resumeBoundary.end);
327
+ cursor = resumeBoundary.end;
328
+ continue;
329
+ }
330
+ output += input.slice(cursor, begin);
331
+ output += `${header}\n...redacted...\n${footer}`;
332
+ cursor = footerStart + footer.length;
333
+ }
334
+ return output;
335
+ }
336
+ function redactSecrets(input) {
337
+ let out = redactPrivateKeyBlocks(input);
338
+ for (const pattern of SECRETS_RE) out = out.replace(pattern, (full, token) => {
339
+ if (typeof token !== "string") return "***";
340
+ if (token.length < 12) return full.replace(token, "***");
341
+ return full.replace(token, `${token.slice(0, 4)}...${token.slice(-4)}`);
342
+ });
343
+ return out;
344
+ }
345
+ function toSnakeCase(value) {
346
+ return value.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/[^a-zA-Z0-9_]+/g, "_").replace(/^_+|_+$/g, "").toLowerCase();
347
+ }
348
+ function normalizeEventName(value) {
349
+ const segments = value.trim().split(".").map(toSnakeCase).filter(Boolean);
350
+ const normalized = segments.length === 0 ? "log.record.emitted" : segments.length === 1 ? `app.${segments[0]}` : segments.join(".");
351
+ if (process.env.NODE_ENV !== "production" && (!EVENT_NAME_PATTERN.test(value) || value !== normalized)) throw new Error(`Invalid log event name "${value}"; use lowercase dot-delimited namespaces`);
352
+ return normalized;
353
+ }
354
+ function isSemanticKey(key) {
355
+ return /^[a-z][a-z0-9_]*(\.[a-z0-9_][a-z0-9_-]*)+$/.test(key);
356
+ }
357
+ function normalizeAttributeKey(key) {
358
+ const mapped = LEGACY_KEY_MAP[key];
359
+ if (mapped) return mapped;
360
+ if (key === "trace_id" || key === "span_id" || key === "trace_flags") return key;
361
+ if (isSemanticKey(key)) return key;
362
+ if (key === "platform") return "app.platform";
363
+ if (key === "request.id") return "app.request.id";
364
+ const snake = toSnakeCase(key);
365
+ if (!snake) return "app.attribute";
366
+ return `app.${snake}`;
367
+ }
368
+ function sanitizePrimitive(value) {
369
+ if (value === null || value === void 0) return void 0;
370
+ if (typeof value === "string") {
371
+ const trimmed = value.trim();
372
+ if (!trimmed) return void 0;
373
+ const redacted = redactSecrets(trimmed);
374
+ return redacted.length > MAX_STRING_VALUE ? `${redacted.slice(0, MAX_STRING_VALUE)}...` : redacted;
375
+ }
376
+ if (typeof value === "number") return Number.isFinite(value) ? value : void 0;
377
+ if (typeof value === "boolean") return value;
378
+ if (value instanceof Error) return redactSecrets(value.message);
379
+ try {
380
+ const json = JSON.stringify(value);
381
+ if (!json) return void 0;
382
+ const redacted = redactSecrets(json);
383
+ return redacted.length > MAX_STRING_VALUE ? `${redacted.slice(0, MAX_STRING_VALUE)}...` : redacted;
384
+ } catch {
385
+ return;
386
+ }
387
+ }
388
+ function sanitizeValue(value) {
389
+ if (Array.isArray(value)) {
390
+ const sanitized = value.filter((entry) => typeof entry === "string").map((entry) => sanitizePrimitive(entry)).filter((entry) => typeof entry === "string");
391
+ return sanitized.length > 0 ? sanitized : void 0;
392
+ }
393
+ return sanitizePrimitive(value);
394
+ }
395
+ function contextToAttributes(context) {
396
+ return mergeAttributes(logContextToAttributes(context));
397
+ }
398
+ function getTraceCorrelationAttributes() {
399
+ try {
400
+ const span = getActiveSpan();
401
+ if (!span) return {};
402
+ const json = spanToJSON(span);
403
+ const attrs = {};
404
+ if (json.trace_id) attrs.trace_id = json.trace_id;
405
+ if (json.span_id) attrs.span_id = json.span_id;
406
+ return attrs;
407
+ } catch {
408
+ return {};
409
+ }
410
+ }
411
+ function mergeAttributes(...maps) {
412
+ const merged = {};
413
+ for (const map of maps) {
414
+ if (!map) continue;
415
+ for (const [rawKey, rawValue] of Object.entries(map)) {
416
+ const key = normalizeAttributeKey(rawKey);
417
+ const value = sanitizeValue(key === "gen_ai.response.finish_reasons" ? normalizeGenAiFinishReasons(rawValue) : rawValue);
418
+ if (value !== void 0) merged[key] = value;
419
+ }
420
+ }
421
+ return merged;
422
+ }
423
+ function fromLogTapeLevel(level) {
424
+ if (level === "warning") return "warn";
425
+ if (level === "fatal") return "error";
426
+ if (level === "trace") return "debug";
427
+ return level;
428
+ }
429
+ function getLogSource(category) {
430
+ if (category.length <= ROOT_LOGGER_CATEGORY.length) return;
431
+ const sourceParts = category.slice(ROOT_LOGGER_CATEGORY.length);
432
+ return sourceParts.length > 0 ? sourceParts.join(".") : void 0;
433
+ }
434
+ function toEmittedLogRecord(record) {
435
+ const properties = { ...record.properties };
436
+ const rawBody = properties[LOGTAPE_BODY_KEY];
437
+ delete properties[LOGTAPE_BODY_KEY];
438
+ const attributes = mergeAttributes(properties);
439
+ const source = getLogSource(record.category);
440
+ if (source && attributes["app.log.source"] === void 0) attributes["app.log.source"] = source;
441
+ const body = toOptionalString(rawBody) ?? record.message.map((segment) => typeof segment === "string" ? segment : String(segment ?? "")).join("");
442
+ const eventName = toOptionalString(attributes["event.name"]) ?? "log.record.emitted";
443
+ return {
444
+ level: fromLogTapeLevel(record.level),
445
+ eventName,
446
+ body,
447
+ attributes
448
+ };
449
+ }
450
+ function createConsoleSink() {
451
+ return (record) => {
452
+ const emitted = toEmittedLogRecord(record);
453
+ emitConsole(emitted.level, emitted.eventName, emitted.body, emitted.attributes);
454
+ };
455
+ }
456
+ function createSentrySink() {
457
+ return (record) => {
458
+ const emitted = toEmittedLogRecord(record);
459
+ emitSentry(emitted.level, emitted.body, emitted.attributes);
460
+ };
461
+ }
462
+ function createRecordSink() {
463
+ return (record) => {
464
+ const emitted = toEmittedLogRecord(record);
465
+ for (const sink of logRecordSinks) try {
466
+ sink(emitted);
467
+ } catch {}
468
+ };
469
+ }
470
+ let rootLogger;
471
+ let ownsLogTapeBackend = false;
472
+ let usesDirectEmissionFallback = false;
473
+ function ensureLoggerBackend() {
474
+ if (rootLogger || usesDirectEmissionFallback) return;
475
+ if (getConfig() !== null) {
476
+ usesDirectEmissionFallback = true;
477
+ return;
478
+ }
479
+ try {
480
+ configureSync({
481
+ sinks: {
482
+ console: createConsoleSink(),
483
+ sentry: createSentrySink(),
484
+ records: createRecordSink()
485
+ },
486
+ loggers: [{
487
+ category: [...ROOT_LOGGER_CATEGORY],
488
+ sinks: [
489
+ "console",
490
+ "sentry",
491
+ "records"
492
+ ],
493
+ lowestLevel: "debug"
494
+ }, {
495
+ category: ["logtape"],
496
+ sinks: ["console"],
497
+ lowestLevel: "error"
498
+ }],
499
+ contextLocalStorage: logContextStorage
500
+ });
501
+ ownsLogTapeBackend = true;
502
+ rootLogger = getLogger([...ROOT_LOGGER_CATEGORY]);
503
+ } catch (error) {
504
+ if (error instanceof ConfigError && getConfig() !== null) {
505
+ usesDirectEmissionFallback = true;
506
+ return;
507
+ }
508
+ throw error;
509
+ }
510
+ }
511
+ function getLogTapeLogger(category = []) {
512
+ ensureLoggerBackend();
513
+ if (!rootLogger) throw new Error("LogTape backend is unavailable");
514
+ let logger = rootLogger;
515
+ for (const part of category) logger = logger.getChild(part);
516
+ return logger;
517
+ }
518
+ function emitSentry(level, body, attributes) {
519
+ if (shouldSuppressInfoLog(level)) return;
520
+ const loggerFn = logger?.[level];
521
+ if (typeof loggerFn === "function") {
522
+ loggerFn(body, attributes);
523
+ return;
524
+ }
525
+ const sentryLevel = level === "warn" ? "warning" : level;
526
+ withScope((scope) => {
527
+ for (const [key, value] of Object.entries(attributes)) scope.setExtra(key, value);
528
+ captureMessage(body, sentryLevel);
529
+ });
530
+ }
531
+ function formatConsoleLevel(level) {
532
+ if (level === "debug") return "DBG";
533
+ if (level === "info") return "INF";
534
+ if (level === "warn") return "WRN";
535
+ return "ERR";
536
+ }
537
+ function consoleLevelStyle(level) {
538
+ if (level === "error") return "red";
539
+ if (level === "warn") return "yellow";
540
+ if (level === "info") return "green";
541
+ return "blue";
542
+ }
543
+ function quoteConsoleValue(value) {
544
+ return `"${value.replace(/\\/g, "\\\\").replace(/"/g, "\\\"")}"`;
545
+ }
546
+ function formatConsoleValue(value) {
547
+ if (typeof value === "number" || typeof value === "boolean") return String(value);
548
+ if (Array.isArray(value)) return quoteConsoleValue(JSON.stringify(value));
549
+ if (/^[A-Za-z0-9._:/@+-]+$/.test(value)) return value;
550
+ return quoteConsoleValue(value);
551
+ }
552
+ function shouldShowConsoleDestinationName(eventName) {
553
+ return /^(app_home|oauth|queue|slash_command|slack|webhook)\./.test(eventName);
554
+ }
555
+ function shouldShowConsoleModel(level, eventName) {
556
+ if (level === "warn" || level === "error") return true;
557
+ return eventName.startsWith("ai.") || eventName.startsWith("assistant.") || eventName === "agent.turn.started" || eventName === "agent.turn.completed" || eventName === "agent.turn.provider_error";
558
+ }
559
+ function shouldHideConsoleAttribute(level, eventName, key, attributes) {
560
+ if (CONSOLE_ALWAYS_HIDDEN_KEYS.has(key)) return true;
561
+ if (CONSOLE_DROP_WHEN_COUNTED_KEYS.has(key)) return true;
562
+ if (key === "messaging.message.conversation_id" && attributes[key] === attributes["gen_ai.conversation.id"]) return true;
563
+ if (key === "app.message.id" && attributes[key] === attributes["messaging.message.id"]) return true;
564
+ if (key === "messaging.destination.name" && !shouldShowConsoleDestinationName(eventName)) return true;
565
+ if (key === "gen_ai.request.model" && !shouldShowConsoleModel(level, eventName)) return true;
566
+ if (key === "gen_ai.provider.name" && eventName.startsWith("agent.tool_call.") && level !== "warn" && level !== "error") return true;
567
+ if (key === "gen_ai.operation.name" && eventName.startsWith("agent.tool_call.")) return true;
568
+ return false;
569
+ }
570
+ function summarizeConsoleString(value, maxChars) {
571
+ const collapsed = value.replace(/\s+/g, " ").trim();
572
+ if (collapsed.length <= maxChars) return collapsed;
573
+ return `${collapsed.slice(0, maxChars)}... [${collapsed.length} chars]`;
574
+ }
575
+ function abbreviateConsoleId(value) {
576
+ if (value.length <= 20) return value;
577
+ return `${value.slice(0, 12)}...${value.slice(-4)}`;
578
+ }
579
+ function toRelativeConsolePath(value) {
580
+ const normalized = value.trim();
581
+ if (!normalized) return normalized;
582
+ try {
583
+ const relative = path.relative(process.cwd(), normalized);
584
+ if (relative.length > 0 && !relative.startsWith("..") && !path.isAbsolute(relative)) return relative;
585
+ } catch {}
586
+ return normalized;
587
+ }
588
+ function pushPrettyConsoleToken(tokens, token) {
589
+ if (!token || tokens.includes(token)) return;
590
+ tokens.push(token);
591
+ }
592
+ function numericConsoleToken(label, value) {
593
+ return typeof value === "number" ? `${label}=${value}` : void 0;
594
+ }
595
+ function stringConsoleToken(label, value) {
596
+ const normalized = toOptionalString(value);
597
+ return normalized ? `${label}=${normalized}` : void 0;
598
+ }
599
+ function booleanConsoleToken(label, value) {
600
+ return typeof value === "boolean" ? `${label}=${value ? "yes" : "no"}` : void 0;
601
+ }
602
+ function shouldShowPrettyCorrelation(eventName) {
603
+ return !(eventName === "plugin.loaded" || eventName === "startup.discovery.completed" || eventName.endsWith(".loaded"));
604
+ }
605
+ function getPrettyConsoleSummaryTokens(level, eventName, attributes) {
606
+ const tokens = [];
607
+ pushPrettyConsoleToken(tokens, toOptionalString(attributes["app.log.source"]) ?? void 0);
608
+ pushPrettyConsoleToken(tokens, eventName.startsWith("plugin.heartbeat.") ? stringConsoleToken("plugin", attributes["app.plugin.name"]) : toOptionalString(attributes["app.plugin.name"]) ?? void 0);
609
+ pushPrettyConsoleToken(tokens, numericConsoleToken("config", attributes["app.plugin.config_key_count"]));
610
+ pushPrettyConsoleToken(tokens, booleanConsoleToken("mcp", attributes["app.plugin.has_mcp"]));
611
+ pushPrettyConsoleToken(tokens, numericConsoleToken("plugins", attributes["app.plugin.count"]));
612
+ pushPrettyConsoleToken(tokens, numericConsoleToken("dispatches", attributes["app.dispatch.count"]));
613
+ pushPrettyConsoleToken(tokens, numericConsoleToken("skills", attributes["app.skill.count"]));
614
+ pushPrettyConsoleToken(tokens, numericConsoleToken("config", attributes["app.config.key_count"]));
615
+ pushPrettyConsoleToken(tokens, numericConsoleToken("chars", attributes["app.message.length"]));
616
+ pushPrettyConsoleToken(tokens, numericConsoleToken("attachments", attributes["app.message.attachment_count"]));
617
+ const rawAttachmentCount = toOptionalNumber(attributes["app.message.attachment_count"]);
618
+ const promptAttachmentCount = toOptionalNumber(attributes["app.message.prompt_attachment_count"]);
619
+ if (promptAttachmentCount !== void 0 && promptAttachmentCount !== rawAttachmentCount) pushPrettyConsoleToken(tokens, numericConsoleToken("prompt_attachments", promptAttachmentCount));
620
+ const filePath = toOptionalString(attributes["file.path"]);
621
+ if (filePath && eventName.endsWith(".loaded")) pushPrettyConsoleToken(tokens, toRelativeConsolePath(filePath));
622
+ if (shouldShowPrettyCorrelation(eventName)) {
623
+ const conversationId = toOptionalString(attributes["gen_ai.conversation.id"]);
624
+ const messageId = toOptionalString(attributes["messaging.message.id"]);
625
+ if (conversationId) pushPrettyConsoleToken(tokens, `conv=${abbreviateConsoleId(conversationId)}`);
626
+ if (messageId) pushPrettyConsoleToken(tokens, `msg=${abbreviateConsoleId(messageId)}`);
627
+ }
628
+ const model = toOptionalString(attributes["gen_ai.request.model"]);
629
+ if (model && shouldShowConsoleModel(level, eventName)) pushPrettyConsoleToken(tokens, `model=${model}`);
630
+ return tokens;
631
+ }
632
+ function projectConsoleValue(level, key, value) {
633
+ if ((level === "debug" || level === "info") && CONSOLE_PREVIEW_KEYS.has(key) && typeof value === "string") return summarizeConsoleString(value, key === "gen_ai.tool.call.result" ? 220 : 140);
634
+ return value;
635
+ }
636
+ function projectConsoleAttributes(level, eventName, attributes) {
637
+ const projected = {};
638
+ for (const [key, value] of Object.entries(attributes)) {
639
+ if (shouldHideConsoleAttribute(level, eventName, key, attributes)) continue;
640
+ const nextValue = projectConsoleValue(level, key, value);
641
+ if (nextValue !== void 0) projected[key] = nextValue;
642
+ }
643
+ return projected;
644
+ }
645
+ function formatConsoleLine(level, eventName, body, attributes) {
646
+ const timestamp = /* @__PURE__ */ new Date();
647
+ const useColor = shouldUseConsoleColor();
648
+ const levelStyle = consoleLevelStyle(level);
649
+ const colorize = (text, style) => useColor ? styleText(style, text) : text;
650
+ if (shouldUsePrettyConsole(level)) {
651
+ const summary = [body, ...getPrettyConsoleSummaryTokens(level, eventName, attributes)].join(" ");
652
+ return [
653
+ colorize(formatConsoleTimestamp(timestamp), "gray"),
654
+ colorize(formatConsoleLevel(level), levelStyle),
655
+ summary
656
+ ].join(" ");
657
+ }
658
+ const parts = [`${colorize(formatConsoleTimestamp(timestamp), "gray")} ${colorize(formatConsoleLevel(level), levelStyle)} ${body}`];
659
+ const projectedAttributes = projectConsoleAttributes(level, eventName, attributes);
660
+ const sortedAttributes = Object.entries(projectedAttributes).sort(([left], [right]) => {
661
+ const leftRank = CONSOLE_PRIORITY_INDEX.get(left);
662
+ const rightRank = CONSOLE_PRIORITY_INDEX.get(right);
663
+ if (leftRank !== void 0 || rightRank !== void 0) {
664
+ if (leftRank === void 0) return 1;
665
+ if (rightRank === void 0) return -1;
666
+ return leftRank - rightRank;
667
+ }
668
+ return left.localeCompare(right);
669
+ });
670
+ for (const [key, value] of sortedAttributes) {
671
+ const rendered = `${colorize(key, "cyan")}=${colorize(formatConsoleValue(value), "dim")}`;
672
+ parts.push(rendered);
673
+ }
674
+ return parts.join(" ");
675
+ }
676
+ function emitConsole(level, eventName, body, attributes) {
677
+ if (!shouldEmitConsole(level)) return;
678
+ const line = formatConsoleLine(level, eventName, body, attributes);
679
+ if (level === "error") {
680
+ console.error(line);
681
+ return;
682
+ }
683
+ if (level === "warn") {
684
+ console.warn(line);
685
+ return;
686
+ }
687
+ if (level === "info") {
688
+ console.info(line);
689
+ return;
690
+ }
691
+ console.debug(line);
692
+ }
693
+ function emitDirect(level, eventName, body, attributes) {
694
+ for (const sink of logRecordSinks) try {
695
+ sink({
696
+ level,
697
+ eventName,
698
+ body,
699
+ attributes
700
+ });
701
+ } catch {}
702
+ emitConsole(level, eventName, body, attributes);
703
+ emitSentry(level, body, attributes);
704
+ }
705
+ function emitRecord(category, level, eventName, attrs = {}, body) {
706
+ ensureLoggerBackend();
707
+ const traceAttributes = getTraceCorrelationAttributes();
708
+ const normalizedEventName = normalizeEventName(eventName);
709
+ const message = body ? redactSecrets(body) : normalizedEventName;
710
+ const source = getLogSource([...ROOT_LOGGER_CATEGORY, ...category]);
711
+ const attributes = mergeAttributes(ownsLogTapeBackend ? void 0 : getBoundLogAttributes(), traceAttributes, {
712
+ "event.name": normalizedEventName,
713
+ ...source ? { "app.log.source": source } : void 0,
714
+ ...attrs
715
+ }, deploymentLogAttributes);
716
+ if (usesDirectEmissionFallback) {
717
+ emitDirect(level, normalizedEventName, message, attributes);
718
+ return;
719
+ }
720
+ const logger = getLogTapeLogger(category);
721
+ const properties = {
722
+ [LOGTAPE_BODY_KEY]: message,
723
+ ...attributes
724
+ };
725
+ if (level === "error") {
726
+ logger.error(`{${LOGTAPE_BODY_KEY}}`, properties);
727
+ return;
728
+ }
729
+ if (level === "warn") {
730
+ logger.warn(`{${LOGTAPE_BODY_KEY}}`, properties);
731
+ return;
732
+ }
733
+ if (level === "info") {
734
+ logger.info(`{${LOGTAPE_BODY_KEY}}`, properties);
735
+ return;
736
+ }
737
+ logger.debug(`{${LOGTAPE_BODY_KEY}}`, properties);
738
+ }
739
+ function emit(level, eventName, attrs = {}, body) {
740
+ emitRecord([], level, eventName, attrs, body);
741
+ }
742
+ /**
743
+ * Low-level adapter logger.
744
+ *
745
+ * Application runtime code should use the severity helpers below. This surface
746
+ * exists for adapters that must preserve an external free-form body.
747
+ */
748
+ const log = {
749
+ debug(eventName, attrs = {}, body) {
750
+ emit("debug", eventName, attrs, body);
751
+ },
752
+ info(eventName, attrs = {}, body) {
753
+ emit("info", eventName, attrs, body);
754
+ },
755
+ warn(eventName, attrs = {}, body) {
756
+ emit("warn", eventName, attrs, body);
757
+ },
758
+ error(eventName, attrs = {}, body) {
759
+ emit("error", eventName, attrs, body);
760
+ },
761
+ exception(eventName, error, attrs = {}, body) {
762
+ const normalizedError = error instanceof Error ? error : new Error(String(error));
763
+ emit("error", eventName, {
764
+ ...attrs,
765
+ "error.type": normalizedError.name,
766
+ "exception.type": normalizedError.name,
767
+ "exception.message": normalizedError.message,
768
+ "exception.stacktrace": normalizedError.stack
769
+ }, body);
770
+ let eventId;
771
+ withScope((scope) => {
772
+ setSentryScopeContext(scope, getBoundLogContext());
773
+ const mergedAttributes = mergeAttributes(getBoundLogAttributes(), attrs);
774
+ for (const [key, value] of Object.entries(mergedAttributes)) {
775
+ scope.setExtra(key, value);
776
+ if (SENTRY_TAG_ATTRIBUTE_KEYS.has(key) && typeof value === "string" && value.length > 0) scope.setTag(key, value);
777
+ }
778
+ const capturedEventId = captureException(normalizedError);
779
+ eventId = typeof capturedEventId === "string" ? capturedEventId : void 0;
780
+ });
781
+ return eventId;
782
+ }
783
+ };
784
+ const CHAT_SDK_LEVEL_PRIORITY = {
785
+ debug: 10,
786
+ info: 20,
787
+ warn: 30,
788
+ error: 40
789
+ };
790
+ function resolveChatSdkLogLevel() {
791
+ if (isDevelopmentLoggingMode()) return "warn";
792
+ return "info";
793
+ }
794
+ function shouldEmitChatSdkLevel(level, minimumLevel) {
795
+ if (minimumLevel === "silent") return false;
796
+ return CHAT_SDK_LEVEL_PRIORITY[level] >= CHAT_SDK_LEVEL_PRIORITY[minimumLevel];
797
+ }
798
+ function renderChatSdkArgument(value) {
799
+ if (value === null || value === void 0) return "";
800
+ if (typeof value === "string") return value;
801
+ if (value instanceof Error) return value.message;
802
+ try {
803
+ return JSON.stringify(value);
804
+ } catch {
805
+ return String(value);
806
+ }
807
+ }
808
+ function formatChatSdkBody(message, args) {
809
+ const renderedArgs = args.map((arg) => renderChatSdkArgument(arg).trim()).filter((arg) => arg.length > 0);
810
+ if (renderedArgs.length === 0) return message;
811
+ return `${message} ${renderedArgs.join(" ")}`;
812
+ }
813
+ function createChatSdkLoggerImpl(category, minimumLevel) {
814
+ const emitChatSdkLog = (level, message, args) => {
815
+ if (!shouldEmitChatSdkLevel(level, minimumLevel)) return;
816
+ emitRecord(category, level === "warn" ? "warn" : level, level === "error" ? "chat_sdk.log.error" : level === "warn" ? "chat_sdk.log.warn" : "chat_sdk.log", args.length > 0 ? { "app.log.args": args.length === 1 ? args[0] : args } : {}, formatChatSdkBody(message, args));
817
+ };
818
+ return {
819
+ child(prefix) {
820
+ return createChatSdkLoggerImpl([...category, prefix], minimumLevel);
821
+ },
822
+ debug(message, ...args) {
823
+ emitChatSdkLog("debug", message, args);
824
+ },
825
+ info(message, ...args) {
826
+ emitChatSdkLog("info", message, args);
827
+ },
828
+ warn(message, ...args) {
829
+ emitChatSdkLog("warn", message, args);
830
+ },
831
+ error(message, ...args) {
832
+ emitChatSdkLog("error", message, args);
833
+ }
834
+ };
835
+ }
836
+ /** Create a Chat SDK logger that routes records through Junior's logging backend. */
837
+ function createChatSdkLogger() {
838
+ return createChatSdkLoggerImpl(["chat-sdk"], resolveChatSdkLogLevel());
839
+ }
840
+ /**
841
+ * Run one operation with inherited correlation context.
842
+ *
843
+ * Call this at execution boundaries after reconstructing authoritative
844
+ * context. Nested application logs should not receive the same context again.
845
+ */
846
+ function withLogContext(context, callback) {
847
+ return runWithLogContext(context, contextToAttributes(context), callback);
848
+ }
849
+ function getLogContextAttributes() {
850
+ return getBoundLogAttributes();
851
+ }
852
+ /** Return inherited log context filtered to attributes valid for the span operation. */
853
+ function getLogContextAttributesForSpan(op) {
854
+ const attributes = { ...getLogContextAttributes() };
855
+ if (op === "gen_ai.invoke_agent" || op === "gen_ai.execute_tool") {
856
+ delete attributes["gen_ai.request.model"];
857
+ return attributes;
858
+ }
859
+ if (op === "gen_ai.chat" || op === "gen_ai.embeddings") {
860
+ delete attributes["gen_ai.agent.name"];
861
+ delete attributes["gen_ai.request.model"];
862
+ return attributes;
863
+ }
864
+ delete attributes["gen_ai.agent.name"];
865
+ delete attributes["gen_ai.request.model"];
866
+ return attributes;
867
+ }
868
+ function createLogContextFromRequest(request, context = {}) {
869
+ const url = new URL(request.url);
870
+ return {
871
+ ...context,
872
+ requestId: context.requestId ?? request.headers.get("x-request-id") ?? void 0,
873
+ httpMethod: request.method,
874
+ httpPath: url.pathname,
875
+ urlFull: url.toString(),
876
+ userAgent: request.headers.get("user-agent") ?? void 0
877
+ };
878
+ }
879
+ /** Attach filterable non-user context tags to Sentry. */
880
+ function setSentryTagsFromContext(context) {
881
+ const attrs = contextToAttributes(context);
882
+ for (const [key, value] of Object.entries(attrs)) {
883
+ if (!SENTRY_TAG_ATTRIBUTE_KEYS.has(key)) continue;
884
+ if (typeof value === "string" && value.length > 0) setTag(key, value);
885
+ }
886
+ }
887
+ function sentryUserIdentityFromContext(context) {
888
+ if (context.userId) {
889
+ const email = normalizeIdentityEmail(context.userEmail);
890
+ return {
891
+ id: context.userId,
892
+ ...context.userName ? { username: context.userName } : void 0,
893
+ ...email ? { email } : void 0
894
+ };
895
+ }
896
+ }
897
+ function sentryUserFromIdentity(identity) {
898
+ return {
899
+ id: identity.id,
900
+ ip_address: null,
901
+ ...identity.username ? { username: identity.username } : void 0,
902
+ ...identity.email ? { email: identity.email } : void 0
903
+ };
904
+ }
905
+ /** Bind actor identity to Sentry's native user fields. */
906
+ function setSentryUser(identity) {
907
+ if (!identity) return;
908
+ setUser(sentryUserFromIdentity(identity));
909
+ }
910
+ /** Attach scoped Sentry context for isolated exception capture. */
911
+ function setSentryScopeContext(scope, context) {
912
+ const attrs = contextToAttributes(context);
913
+ for (const [key, value] of Object.entries(attrs)) {
914
+ if (!SENTRY_TAG_ATTRIBUTE_KEYS.has(key)) continue;
915
+ if (typeof value === "string" && value.length > 0) scope.setTag(key, value);
916
+ }
917
+ const identity = sentryUserIdentityFromContext(context);
918
+ if (identity) scope.setUser(sentryUserFromIdentity(identity));
919
+ scope.setContext("app", attrs);
920
+ }
921
+ function toSpanAttributeValue(value) {
922
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") return value;
923
+ if (!Array.isArray(value)) return;
924
+ const sanitized = value.filter((entry) => typeof entry === "string");
925
+ return sanitized.length > 0 ? sanitized : void 0;
926
+ }
927
+ function normalizeSpanAttributes(attributes) {
928
+ const normalized = {};
929
+ for (const [rawKey, value] of Object.entries(attributes)) {
930
+ const key = normalizeAttributeKey(rawKey);
931
+ const normalizedValue = toSpanAttributeValue(key === "gen_ai.response.finish_reasons" ? normalizeGenAiFinishReasons(value) : value);
932
+ if (normalizedValue !== void 0) normalized[key] = normalizedValue;
933
+ }
934
+ return normalized;
935
+ }
936
+ function setAttributesOnSpan(span, attributes) {
937
+ for (const [key, value] of Object.entries(normalizeSpanAttributes(attributes))) span.setAttribute(key, value);
938
+ }
939
+ /**
940
+ * Emit an informational event with occurrence-specific attributes.
941
+ *
942
+ * Bind correlation context at the owning operation boundary instead of
943
+ * passing it here.
944
+ */
945
+ function logInfo(eventName, attributes = {}) {
946
+ log.info(eventName, attributes);
947
+ }
948
+ /**
949
+ * Emit a warning event with occurrence-specific attributes.
950
+ *
951
+ * Bind correlation context at the owning operation boundary instead of
952
+ * passing it here.
953
+ */
954
+ function logWarn(eventName, attributes = {}) {
955
+ log.warn(eventName, attributes);
956
+ }
957
+ /**
958
+ * Emit an error event without capturing an exception.
959
+ *
960
+ * Use `logException` when an actual exception instance owns the failure.
961
+ */
962
+ function logError(eventName, attributes = {}) {
963
+ log.error(eventName, attributes);
964
+ }
965
+ /**
966
+ * Emit an exception event and capture the exception with bound context.
967
+ *
968
+ * Exception event names should end in `.exception` when they describe a
969
+ * generic operation exception. Existing domain failure events may retain a
970
+ * `.failed` outcome when the event also covers non-exception failures.
971
+ */
972
+ function logException(error, eventName, attributes = {}) {
973
+ const normalizedError = error instanceof Error ? error : new Error(String(error));
974
+ return log.exception(eventName, normalizedError, attributes);
975
+ }
976
+ /** Run an optional side effect without changing the successful primary outcome. */
977
+ async function runBestEffort(operation, eventName, attributes = {}) {
978
+ try {
979
+ await operation();
980
+ } catch (error) {
981
+ logException(error, eventName, attributes);
982
+ }
983
+ }
984
+ /** Add context to the current operation and Sentry scope. */
985
+ function setTags(context = {}) {
986
+ updateLogContext(context, contextToAttributes(context));
987
+ setSentryTagsFromContext(context);
988
+ setSentryUser(sentryUserIdentityFromContext(context));
989
+ }
990
+ /** Create a LogContext from an incoming HTTP request. */
991
+ function createRequestContext(request, context = {}) {
992
+ return createLogContextFromRequest(request, context);
993
+ }
994
+ /** Run a callback within a scoped log context. */
995
+ async function withContext(context, callback) {
996
+ return withLogContext(context, callback);
997
+ }
998
+ /** Run a callback within a Sentry span and scoped log context. */
999
+ async function withSpan(name, op, context, callback, attributes = {}) {
1000
+ const normalizedAttributes = normalizeSpanAttributes(attributes);
1001
+ return withLogContext(context, () => {
1002
+ const inheritedAttributes = getLogContextAttributesForSpan(op);
1003
+ return startSpan({
1004
+ name,
1005
+ op,
1006
+ attributes: {
1007
+ ...inheritedAttributes,
1008
+ ...normalizedAttributes
1009
+ }
1010
+ }, async (span) => {
1011
+ try {
1012
+ return await callback((attributes) => setAttributesOnSpan(span, attributes));
1013
+ } catch (error) {
1014
+ setAttributesOnSpan(span, { "error.type": error instanceof Error ? error.name : typeof error });
1015
+ throw error;
1016
+ }
1017
+ });
1018
+ });
1019
+ }
1020
+ /** Return Sentry-standard trace propagation headers for the active span. */
1021
+ function getTracePropagationHeaders() {
1022
+ const traceData = getTraceData({ propagateTraceparent: true });
1023
+ if (!traceData) return {};
1024
+ const headers = {};
1025
+ for (const key of [
1026
+ "sentry-trace",
1027
+ "baggage",
1028
+ "traceparent"
1029
+ ]) {
1030
+ const value = traceData[key];
1031
+ if (typeof value === "string" && value.trim()) headers[key] = value;
1032
+ }
1033
+ return headers;
1034
+ }
1035
+ /** Set attributes on the currently active Sentry span. */
1036
+ function setSpanAttributes(attributes) {
1037
+ const span = getActiveSpan();
1038
+ if (!span) return;
1039
+ setAttributesOnSpan(span, attributes);
1040
+ }
1041
+ /** Set the status of the currently active Sentry span. */
1042
+ function setSpanStatus(status) {
1043
+ const span = getActiveSpan();
1044
+ if (!span) return;
1045
+ span.setStatus(status === "ok" ? { code: 1 } : {
1046
+ code: 2,
1047
+ message: "internal_error"
1048
+ });
1049
+ }
1050
+ /** Return the trace ID from the active Sentry span, if any. */
1051
+ function getActiveTraceId() {
1052
+ try {
1053
+ const span = getActiveSpan();
1054
+ if (!span) return;
1055
+ return toOptionalString(spanToJSON(span).trace_id);
1056
+ } catch {
1057
+ return;
1058
+ }
1059
+ }
1060
+ const TURN_FAILURE_RESPONSE_TEMPLATE = "I ran into an internal error while processing that. Reference: `event_id={eventId}`.";
1061
+ /** Build the static user-facing response for a failed turn. */
1062
+ function buildTurnFailureResponse(eventId) {
1063
+ return TURN_FAILURE_RESPONSE_TEMPLATE.replace("{eventId}", eventId);
1064
+ }
1065
+ const GEN_AI_DEFAULT_MAX_ATTRIBUTE_CHARS = 1e5;
1066
+ const GEN_AI_MAX_ARRAY_ITEMS = 50;
1067
+ const GEN_AI_MAX_OBJECT_KEYS = 50;
1068
+ function truncateGenAiString(value, maxChars) {
1069
+ return value.length > maxChars ? "" : value;
1070
+ }
1071
+ function sanitizeGenAiValue(value, seen, depth, keyName) {
1072
+ if (value === null || value === void 0) return;
1073
+ if (typeof value === "string") {
1074
+ if ((keyName === "data" || keyName === "base64" || keyName?.endsWith("_base64") === true) && value.length > 256) return `[omitted:${value.length}]`;
1075
+ return redactSecrets(value);
1076
+ }
1077
+ if (typeof value === "number") return Number.isFinite(value) ? value : void 0;
1078
+ if (typeof value === "boolean") return value;
1079
+ if (depth >= 8) return "[depth_limit]";
1080
+ if (Array.isArray(value)) return value.slice(0, GEN_AI_MAX_ARRAY_ITEMS).map((entry) => sanitizeGenAiValue(entry, seen, depth + 1)).filter((entry) => entry !== void 0);
1081
+ if (typeof value !== "object") return redactSecrets(String(value));
1082
+ if (seen.has(value)) return "[circular]";
1083
+ seen.add(value);
1084
+ const record = value;
1085
+ const out = {};
1086
+ for (const [key, entryValue] of Object.entries(record).slice(0, GEN_AI_MAX_OBJECT_KEYS)) {
1087
+ const sanitized = sanitizeGenAiValue(entryValue, seen, depth + 1, key);
1088
+ if (sanitized !== void 0) out[key] = sanitized;
1089
+ }
1090
+ return out;
1091
+ }
1092
+ /** Serialize a bounded AI value, omitting it when valid JSON cannot fit. */
1093
+ function serializeGenAiAttribute(value, maxChars = GEN_AI_DEFAULT_MAX_ATTRIBUTE_CHARS) {
1094
+ const sanitized = sanitizeGenAiValue(value, /* @__PURE__ */ new WeakSet(), 0);
1095
+ if (sanitized === void 0) return;
1096
+ const serialized = typeof sanitized === "string" ? sanitized : JSON.stringify(sanitized);
1097
+ if (!serialized) return;
1098
+ return truncateGenAiString(redactSecrets(serialized), maxChars) || void 0;
1099
+ }
1100
+ function asRecord(value) {
1101
+ return value && typeof value === "object" ? value : void 0;
1102
+ }
1103
+ function toFiniteTokenCount(value) {
1104
+ if (typeof value !== "number" || !Number.isFinite(value)) return;
1105
+ const rounded = Math.floor(value);
1106
+ return rounded >= 0 ? rounded : void 0;
1107
+ }
1108
+ function toFiniteCost(value) {
1109
+ return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : void 0;
1110
+ }
1111
+ function addCost(left, right) {
1112
+ return Math.round(((left ?? 0) + right) * 0xe8d4a51000) / 0xe8d4a51000;
1113
+ }
1114
+ function sumTokenCounts(...values) {
1115
+ let total = 0;
1116
+ let hasValue = false;
1117
+ for (const value of values) {
1118
+ if (value === void 0) continue;
1119
+ total += value;
1120
+ hasValue = true;
1121
+ }
1122
+ return hasValue ? total : void 0;
1123
+ }
1124
+ const PI_USAGE_FIELDS = [
1125
+ ["input", "inputTokens"],
1126
+ ["output", "outputTokens"],
1127
+ ["cacheRead", "cachedInputTokens"],
1128
+ ["cacheWrite", "cacheCreationTokens"],
1129
+ ["reasoning", "reasoningTokens"],
1130
+ ["totalTokens", "totalTokens"]
1131
+ ];
1132
+ const PI_COST_FIELDS = [
1133
+ "input",
1134
+ "output",
1135
+ "cacheRead",
1136
+ "cacheWrite",
1137
+ "total"
1138
+ ];
1139
+ function readPiUsage(source) {
1140
+ const record = asRecord(source);
1141
+ if (!record) return {};
1142
+ const usage = asRecord(record.usage) ?? record;
1143
+ const summary = {};
1144
+ for (const [piKey, ourKey] of PI_USAGE_FIELDS) {
1145
+ const value = toFiniteTokenCount(usage[piKey]) ?? toFiniteTokenCount(usage[ourKey]);
1146
+ if (value !== void 0) summary[ourKey] = value;
1147
+ }
1148
+ const piCost = asRecord(usage.cost);
1149
+ if (piCost) {
1150
+ const cost = {};
1151
+ for (const field of PI_COST_FIELDS) {
1152
+ const value = toFiniteCost(piCost[field]);
1153
+ if (value !== void 0) cost[field] = value;
1154
+ }
1155
+ if (Object.keys(cost).length > 0) summary.cost = cost;
1156
+ }
1157
+ return summary;
1158
+ }
1159
+ /**
1160
+ * Sum pi-ai `Usage` counters across every source into an `AgentTurnUsage`.
1161
+ *
1162
+ * Callers pass every assistant message produced during a turn so the result
1163
+ * reflects the aggregate usage for the entire turn rather than a single model
1164
+ * call. Sources without a recognized usage record contribute nothing.
1165
+ */
1166
+ function extractGenAiUsageSummary(...sources) {
1167
+ const summary = {};
1168
+ const cost = {};
1169
+ for (const source of sources) {
1170
+ const single = readPiUsage(source);
1171
+ for (const field of [
1172
+ "inputTokens",
1173
+ "outputTokens",
1174
+ "cachedInputTokens",
1175
+ "cacheCreationTokens",
1176
+ "reasoningTokens",
1177
+ "totalTokens"
1178
+ ]) {
1179
+ const value = single[field];
1180
+ if (value === void 0) continue;
1181
+ summary[field] = (summary[field] ?? 0) + value;
1182
+ }
1183
+ for (const field of PI_COST_FIELDS) {
1184
+ const value = single.cost?.[field];
1185
+ if (value === void 0) continue;
1186
+ cost[field] = addCost(cost[field], value);
1187
+ }
1188
+ }
1189
+ if (Object.keys(cost).length > 0) summary.cost = cost;
1190
+ return summary;
1191
+ }
1192
+ /** Extract GenAI token and estimated USD cost attributes for tracing. */
1193
+ function extractGenAiUsageAttributes(...sources) {
1194
+ const { inputTokens, outputTokens, cachedInputTokens, cacheCreationTokens, reasoningTokens, cost } = extractGenAiUsageSummary(...sources);
1195
+ const semanticInputTokens = sumTokenCounts(inputTokens, cachedInputTokens, cacheCreationTokens);
1196
+ return {
1197
+ ...semanticInputTokens !== void 0 ? { "gen_ai.usage.input_tokens": semanticInputTokens } : void 0,
1198
+ ...outputTokens !== void 0 ? { "gen_ai.usage.output_tokens": outputTokens } : void 0,
1199
+ ...cachedInputTokens !== void 0 ? { "gen_ai.usage.cache_read.input_tokens": cachedInputTokens } : void 0,
1200
+ ...cacheCreationTokens !== void 0 ? { "gen_ai.usage.cache_creation.input_tokens": cacheCreationTokens } : void 0,
1201
+ ...reasoningTokens !== void 0 ? { "gen_ai.usage.reasoning.output_tokens": reasoningTokens } : void 0,
1202
+ ...cost?.input !== void 0 ? { "app.cost.input_usd": cost.input } : void 0,
1203
+ ...cost?.output !== void 0 ? { "app.cost.output_usd": cost.output } : void 0,
1204
+ ...cost?.cacheRead !== void 0 ? { "app.cost.cache_read_usd": cost.cacheRead } : void 0,
1205
+ ...cost?.cacheWrite !== void 0 ? { "app.cost.cache_write_usd": cost.cacheWrite } : void 0,
1206
+ ...cost?.total !== void 0 ? { "app.cost.total_usd": cost.total } : void 0
1207
+ };
1208
+ }
1209
+ //#endregion
1210
+ export { JUNIOR_WORKSPACE_SNAPSHOT_JOB_CALLBACK_ROUTE as A, withSpan as C, JUNIOR_PLUGIN_TASK_CALLBACK_ROUTE as D, JUNIOR_HEARTBEAT_ROUTE as E, isRecord as F, toOptionalNumber as I, toOptionalString as L, getDeploymentServiceVersion as M, getDeploymentTelemetryAttributes as N, JUNIOR_RETENTION_CRON_SCHEDULE as O, normalizeIdentityEmail as P, withLogContext as S, JUNIOR_HEARTBEAT_CRON_SCHEDULE as T, setSpanAttributes as _, extractGenAiUsageSummary as a, summarizeMessageText as b, getTracePropagationHeaders as c, logInfo as d, logWarn as f, setSentryUser as g, serializeGenAiAttribute as h, extractGenAiUsageAttributes as i, LEGACY_JUNIOR_CONVERSATION_WORK_FUNCTION as j, JUNIOR_RETENTION_ROUTE as k, logError as l, runBestEffort as m, createChatSdkLogger as n, getActiveTraceId as o, normalizeGenAiFinishReason as p, createRequestContext as r, getLogContextAttributesForSpan as s, buildTurnFailureResponse as t, logException as u, setSpanStatus as v, JUNIOR_CONVERSATION_WORK_CALLBACK_ROUTE as w, withContext as x, setTags as y };