@langwatch/mcp-server 0.10.1 → 1.0.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 (122) hide show
  1. package/.release-please-shim +1 -1
  2. package/CHANGELOG.md +54 -0
  3. package/README.md +9 -17
  4. package/dist/{archive-project-KAZFHR4A.js → archive-project-MK3673A7.js} +4 -3
  5. package/dist/{archive-scenario-6M2IB7Y2.js → archive-scenario-KATSXRIN.js} +4 -3
  6. package/dist/{archive-suite-NXZ3YDS3.js → archive-suite-C3KX6IIZ.js} +4 -3
  7. package/dist/{assign-prompt-tag-WPUJO55U.js → assign-prompt-tag-E3C5W6PI.js} +3 -2
  8. package/dist/chunk-37SMPMQS.js +12 -0
  9. package/dist/{chunk-CAY57CKF.js → chunk-5UWY24RP.js} +77 -4
  10. package/dist/chunk-BJ7B4R26.js +42 -0
  11. package/dist/chunk-CE6QMZOP.js +432 -0
  12. package/dist/{chunk-AGGE6NPR.js → chunk-DAIQKS27.js} +2 -2
  13. package/dist/{chunk-GWEW5XON.js → chunk-EU22L52K.js} +2 -2
  14. package/dist/{chunk-ITN2QGHF.js → chunk-J45SVWPR.js} +2 -2
  15. package/dist/{chunk-LTEJDL4V.js → chunk-O3LWVN67.js} +2 -2
  16. package/dist/{chunk-RDUXCCFR.js → chunk-RYRB2YVJ.js} +2 -2
  17. package/dist/{chunk-XRQNXN2Z.js → chunk-T7WJVS2N.js} +2 -2
  18. package/dist/{chunk-U2QIW2SW.js → chunk-UXXA4D6K.js} +2 -2
  19. package/dist/{chunk-HRFQAFPR.js → chunk-VYPSKRPN.js} +220 -133
  20. package/dist/{chunk-UKRCZJJC.js → chunk-WDH5P5RF.js} +2 -2
  21. package/dist/{chunk-COCNCXVJ.js → chunk-WWMDHZZV.js} +2 -2
  22. package/dist/{chunk-B6UV3JVI.js → chunk-XY4STOBE.js} +2 -2
  23. package/dist/{chunk-ESGZVPPC.js → chunk-Y3HDZ6OW.js} +2 -2
  24. package/dist/config.js +1 -0
  25. package/dist/{create-agent-BI7UTJ6A.js → create-agent-7W57J7MT.js} +4 -3
  26. package/dist/{create-annotation-SNM2J6S4.js → create-annotation-W2XELBCQ.js} +4 -3
  27. package/dist/{create-api-key-23MXYC2L.js → create-api-key-MKRXKFJM.js} +4 -3
  28. package/dist/{create-dashboard-CPOOOIKK.js → create-dashboard-QGL7IODC.js} +4 -3
  29. package/dist/{create-dataset-BVXPVVY2.js → create-dataset-3PH7A4HG.js} +4 -3
  30. package/dist/{create-dataset-records-S7VFIIMR.js → create-dataset-records-4DZS3VRL.js} +4 -3
  31. package/dist/{create-evaluator-WJAAQOUE.js → create-evaluator-YWH6NC4M.js} +4 -3
  32. package/dist/create-mcp-server.js +3 -2
  33. package/dist/{create-project-BF7LMZH5.js → create-project-BOBQ32C5.js} +4 -3
  34. package/dist/{create-prompt-LZ3QHSU4.js → create-prompt-FLCFGITE.js} +3 -2
  35. package/dist/{create-prompt-tag-IF4J24QM.js → create-prompt-tag-EMPNIKEA.js} +3 -2
  36. package/dist/{create-scenario-BK4E5DEU.js → create-scenario-BSBIHUL6.js} +4 -3
  37. package/dist/{create-suite-HEQPNLND.js → create-suite-TWF6BBR4.js} +4 -3
  38. package/dist/{delete-agent-Y4T2G5PT.js → delete-agent-7MSYNY5E.js} +4 -3
  39. package/dist/{delete-annotation-KYDMQTZG.js → delete-annotation-ZT5IGN24.js} +4 -3
  40. package/dist/{delete-dashboard-3RW647WJ.js → delete-dashboard-BTIY5S3L.js} +4 -3
  41. package/dist/{delete-dataset-SZAHFHHS.js → delete-dataset-U45HQHPR.js} +4 -3
  42. package/dist/{delete-dataset-records-ISHKGEBH.js → delete-dataset-records-R43IMAWB.js} +4 -3
  43. package/dist/{delete-evaluator-VKIG5I3S.js → delete-evaluator-U6JMQ6C7.js} +4 -3
  44. package/dist/{delete-prompt-tag-VYYL4GTF.js → delete-prompt-tag-4EV4TDHB.js} +3 -2
  45. package/dist/{delete-workflow-SHNPYSWQ.js → delete-workflow-5QYALXEL.js} +4 -3
  46. package/dist/discover-evaluator-schema-MRGHVNTT.js +2175 -0
  47. package/dist/{discover-scenario-schema-MEEEVND7.js → discover-scenario-schema-UPBTCWPG.js} +3 -1
  48. package/dist/{discover-schema-3T52ORPB.js → discover-schema-ICGXPHUW.js} +3 -1
  49. package/dist/{get-agent-IZSP7AR5.js → get-agent-7QJVPH72.js} +4 -3
  50. package/dist/{get-analytics-EDFAYYIQ.js → get-analytics-PVERWOA5.js} +3 -2
  51. package/dist/{get-dashboard-WSAO6IQ4.js → get-dashboard-ZZPC3WMD.js} +4 -3
  52. package/dist/{get-dataset-BEVNXQNF.js → get-dataset-25TB2LQH.js} +4 -3
  53. package/dist/{get-evaluator-HCVXNPZR.js → get-evaluator-3FTRQKEC.js} +4 -3
  54. package/dist/{get-project-H4V3GYRQ.js → get-project-5OAXYC57.js} +4 -3
  55. package/dist/{get-prompt-EWRJVVGB.js → get-prompt-I753LZKZ.js} +3 -2
  56. package/dist/{get-scenario-24YUJS5W.js → get-scenario-DSSTR6FI.js} +4 -3
  57. package/dist/{get-simulation-run-UX2W6F6I.js → get-simulation-run-RQPMS2MC.js} +4 -3
  58. package/dist/{get-suite-B65ZKZJA.js → get-suite-GTOCY5PL.js} +4 -3
  59. package/dist/{get-trace-ZR7MIITH.js → get-trace-O5VT3NAC.js} +7 -9
  60. package/dist/{get-workflow-YROHUQJW.js → get-workflow-3EZDOEIF.js} +4 -3
  61. package/dist/http-server-2ACJ3CXW.js +24366 -0
  62. package/dist/index.js +20935 -1751
  63. package/dist/{langwatch-api-annotations-OPEXNTPF.js → langwatch-api-annotations-E65MI3WZ.js} +4 -3
  64. package/dist/{langwatch-api-dashboards-NPQM6QJI.js → langwatch-api-dashboards-QCDECRCY.js} +4 -3
  65. package/dist/{langwatch-api-monitors-3L25OOOS.js → langwatch-api-monitors-UIO2KTDV.js} +3 -2
  66. package/dist/{langwatch-api-secrets-ZFURUA62.js → langwatch-api-secrets-4T2EKSJ7.js} +3 -2
  67. package/dist/{langwatch-api-triggers-XGXXT7DD.js → langwatch-api-triggers-MPOEKPUY.js} +3 -2
  68. package/dist/{langwatch-api-workflows-CXCTTCXT.js → langwatch-api-workflows-5HRZ7HR4.js} +4 -3
  69. package/dist/{list-agents-6ZNOV7FK.js → list-agents-TIJTP566.js} +4 -3
  70. package/dist/{list-annotations-6P3IWILH.js → list-annotations-CGX5BT7E.js} +4 -3
  71. package/dist/{list-api-keys-JJI62KD2.js → list-api-keys-JLWJPFRX.js} +4 -3
  72. package/dist/{list-dashboards-G2WJOXWB.js → list-dashboards-RNIWX3TX.js} +4 -3
  73. package/dist/{list-dataset-records-GWWVOCII.js → list-dataset-records-B5MHZR66.js} +4 -3
  74. package/dist/{list-datasets-HBTH33X4.js → list-datasets-BVCAMQCP.js} +4 -3
  75. package/dist/{list-evaluators-K5OGB6TX.js → list-evaluators-65FBTL2U.js} +4 -3
  76. package/dist/{list-model-providers-JMOGZLSO.js → list-model-providers-GRK3I3VV.js} +4 -3
  77. package/dist/{list-projects-OXJC2NW5.js → list-projects-JLMBFMW3.js} +4 -3
  78. package/dist/{list-prompt-tags-J2HPHVAZ.js → list-prompt-tags-UHNWDGQI.js} +3 -2
  79. package/dist/{list-prompts-C7GR72XL.js → list-prompts-7254B3U7.js} +3 -2
  80. package/dist/{list-scenarios-JEPGIIDO.js → list-scenarios-46YNICKM.js} +4 -3
  81. package/dist/{list-simulation-runs-DRSAGPEC.js → list-simulation-runs-LGNEFNPN.js} +4 -3
  82. package/dist/{list-suites-POTZ3ZT6.js → list-suites-5VK4HXEK.js} +4 -3
  83. package/dist/{list-workflows-QQZQIOHB.js → list-workflows-MLQDM6CP.js} +4 -3
  84. package/dist/{rename-prompt-tag-4AAV2BS4.js → rename-prompt-tag-RHQMNEQL.js} +3 -2
  85. package/dist/report-issue-DXJ6TPTC.js +412 -0
  86. package/dist/{revoke-api-key-TONB4ADQ.js → revoke-api-key-3Y35EMBT.js} +4 -3
  87. package/dist/{run-agent-7QE3YEH7.js → run-agent-RBSIFKRT.js} +4 -3
  88. package/dist/{run-suite-Q66OSPO4.js → run-suite-K3DNQ3SE.js} +4 -3
  89. package/dist/{run-workflow-RWX2D752.js → run-workflow-5LVBZYLS.js} +4 -3
  90. package/dist/{search-traces-M5E5VB4X.js → search-traces-U4HLOCZ2.js} +9 -2
  91. package/dist/{set-model-provider-XENT5D2P.js → set-model-provider-V3M5CDIY.js} +4 -3
  92. package/dist/{update-agent-GML25EE3.js → update-agent-47RZIHS7.js} +4 -3
  93. package/dist/{update-dataset-R4MM6NNY.js → update-dataset-G6QJJGS5.js} +4 -3
  94. package/dist/{update-dataset-record-FN4BL5P4.js → update-dataset-record-RMWLSWCS.js} +4 -3
  95. package/dist/{update-evaluator-LH2RDDB5.js → update-evaluator-SFRRI5Q3.js} +4 -3
  96. package/dist/{update-project-H53IHRBB.js → update-project-PI5DWBVK.js} +4 -3
  97. package/dist/{update-prompt-M33OTTAJ.js → update-prompt-RQFTEO7Y.js} +3 -2
  98. package/dist/{update-scenario-FKTQRAFQ.js → update-scenario-G3IU2UIB.js} +4 -3
  99. package/dist/{update-suite-JJTNOTXN.js → update-suite-TRGGLNR7.js} +4 -3
  100. package/package.json +20 -18
  101. package/pnpm-workspace.yaml +20 -3
  102. package/pyproject.toml +9 -1
  103. package/src/__tests__/all-tools.integration.test.ts +56 -120
  104. package/src/__tests__/documentation-fetch-security.integration.test.ts +176 -0
  105. package/src/__tests__/langwatch-api.unit.test.ts +206 -0
  106. package/src/__tests__/public-http-request-security.integration.test.ts +118 -0
  107. package/src/__tests__/report-issue.integration.test.ts +147 -0
  108. package/src/__tests__/tools.unit.test.ts +24 -0
  109. package/src/create-mcp-server.ts +43 -29
  110. package/src/documentation-fetch.ts +111 -0
  111. package/src/langwatch-api-agents.ts +2 -2
  112. package/src/langwatch-api.ts +138 -8
  113. package/src/public-http-request.ts +242 -0
  114. package/src/tools/get-trace.ts +2 -12
  115. package/src/tools/report-issue.ts +150 -0
  116. package/src/tools/search-traces.ts +4 -0
  117. package/src/utils/format-evaluations.ts +20 -0
  118. package/tsconfig.json +8 -1
  119. package/uv.lock +259 -205
  120. package/dist/chunk-IUP5IHBD.js +0 -71
  121. package/dist/discover-evaluator-schema-H23XCLNE.js +0 -1402
  122. package/dist/http-server-GXVEDA7G.js +0 -226
@@ -0,0 +1,412 @@
1
+ import {
2
+ getConfig
3
+ } from "./chunk-KOO5733S.js";
4
+ import "./chunk-BJ7B4R26.js";
5
+
6
+ // ../langwatch/packages/redaction/src/markers.ts
7
+ var SECRET_MARKER = "[SECRET]";
8
+ function formatPiiMarker(entity) {
9
+ return `[${entity}]`;
10
+ }
11
+
12
+ // ../langwatch/packages/redaction/src/secrets.ts
13
+ var SECRETS_REDACTION_MARKER = SECRET_MARKER;
14
+ var REPLACEMENT = SECRETS_REDACTION_MARKER;
15
+ var MAX_SCAN_LENGTH = 25e4;
16
+ var VALUE_RULES = [
17
+ {
18
+ id: "pem_private_key",
19
+ description: "PEM private key block",
20
+ regex: /-----BEGIN (?:RSA |EC |DSA |OPENSSH |PGP )?PRIVATE KEY-----[\s\S]*?-----END (?:RSA |EC |DSA |OPENSSH |PGP )?PRIVATE KEY-----/g
21
+ },
22
+ {
23
+ id: "aws_access_key_id",
24
+ description: "AWS access key id",
25
+ regex: /\b(?:AKIA|ASIA|AGPA|AIDA|AROA|ANPA|ANVA)[0-9A-Z]{16}\b/g
26
+ },
27
+ {
28
+ id: "github_token",
29
+ description: "GitHub token",
30
+ regex: /\b(?:gh[posru]_[A-Za-z0-9]{36,}|github_pat_[A-Za-z0-9_]{60,})\b/g
31
+ },
32
+ {
33
+ // Provider secret keys share the `sk-` namespace: OpenAI (`sk-proj-...`,
34
+ // legacy `sk-...`), Anthropic (`sk-ant-...`), LangWatch (`sk-lw-...`), and
35
+ // others. The body is base64url, so it includes `_` and `-` and has no inner
36
+ // word boundary; matching the whole token and stopping at the next non-key
37
+ // char catches modern keys a `[A-Za-z0-9]+\b` rule misses.
38
+ id: "provider_api_key",
39
+ description: "Provider API key (sk-...)",
40
+ regex: /\bsk-[A-Za-z0-9_-]{20,}(?![A-Za-z0-9_-])/g
41
+ },
42
+ {
43
+ id: "stripe_secret_key",
44
+ description: "Stripe secret key",
45
+ regex: /\b[rs]k_(?:live|test)_[A-Za-z0-9]{16,}\b/g
46
+ },
47
+ {
48
+ id: "slack_token",
49
+ description: "Slack token",
50
+ regex: /\bxox[abposr]-[A-Za-z0-9-]{10,}\b/g
51
+ },
52
+ {
53
+ id: "google_api_key",
54
+ description: "Google API key",
55
+ regex: /\bAIza[0-9A-Za-z_-]{35}\b/g
56
+ },
57
+ {
58
+ id: "jwt",
59
+ description: "JSON Web Token",
60
+ regex: /\beyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\b/g
61
+ },
62
+ {
63
+ id: "url_credentials",
64
+ description: "Password embedded in a connection URL",
65
+ // scheme://user:password@host -> keep everything but the password. The
66
+ // scheme length is bounded (real schemes are short) so a long run of
67
+ // name-like characters costs constant backtracking per position instead
68
+ // of a quadratic scan on huge inputs.
69
+ regex: /([a-z][a-z0-9+.-]{0,30}:\/\/[^\s:@/]+:)([^\s:@/]+)(@)/gi,
70
+ render: (_m, prefix, _password, at) => `${prefix}${REPLACEMENT}${at}`
71
+ },
72
+ {
73
+ id: "bearer_token",
74
+ description: "Bearer authorization token",
75
+ regex: /\b(Bearer\s+)[A-Za-z0-9._~+/-]{10,}=*/gi,
76
+ render: (_m, prefix) => `${prefix}${REPLACEMENT}`
77
+ }
78
+ ];
79
+ var BUILTIN_SECRET_RULES = VALUE_RULES.map(({ id, description }) => ({ id, description }));
80
+ var SENSITIVE_KEY_REGEX = /(?:^|[._-])(?:password|passwd|pwd|secret|api[_-]?key|apikey|access[_-]?token|auth[_-]?token|authorization|auth|bearer|credentials?|private[_-]?key|client[_-]?secret|db[_-]?password|connection[_-]?string|session[_-]?token|refresh[_-]?token|set[_-]?cookie|cookie|x-api-key)(?:$|[._-])/i;
81
+ function isSensitiveAttributeKey(key) {
82
+ return SENSITIVE_KEY_REGEX.test(key);
83
+ }
84
+ var VALUE_BOUNDARY = /["'`]/;
85
+ function keptLengthAtBoundary(match) {
86
+ const index = match.search(VALUE_BOUNDARY);
87
+ return index === -1 ? match.length : index;
88
+ }
89
+ function redactSecretsInText({
90
+ text,
91
+ customPatterns = []
92
+ }) {
93
+ if (typeof text !== "string" || text.length === 0 || text.length > MAX_SCAN_LENGTH) {
94
+ return { text, redactedCount: 0 };
95
+ }
96
+ let redactedCount = 0;
97
+ let result = text;
98
+ for (const rule of VALUE_RULES) {
99
+ result = result.replace(rule.regex, (...args) => {
100
+ if (rule.render) {
101
+ redactedCount++;
102
+ return rule.render(...args);
103
+ }
104
+ const full = args[0] ?? "";
105
+ const kept = keptLengthAtBoundary(full);
106
+ if (kept === 0) return full;
107
+ redactedCount++;
108
+ return REPLACEMENT + full.slice(kept);
109
+ });
110
+ }
111
+ for (const pattern of customPatterns) {
112
+ result = result.replace(pattern, (...args) => {
113
+ const full = args[0] ?? "";
114
+ const kept = keptLengthAtBoundary(full);
115
+ if (kept === 0) return full;
116
+ redactedCount++;
117
+ return REPLACEMENT + full.slice(kept);
118
+ });
119
+ }
120
+ return { text: result, redactedCount };
121
+ }
122
+
123
+ // ../langwatch/packages/redaction/src/sessionReport.ts
124
+ var EMAIL_MARKER = formatPiiMarker("EMAIL_ADDRESS");
125
+ var PHONE_MARKER = formatPiiMarker("PHONE_NUMBER");
126
+ var CARD_MARKER = formatPiiMarker("CREDIT_CARD");
127
+ var IP_MARKER = formatPiiMarker("IP_ADDRESS");
128
+ var ENV_SECRET_NAME_REGEX = /(?:^|[._-])(?:key|token|secret|password|passwd|pwd|credentials?|auth)(?:$|[._-])/i;
129
+ var MIN_ENV_SECRET_LENGTH = 8;
130
+ function collectSensitiveEnvValues(env) {
131
+ const values = /* @__PURE__ */ new Set();
132
+ for (const [name, value] of Object.entries(env)) {
133
+ if (!value) continue;
134
+ const trimmed = value.trim();
135
+ if (trimmed.length < MIN_ENV_SECRET_LENGTH) continue;
136
+ if (!ENV_SECRET_NAME_REGEX.test(name)) continue;
137
+ values.add(trimmed);
138
+ }
139
+ return [...values].sort((a, b) => b.length - a.length);
140
+ }
141
+ var EMAIL_REGEX = /[A-Za-z0-9._%+-]{1,64}@[A-Za-z0-9.-]{1,253}\.[A-Za-z]{2,24}/g;
142
+ var INTL_PHONE_REGEX = /(?<![\w.+-])\+[1-9]\d{0,2}(?:[\s.-]?(?:\(\d{1,4}\)[\s.-]?)?\d{1,4}){1,5}(?!\d)/g;
143
+ var NATIONAL_PHONE_REGEX = /(?<!\d)(?:\(\d{3}\)[\s.-]?|\d{3}[.-])\d{3}[.-]\d{4}(?!\d)/g;
144
+ var CARD_REGEX = /(?<![\d.-])\d(?:[ -]?\d){12,18}(?![\d.-])/g;
145
+ var IPV4_REGEX = /\b(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\b/g;
146
+ var countDigits = (value) => value.replace(/\D/g, "").length;
147
+ function passesLuhn(digits) {
148
+ let sum = 0;
149
+ let double = false;
150
+ for (let i = digits.length - 1; i >= 0; i--) {
151
+ let d = digits.charCodeAt(i) - 48;
152
+ if (double) {
153
+ d *= 2;
154
+ if (d > 9) d -= 9;
155
+ }
156
+ sum += d;
157
+ double = !double;
158
+ }
159
+ return sum % 10 === 0;
160
+ }
161
+ function isCardNumber(candidate) {
162
+ const digits = candidate.replace(/[ -]/g, "");
163
+ if (!/^\d+$/.test(digits)) return false;
164
+ const separated = /[ -]/.test(candidate);
165
+ if (!separated && (digits.length < 14 || digits.length > 16)) return false;
166
+ if (digits.length < 13 || digits.length > 19) return false;
167
+ return passesLuhn(digits);
168
+ }
169
+ function isPrivateOrLocalIp(ip) {
170
+ const parts = ip.split(".").map(Number);
171
+ const [a = 0, b = 0] = parts;
172
+ if (a === 0 || a === 10 || a === 127) return true;
173
+ if (a === 192 && b === 168) return true;
174
+ if (a === 172 && b >= 16 && b <= 31) return true;
175
+ if (a === 169 && b === 254) return true;
176
+ if (a === 100 && b >= 64 && b <= 127) return true;
177
+ if (a >= 224) return true;
178
+ return false;
179
+ }
180
+ var SLICE_TARGET = 2e5;
181
+ function sliceLongText(text) {
182
+ if (text.length <= SLICE_TARGET) return [text];
183
+ const slices = [];
184
+ let start = 0;
185
+ while (start < text.length) {
186
+ let end = Math.min(start + SLICE_TARGET, text.length);
187
+ if (end < text.length) {
188
+ const newline = text.lastIndexOf("\n", end);
189
+ if (newline > start + SLICE_TARGET / 2) end = newline;
190
+ }
191
+ slices.push(text.slice(start, end));
192
+ start = end;
193
+ }
194
+ return slices;
195
+ }
196
+ function redactPiiPatterns(text) {
197
+ let redactedCount = 0;
198
+ let result = text.replace(EMAIL_REGEX, () => {
199
+ redactedCount++;
200
+ return EMAIL_MARKER;
201
+ });
202
+ result = result.replace(CARD_REGEX, (match) => {
203
+ if (!isCardNumber(match)) return match;
204
+ redactedCount++;
205
+ return CARD_MARKER;
206
+ });
207
+ result = result.replace(INTL_PHONE_REGEX, (match) => {
208
+ const digits = countDigits(match);
209
+ if (digits < 7 || digits > 15) return match;
210
+ redactedCount++;
211
+ return PHONE_MARKER;
212
+ });
213
+ result = result.replace(NATIONAL_PHONE_REGEX, () => {
214
+ redactedCount++;
215
+ return PHONE_MARKER;
216
+ });
217
+ result = result.replace(IPV4_REGEX, (match) => {
218
+ if (isPrivateOrLocalIp(match)) return match;
219
+ redactedCount++;
220
+ return IP_MARKER;
221
+ });
222
+ return { text: result, redactedCount };
223
+ }
224
+ function scrubEnvLiterals(text, envValues) {
225
+ let result = text;
226
+ let redactedCount = 0;
227
+ for (const value of envValues) {
228
+ if (!result.includes(value)) continue;
229
+ const parts = result.split(value);
230
+ redactedCount += parts.length - 1;
231
+ result = parts.join(SECRET_MARKER);
232
+ }
233
+ return { text: result, redactedCount };
234
+ }
235
+ function redactReportText({
236
+ text,
237
+ envValues = []
238
+ }) {
239
+ if (typeof text !== "string" || text.length === 0) {
240
+ return { text, redactedCount: 0 };
241
+ }
242
+ const envPass = scrubEnvLiterals(text, envValues);
243
+ let redactedCount = envPass.redactedCount;
244
+ const pieces = sliceLongText(envPass.text).map((slice) => {
245
+ const secrets = redactSecretsInText({ text: slice });
246
+ redactedCount += secrets.redactedCount;
247
+ const pii = redactPiiPatterns(secrets.text);
248
+ redactedCount += pii.redactedCount;
249
+ return pii.text;
250
+ });
251
+ return { text: pieces.join(""), redactedCount };
252
+ }
253
+ function redactJsonValue(value, envValues, count) {
254
+ if (typeof value === "string") {
255
+ const result = redactReportText({ text: value, envValues });
256
+ count.redacted += result.redactedCount;
257
+ return result.text;
258
+ }
259
+ if (Array.isArray(value)) {
260
+ return value.map((item) => redactJsonValue(item, envValues, count));
261
+ }
262
+ if (value && typeof value === "object") {
263
+ const out = {};
264
+ for (const [key, entry] of Object.entries(value)) {
265
+ if (isSensitiveAttributeKey(key) && entry !== null && entry !== void 0) {
266
+ out[key] = SECRET_MARKER;
267
+ count.redacted++;
268
+ continue;
269
+ }
270
+ out[key] = redactJsonValue(entry, envValues, count);
271
+ }
272
+ return out;
273
+ }
274
+ return value;
275
+ }
276
+ function redactSessionJsonl({
277
+ jsonl,
278
+ envValues = []
279
+ }) {
280
+ let redactedCount = 0;
281
+ const lines = jsonl.split("\n").map((line) => {
282
+ if (line.trim().length === 0) return line;
283
+ try {
284
+ const parsed = JSON.parse(line);
285
+ const count = { redacted: 0 };
286
+ const redacted = redactJsonValue(parsed, envValues, count);
287
+ redactedCount += count.redacted;
288
+ return JSON.stringify(redacted);
289
+ } catch {
290
+ const result = redactReportText({ text: line, envValues });
291
+ redactedCount += result.redactedCount;
292
+ return result.text;
293
+ }
294
+ });
295
+ return { text: lines.join("\n"), redactedCount };
296
+ }
297
+ function truncateJsonlToByteBudget({
298
+ jsonl,
299
+ maxBytes
300
+ }) {
301
+ const encoder = new TextEncoder();
302
+ if (encoder.encode(jsonl).length <= maxBytes) {
303
+ return { text: jsonl, truncated: false };
304
+ }
305
+ const lines = jsonl.split("\n");
306
+ const kept = [];
307
+ let used = 0;
308
+ for (let i = lines.length - 1; i >= 0; i--) {
309
+ const line = lines[i] ?? "";
310
+ const size = encoder.encode(line).length + 1;
311
+ if (used + size > maxBytes) break;
312
+ kept.unshift(line);
313
+ used += size;
314
+ }
315
+ return { text: kept.join("\n"), truncated: true };
316
+ }
317
+ var REDACTION_AUDIT_URL = "https://github.com/langwatch/langwatch/blob/main/langwatch/packages/redaction/src/sessionReport.ts";
318
+
319
+ // src/tools/report-issue.ts
320
+ var MAX_SESSION_BYTES = 8 * 1024 * 1024;
321
+ var REQUEST_TIMEOUT_MS = 6e4;
322
+ function redactReport(params) {
323
+ const envValues = collectSensitiveEnvValues(process.env);
324
+ let redactedCount = 0;
325
+ const titleResult = redactReportText({ text: params.title, envValues });
326
+ redactedCount += titleResult.redactedCount;
327
+ let summary;
328
+ if (params.summary) {
329
+ const result = redactReportText({ text: params.summary, envValues });
330
+ summary = result.text;
331
+ redactedCount += result.redactedCount;
332
+ }
333
+ let sessionData;
334
+ let sessionTruncated = false;
335
+ if (params.session_content) {
336
+ const redacted = redactSessionJsonl({
337
+ jsonl: params.session_content,
338
+ envValues
339
+ });
340
+ redactedCount += redacted.redactedCount;
341
+ const truncated = truncateJsonlToByteBudget({
342
+ jsonl: redacted.text,
343
+ maxBytes: MAX_SESSION_BYTES
344
+ });
345
+ sessionData = truncated.text;
346
+ sessionTruncated = truncated.truncated;
347
+ }
348
+ return {
349
+ title: titleResult.text,
350
+ summary,
351
+ sessionData,
352
+ sessionTruncated,
353
+ redactedCount
354
+ };
355
+ }
356
+ async function deliverReport(report, params) {
357
+ const config = getConfig();
358
+ const endpoint = config.endpoint.replace(/\/+$/, "");
359
+ const response = await fetch(`${endpoint}/api/bug-reports`, {
360
+ method: "POST",
361
+ headers: {
362
+ "content-type": "application/json",
363
+ ...config.apiKey ? { authorization: `Bearer ${config.apiKey}` } : {}
364
+ },
365
+ body: JSON.stringify({
366
+ source: "mcp",
367
+ kind: report.sessionData ? "full_session" : "summary",
368
+ title: report.title,
369
+ ...report.summary ? { summary: report.summary } : {},
370
+ ...report.sessionData ? { sessionData: report.sessionData, sessionTruncated: report.sessionTruncated } : {},
371
+ ...params.agent ? { agent: params.agent } : {},
372
+ ...params.contact_email ? { contactEmail: params.contact_email } : {}
373
+ }),
374
+ signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS)
375
+ }).catch(() => {
376
+ throw new Error(
377
+ `Could not reach ${endpoint} to deliver the report. Retry in a moment; if it keeps failing, email support@langwatch.ai with the same content.`
378
+ );
379
+ });
380
+ if (!response.ok) {
381
+ const body = (await response.text().catch(() => "")).slice(0, 300);
382
+ throw new Error(
383
+ `The reports endpoint answered HTTP ${response.status}: ${body}. Retry in a moment; if it keeps failing, email support@langwatch.ai.`
384
+ );
385
+ }
386
+ const { id } = await response.json();
387
+ return id;
388
+ }
389
+ async function handleReportIssue(params) {
390
+ if (!params.user_approved) {
391
+ throw new Error(
392
+ `This sends a report to the LangWatch team, so the user must approve it first. Ask the user: "Can I send this issue report to LangWatch to help them fix it?" If they agree, call again with user_approved=true. Secrets and personal data are redacted locally before sending; audit the rules at ${REDACTION_AUDIT_URL}`
393
+ );
394
+ }
395
+ if (!params.summary?.trim() && !params.session_content?.trim()) {
396
+ throw new Error(
397
+ "Nothing to report: pass a summary (what you tried, verbatim errors, what you had to figure out), session_content, or both."
398
+ );
399
+ }
400
+ const report = redactReport(params);
401
+ const id = await deliverReport(report, params);
402
+ return [
403
+ `Report sent to the LangWatch team (${id}). Thank you!`,
404
+ `Redacted ${report.redactedCount} sensitive value${report.redactedCount === 1 ? "" : "s"} locally before sending.`,
405
+ ...report.sessionTruncated ? ["The session content was truncated to the most recent activity to fit the upload limit."] : [],
406
+ "Reports like this directly shape what gets fixed next."
407
+ ].join(" ");
408
+ }
409
+ export {
410
+ handleReportIssue
411
+ };
412
+ //# sourceMappingURL=report-issue-DXJ6TPTC.js.map
@@ -1,8 +1,9 @@
1
1
  import {
2
2
  revokeApiKey
3
- } from "./chunk-COCNCXVJ.js";
4
- import "./chunk-CAY57CKF.js";
3
+ } from "./chunk-WWMDHZZV.js";
4
+ import "./chunk-5UWY24RP.js";
5
5
  import "./chunk-KOO5733S.js";
6
+ import "./chunk-BJ7B4R26.js";
6
7
 
7
8
  // src/tools/revoke-api-key.ts
8
9
  async function handleRevokeApiKey(params) {
@@ -12,4 +13,4 @@ async function handleRevokeApiKey(params) {
12
13
  export {
13
14
  handleRevokeApiKey
14
15
  };
15
- //# sourceMappingURL=revoke-api-key-TONB4ADQ.js.map
16
+ //# sourceMappingURL=revoke-api-key-3Y35EMBT.js.map
@@ -1,8 +1,9 @@
1
1
  import {
2
2
  runAgent
3
- } from "./chunk-IUP5IHBD.js";
4
- import "./chunk-CAY57CKF.js";
3
+ } from "./chunk-CE6QMZOP.js";
4
+ import "./chunk-5UWY24RP.js";
5
5
  import "./chunk-KOO5733S.js";
6
+ import "./chunk-BJ7B4R26.js";
6
7
 
7
8
  // src/tools/run-agent.ts
8
9
  async function handleRunAgent(params) {
@@ -33,4 +34,4 @@ async function handleRunAgent(params) {
33
34
  export {
34
35
  handleRunAgent
35
36
  };
36
- //# sourceMappingURL=run-agent-7QE3YEH7.js.map
37
+ //# sourceMappingURL=run-agent-RBSIFKRT.js.map
@@ -1,8 +1,9 @@
1
1
  import {
2
2
  runSuite
3
- } from "./chunk-UKRCZJJC.js";
4
- import "./chunk-CAY57CKF.js";
3
+ } from "./chunk-WDH5P5RF.js";
4
+ import "./chunk-5UWY24RP.js";
5
5
  import "./chunk-KOO5733S.js";
6
+ import "./chunk-BJ7B4R26.js";
6
7
 
7
8
  // src/tools/run-suite.ts
8
9
  async function handleRunSuite(params) {
@@ -26,4 +27,4 @@ async function handleRunSuite(params) {
26
27
  export {
27
28
  handleRunSuite
28
29
  };
29
- //# sourceMappingURL=run-suite-Q66OSPO4.js.map
30
+ //# sourceMappingURL=run-suite-K3DNQ3SE.js.map
@@ -1,8 +1,9 @@
1
1
  import {
2
2
  runWorkflow
3
- } from "./chunk-XRQNXN2Z.js";
4
- import "./chunk-CAY57CKF.js";
3
+ } from "./chunk-T7WJVS2N.js";
4
+ import "./chunk-5UWY24RP.js";
5
5
  import "./chunk-KOO5733S.js";
6
+ import "./chunk-BJ7B4R26.js";
6
7
 
7
8
  // src/tools/run-workflow.ts
8
9
  async function handleRunWorkflow(params) {
@@ -33,4 +34,4 @@ async function handleRunWorkflow(params) {
33
34
  export {
34
35
  handleRunWorkflow
35
36
  };
36
- //# sourceMappingURL=run-workflow-RWX2D752.js.map
37
+ //# sourceMappingURL=run-workflow-5LVBZYLS.js.map
@@ -1,10 +1,14 @@
1
+ import {
2
+ formatEvaluationLines
3
+ } from "./chunk-37SMPMQS.js";
1
4
  import {
2
5
  parseRelativeDate
3
6
  } from "./chunk-ZXKLPC2E.js";
4
7
  import {
5
8
  searchTraces
6
- } from "./chunk-CAY57CKF.js";
9
+ } from "./chunk-5UWY24RP.js";
7
10
  import "./chunk-KOO5733S.js";
11
+ import "./chunk-BJ7B4R26.js";
8
12
 
9
13
  // src/tools/search-traces.ts
10
14
  async function handleSearchTraces(params) {
@@ -53,6 +57,9 @@ async function handleSearchTraces(params) {
53
57
  if (trace.error) {
54
58
  lines.push(`- **Error**: ${JSON.stringify(trace.error)}`);
55
59
  }
60
+ if (trace.evaluations && trace.evaluations.length > 0) {
61
+ lines.push(...formatEvaluationLines(trace.evaluations));
62
+ }
56
63
  lines.push("");
57
64
  }
58
65
  if (result.pagination?.scrollId) {
@@ -69,4 +76,4 @@ async function handleSearchTraces(params) {
69
76
  export {
70
77
  handleSearchTraces
71
78
  };
72
- //# sourceMappingURL=search-traces-M5E5VB4X.js.map
79
+ //# sourceMappingURL=search-traces-U4HLOCZ2.js.map
@@ -1,8 +1,9 @@
1
1
  import {
2
2
  setModelProvider
3
- } from "./chunk-AGGE6NPR.js";
4
- import "./chunk-CAY57CKF.js";
3
+ } from "./chunk-DAIQKS27.js";
4
+ import "./chunk-5UWY24RP.js";
5
5
  import "./chunk-KOO5733S.js";
6
+ import "./chunk-BJ7B4R26.js";
6
7
 
7
8
  // src/tools/set-model-provider.ts
8
9
  async function handleSetModelProvider(params) {
@@ -30,4 +31,4 @@ async function handleSetModelProvider(params) {
30
31
  export {
31
32
  handleSetModelProvider
32
33
  };
33
- //# sourceMappingURL=set-model-provider-XENT5D2P.js.map
34
+ //# sourceMappingURL=set-model-provider-V3M5CDIY.js.map
@@ -1,8 +1,9 @@
1
1
  import {
2
2
  updateAgent
3
- } from "./chunk-IUP5IHBD.js";
4
- import "./chunk-CAY57CKF.js";
3
+ } from "./chunk-CE6QMZOP.js";
4
+ import "./chunk-5UWY24RP.js";
5
5
  import "./chunk-KOO5733S.js";
6
+ import "./chunk-BJ7B4R26.js";
6
7
 
7
8
  // src/tools/update-agent.ts
8
9
  async function handleUpdateAgent(params) {
@@ -17,4 +18,4 @@ async function handleUpdateAgent(params) {
17
18
  export {
18
19
  handleUpdateAgent
19
20
  };
20
- //# sourceMappingURL=update-agent-GML25EE3.js.map
21
+ //# sourceMappingURL=update-agent-47RZIHS7.js.map
@@ -4,9 +4,10 @@ import {
4
4
  import "./chunk-NUFPTHKU.js";
5
5
  import {
6
6
  updateDataset
7
- } from "./chunk-ITN2QGHF.js";
8
- import "./chunk-CAY57CKF.js";
7
+ } from "./chunk-J45SVWPR.js";
8
+ import "./chunk-5UWY24RP.js";
9
9
  import "./chunk-KOO5733S.js";
10
+ import "./chunk-BJ7B4R26.js";
10
11
 
11
12
  // src/tools/update-dataset.ts
12
13
  async function handleUpdateDataset(params) {
@@ -19,4 +20,4 @@ async function handleUpdateDataset(params) {
19
20
  export {
20
21
  handleUpdateDataset
21
22
  };
22
- //# sourceMappingURL=update-dataset-R4MM6NNY.js.map
23
+ //# sourceMappingURL=update-dataset-G6QJJGS5.js.map
@@ -1,8 +1,9 @@
1
1
  import {
2
2
  updateDatasetRecord
3
- } from "./chunk-ITN2QGHF.js";
4
- import "./chunk-CAY57CKF.js";
3
+ } from "./chunk-J45SVWPR.js";
4
+ import "./chunk-5UWY24RP.js";
5
5
  import "./chunk-KOO5733S.js";
6
+ import "./chunk-BJ7B4R26.js";
6
7
 
7
8
  // src/tools/update-dataset-record.ts
8
9
  async function handleUpdateDatasetRecord(params) {
@@ -16,4 +17,4 @@ async function handleUpdateDatasetRecord(params) {
16
17
  export {
17
18
  handleUpdateDatasetRecord
18
19
  };
19
- //# sourceMappingURL=update-dataset-record-FN4BL5P4.js.map
20
+ //# sourceMappingURL=update-dataset-record-RMWLSWCS.js.map
@@ -1,9 +1,10 @@
1
1
  import {
2
2
  getEvaluatorType,
3
3
  updateEvaluator
4
- } from "./chunk-GWEW5XON.js";
5
- import "./chunk-CAY57CKF.js";
4
+ } from "./chunk-EU22L52K.js";
5
+ import "./chunk-5UWY24RP.js";
6
6
  import "./chunk-KOO5733S.js";
7
+ import "./chunk-BJ7B4R26.js";
7
8
 
8
9
  // src/tools/update-evaluator.ts
9
10
  async function handleUpdateEvaluator(params) {
@@ -21,4 +22,4 @@ async function handleUpdateEvaluator(params) {
21
22
  export {
22
23
  handleUpdateEvaluator
23
24
  };
24
- //# sourceMappingURL=update-evaluator-LH2RDDB5.js.map
25
+ //# sourceMappingURL=update-evaluator-SFRRI5Q3.js.map
@@ -1,8 +1,9 @@
1
1
  import {
2
2
  updateProject
3
- } from "./chunk-B6UV3JVI.js";
4
- import "./chunk-CAY57CKF.js";
3
+ } from "./chunk-XY4STOBE.js";
4
+ import "./chunk-5UWY24RP.js";
5
5
  import "./chunk-KOO5733S.js";
6
+ import "./chunk-BJ7B4R26.js";
6
7
 
7
8
  // src/tools/update-project.ts
8
9
  async function handleUpdateProject(params) {
@@ -21,4 +22,4 @@ async function handleUpdateProject(params) {
21
22
  export {
22
23
  handleUpdateProject
23
24
  };
24
- //# sourceMappingURL=update-project-H53IHRBB.js.map
25
+ //# sourceMappingURL=update-project-PI5DWBVK.js.map
@@ -1,7 +1,8 @@
1
1
  import {
2
2
  updatePrompt
3
- } from "./chunk-CAY57CKF.js";
3
+ } from "./chunk-5UWY24RP.js";
4
4
  import "./chunk-KOO5733S.js";
5
+ import "./chunk-BJ7B4R26.js";
5
6
 
6
7
  // src/tools/update-prompt.ts
7
8
  async function handleUpdatePrompt(params) {
@@ -21,4 +22,4 @@ async function handleUpdatePrompt(params) {
21
22
  export {
22
23
  handleUpdatePrompt
23
24
  };
24
- //# sourceMappingURL=update-prompt-M33OTTAJ.js.map
25
+ //# sourceMappingURL=update-prompt-RQFTEO7Y.js.map
@@ -1,8 +1,9 @@
1
1
  import {
2
2
  updateScenario
3
- } from "./chunk-LTEJDL4V.js";
4
- import "./chunk-CAY57CKF.js";
3
+ } from "./chunk-O3LWVN67.js";
4
+ import "./chunk-5UWY24RP.js";
5
5
  import "./chunk-KOO5733S.js";
6
+ import "./chunk-BJ7B4R26.js";
6
7
 
7
8
  // src/tools/update-scenario.ts
8
9
  async function handleUpdateScenario(params) {
@@ -24,4 +25,4 @@ async function handleUpdateScenario(params) {
24
25
  export {
25
26
  handleUpdateScenario
26
27
  };
27
- //# sourceMappingURL=update-scenario-FKTQRAFQ.js.map
28
+ //# sourceMappingURL=update-scenario-G3IU2UIB.js.map
@@ -1,8 +1,9 @@
1
1
  import {
2
2
  updateSuite
3
- } from "./chunk-UKRCZJJC.js";
4
- import "./chunk-CAY57CKF.js";
3
+ } from "./chunk-WDH5P5RF.js";
4
+ import "./chunk-5UWY24RP.js";
5
5
  import "./chunk-KOO5733S.js";
6
+ import "./chunk-BJ7B4R26.js";
6
7
 
7
8
  // src/tools/update-suite.ts
8
9
  async function handleUpdateSuite(params) {
@@ -36,4 +37,4 @@ async function handleUpdateSuite(params) {
36
37
  export {
37
38
  handleUpdateSuite
38
39
  };
39
- //# sourceMappingURL=update-suite-JJTNOTXN.js.map
40
+ //# sourceMappingURL=update-suite-TRGGLNR7.js.map