@cyanheads/mcp-ts-core 0.12.7 → 0.12.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +8 -3
- package/CLAUDE.md +8 -3
- package/README.md +11 -4
- package/changelog/0.12.x/0.12.8.md +55 -0
- package/dist/config/index.d.ts +3 -34
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js +4 -26
- package/dist/config/index.js.map +1 -1
- package/dist/core/app.d.ts +0 -8
- package/dist/core/app.d.ts.map +1 -1
- package/dist/core/app.js +0 -7
- package/dist/core/app.js.map +1 -1
- package/dist/core/serverManifest.d.ts +0 -7
- package/dist/core/serverManifest.d.ts.map +1 -1
- package/dist/core/serverManifest.js +1 -13
- package/dist/core/serverManifest.js.map +1 -1
- package/dist/linter/rules/enrichment-rules.js +2 -2
- package/dist/linter/rules/enrichment-rules.js.map +1 -1
- package/dist/linter/rules/format-parity-rules.d.ts.map +1 -1
- package/dist/linter/rules/format-parity-rules.js +14 -36
- package/dist/linter/rules/format-parity-rules.js.map +1 -1
- package/dist/linter/rules/prompt-rules.d.ts +1 -1
- package/dist/linter/rules/prompt-rules.d.ts.map +1 -1
- package/dist/linter/rules/prompt-rules.js +2 -19
- package/dist/linter/rules/prompt-rules.js.map +1 -1
- package/dist/linter/rules/resource-rules.d.ts +1 -1
- package/dist/linter/rules/resource-rules.d.ts.map +1 -1
- package/dist/linter/rules/resource-rules.js +9 -39
- package/dist/linter/rules/resource-rules.js.map +1 -1
- package/dist/linter/rules/schema-rules.d.ts +22 -2
- package/dist/linter/rules/schema-rules.d.ts.map +1 -1
- package/dist/linter/rules/schema-rules.js +28 -5
- package/dist/linter/rules/schema-rules.js.map +1 -1
- package/dist/linter/rules/tool-rules.d.ts +1 -1
- package/dist/linter/rules/tool-rules.d.ts.map +1 -1
- package/dist/linter/rules/tool-rules.js +13 -41
- package/dist/linter/rules/tool-rules.js.map +1 -1
- package/dist/linter/validate.d.ts.map +1 -1
- package/dist/linter/validate.js +22 -42
- package/dist/linter/validate.js.map +1 -1
- package/dist/mcp-server/apps/appBuilders.d.ts.map +1 -1
- package/dist/mcp-server/apps/appBuilders.js +2 -16
- package/dist/mcp-server/apps/appBuilders.js.map +1 -1
- package/dist/mcp-server/handlerContext.d.ts +66 -0
- package/dist/mcp-server/handlerContext.d.ts.map +1 -0
- package/dist/mcp-server/handlerContext.js +71 -0
- package/dist/mcp-server/handlerContext.js.map +1 -0
- package/dist/mcp-server/inputRequired.d.ts +7 -1
- package/dist/mcp-server/inputRequired.d.ts.map +1 -1
- package/dist/mcp-server/inputRequired.js +10 -3
- package/dist/mcp-server/inputRequired.js.map +1 -1
- package/dist/mcp-server/resources/resource-registration.d.ts +2 -2
- package/dist/mcp-server/resources/resource-registration.d.ts.map +1 -1
- package/dist/mcp-server/resources/resource-registration.js.map +1 -1
- package/dist/mcp-server/resources/utils/resourceHandlerFactory.d.ts +14 -43
- package/dist/mcp-server/resources/utils/resourceHandlerFactory.d.ts.map +1 -1
- package/dist/mcp-server/resources/utils/resourceHandlerFactory.js +11 -50
- package/dist/mcp-server/resources/utils/resourceHandlerFactory.js.map +1 -1
- package/dist/mcp-server/tools/tool-registration.d.ts +5 -9
- package/dist/mcp-server/tools/tool-registration.d.ts.map +1 -1
- package/dist/mcp-server/tools/tool-registration.js +9 -11
- package/dist/mcp-server/tools/tool-registration.js.map +1 -1
- package/dist/mcp-server/tools/utils/schemaShape.d.ts +21 -0
- package/dist/mcp-server/tools/utils/schemaShape.d.ts.map +1 -1
- package/dist/mcp-server/tools/utils/schemaShape.js +8 -6
- package/dist/mcp-server/tools/utils/schemaShape.js.map +1 -1
- package/dist/mcp-server/tools/utils/toolHandlerFactory.d.ts +15 -43
- package/dist/mcp-server/tools/utils/toolHandlerFactory.d.ts.map +1 -1
- package/dist/mcp-server/tools/utils/toolHandlerFactory.js +31 -72
- package/dist/mcp-server/tools/utils/toolHandlerFactory.js.map +1 -1
- package/dist/mcp-server/transports/http/httpErrorHandler.d.ts.map +1 -1
- package/dist/mcp-server/transports/http/httpErrorHandler.js +2 -1
- package/dist/mcp-server/transports/http/httpErrorHandler.js.map +1 -1
- package/dist/mcp-server/transports/http/landing-page/handler.d.ts.map +1 -1
- package/dist/mcp-server/transports/http/landing-page/handler.js +2 -1
- package/dist/mcp-server/transports/http/landing-page/handler.js.map +1 -1
- package/dist/mcp-server/transports/http/protectedResourceMetadata.d.ts.map +1 -1
- package/dist/mcp-server/transports/http/protectedResourceMetadata.js +2 -1
- package/dist/mcp-server/transports/http/protectedResourceMetadata.js.map +1 -1
- package/dist/mcp-server/transports/http/publicOrigin.d.ts +11 -0
- package/dist/mcp-server/transports/http/publicOrigin.d.ts.map +1 -0
- package/dist/mcp-server/transports/http/publicOrigin.js +13 -0
- package/dist/mcp-server/transports/http/publicOrigin.js.map +1 -0
- package/dist/mcp-server/transports/http/serverCard.d.ts.map +1 -1
- package/dist/mcp-server/transports/http/serverCard.js +2 -1
- package/dist/mcp-server/transports/http/serverCard.js.map +1 -1
- package/dist/mcp-server/transports/http/sessionIdUtils.d.ts +4 -0
- package/dist/mcp-server/transports/http/sessionIdUtils.d.ts.map +1 -1
- package/dist/mcp-server/transports/http/sessionIdUtils.js +3 -13
- package/dist/mcp-server/transports/http/sessionIdUtils.js.map +1 -1
- package/dist/mcp-server/transports/manager.d.ts +0 -3
- package/dist/mcp-server/transports/manager.d.ts.map +1 -1
- package/dist/mcp-server/transports/manager.js +0 -7
- package/dist/mcp-server/transports/manager.js.map +1 -1
- package/dist/services/canvas/core/CanvasRegistry.d.ts +14 -0
- package/dist/services/canvas/core/CanvasRegistry.d.ts.map +1 -1
- package/dist/services/canvas/core/CanvasRegistry.js +3 -2
- package/dist/services/canvas/core/CanvasRegistry.js.map +1 -1
- package/dist/services/canvas/providers/duckdb/DuckdbProvider.d.ts +16 -0
- package/dist/services/canvas/providers/duckdb/DuckdbProvider.d.ts.map +1 -1
- package/dist/services/canvas/providers/duckdb/DuckdbProvider.js +78 -103
- package/dist/services/canvas/providers/duckdb/DuckdbProvider.js.map +1 -1
- package/dist/services/graph/core/GraphService.d.ts +3 -3
- package/dist/services/graph/core/GraphService.js +3 -3
- package/dist/services/graph/types.d.ts +2 -79
- package/dist/services/graph/types.d.ts.map +1 -1
- package/dist/services/graph/types.js +2 -2
- package/dist/services/index.d.ts +1 -2
- package/dist/services/index.d.ts.map +1 -1
- package/dist/services/index.js +0 -1
- package/dist/services/index.js.map +1 -1
- package/dist/services/mirror/sqlite/handle.d.ts.map +1 -1
- package/dist/services/mirror/sqlite/handle.js +22 -36
- package/dist/services/mirror/sqlite/handle.js.map +1 -1
- package/dist/services/speech/core/ISpeechProvider.d.ts +0 -24
- package/dist/services/speech/core/ISpeechProvider.d.ts.map +1 -1
- package/dist/services/speech/core/ISpeechProvider.js +1 -28
- package/dist/services/speech/core/ISpeechProvider.js.map +1 -1
- package/dist/services/speech/core/SpeechService.d.ts.map +1 -1
- package/dist/services/speech/core/SpeechService.js +5 -8
- package/dist/services/speech/core/SpeechService.js.map +1 -1
- package/dist/services/speech/providers/elevenlabs.provider.d.ts.map +1 -1
- package/dist/services/speech/providers/elevenlabs.provider.js +1 -0
- package/dist/services/speech/providers/elevenlabs.provider.js.map +1 -1
- package/dist/services/speech/types.d.ts +2 -19
- package/dist/services/speech/types.d.ts.map +1 -1
- package/dist/storage/core/providerHelpers.d.ts +52 -0
- package/dist/storage/core/providerHelpers.d.ts.map +1 -0
- package/dist/storage/core/providerHelpers.js +96 -0
- package/dist/storage/core/providerHelpers.js.map +1 -0
- package/dist/storage/providers/cloudflare/d1Provider.d.ts.map +1 -1
- package/dist/storage/providers/cloudflare/d1Provider.js +1 -4
- package/dist/storage/providers/cloudflare/d1Provider.js.map +1 -1
- package/dist/storage/providers/cloudflare/kvProvider.d.ts.map +1 -1
- package/dist/storage/providers/cloudflare/kvProvider.js +4 -31
- package/dist/storage/providers/cloudflare/kvProvider.js.map +1 -1
- package/dist/storage/providers/cloudflare/r2Provider.d.ts +1 -1
- package/dist/storage/providers/cloudflare/r2Provider.d.ts.map +1 -1
- package/dist/storage/providers/cloudflare/r2Provider.js +8 -48
- package/dist/storage/providers/cloudflare/r2Provider.js.map +1 -1
- package/dist/storage/providers/fileSystem/fileSystemProvider.d.ts +1 -1
- package/dist/storage/providers/fileSystem/fileSystemProvider.d.ts.map +1 -1
- package/dist/storage/providers/fileSystem/fileSystemProvider.js +17 -86
- package/dist/storage/providers/fileSystem/fileSystemProvider.js.map +1 -1
- package/dist/storage/providers/inMemory/inMemoryProvider.d.ts.map +1 -1
- package/dist/storage/providers/inMemory/inMemoryProvider.js +5 -38
- package/dist/storage/providers/inMemory/inMemoryProvider.js.map +1 -1
- package/dist/storage/providers/supabase/supabaseProvider.d.ts.map +1 -1
- package/dist/storage/providers/supabase/supabaseProvider.js +1 -4
- package/dist/storage/providers/supabase/supabaseProvider.js.map +1 -1
- package/dist/testing/fuzz.d.ts.map +1 -1
- package/dist/testing/fuzz.js +17 -31
- package/dist/testing/fuzz.js.map +1 -1
- package/dist/testing/index.d.ts.map +1 -1
- package/dist/testing/index.js +4 -26
- package/dist/testing/index.js.map +1 -1
- package/dist/utils/internal/error-handler/types.d.ts +0 -4
- package/dist/utils/internal/error-handler/types.d.ts.map +1 -1
- package/dist/utils/internal/logger.d.ts.map +1 -1
- package/dist/utils/internal/logger.js +2 -16
- package/dist/utils/internal/logger.js.map +1 -1
- package/dist/utils/internal/performance.d.ts +8 -31
- package/dist/utils/internal/performance.d.ts.map +1 -1
- package/dist/utils/internal/performance.js +173 -295
- package/dist/utils/internal/performance.js.map +1 -1
- package/dist/utils/security/idGenerator.d.ts.map +1 -1
- package/dist/utils/security/idGenerator.js +24 -43
- package/dist/utils/security/idGenerator.js.map +1 -1
- package/dist/utils/security/sanitization.d.ts +0 -7
- package/dist/utils/security/sanitization.d.ts.map +1 -1
- package/dist/utils/security/sanitization.js +4 -31
- package/dist/utils/security/sanitization.js.map +1 -1
- package/dist/utils/security/sensitiveFields.d.ts +14 -0
- package/dist/utils/security/sensitiveFields.d.ts.map +1 -0
- package/dist/utils/security/sensitiveFields.js +31 -0
- package/dist/utils/security/sensitiveFields.js.map +1 -0
- package/dist/utils/telemetry/trace.d.ts +8 -10
- package/dist/utils/telemetry/trace.d.ts.map +1 -1
- package/dist/utils/telemetry/trace.js +19 -18
- package/dist/utils/telemetry/trace.js.map +1 -1
- package/dist/utils/types/guards.d.ts +0 -102
- package/dist/utils/types/guards.d.ts.map +1 -1
- package/dist/utils/types/guards.js +0 -114
- package/dist/utils/types/guards.js.map +1 -1
- package/package.json +6 -6
- package/skills/add-provider/SKILL.md +18 -4
- package/skills/api-config/SKILL.md +4 -18
- package/skills/api-services/SKILL.md +1 -1
- package/skills/api-services/references/speech.md +1 -2
- package/skills/api-telemetry/SKILL.md +2 -2
- package/skills/api-utils/SKILL.md +2 -2
- package/skills/code-simplifier/SKILL.md +47 -20
- package/skills/field-test/SKILL.md +93 -14
- package/skills/git-wrapup/SKILL.md +64 -27
- package/skills/orchestrations/SKILL.md +17 -6
- package/skills/orchestrations/workflows/field-test-fix.md +6 -4
- package/skills/orchestrations/workflows/fix-wrapup-release.md +6 -4
- package/skills/orchestrations/workflows/greenfield-build.md +2 -2
- package/skills/orchestrations/workflows/maintenance-release.md +4 -2
- package/skills/release-and-publish/SKILL.md +101 -23
- package/skills/release-pr-review/SKILL.md +147 -0
- package/templates/AGENTS.md +4 -2
- package/templates/CLAUDE.md +4 -2
- package/dist/mcp-server/transports/ITransport.d.ts +0 -15
- package/dist/mcp-server/transports/ITransport.d.ts.map +0 -1
- package/dist/mcp-server/transports/ITransport.js +0 -2
- package/dist/mcp-server/transports/ITransport.js.map +0 -1
- package/dist/services/llm/types.d.ts +0 -16
- package/dist/services/llm/types.d.ts.map +0 -1
- package/dist/services/llm/types.js +0 -9
- package/dist/services/llm/types.js.map +0 -1
- package/dist/utils/internal/health.d.ts +0 -60
- package/dist/utils/internal/health.d.ts.map +0 -1
- package/dist/utils/internal/health.js +0 -46
- package/dist/utils/internal/health.js.map +0 -1
|
@@ -50,28 +50,6 @@ function getActiveRequestsGauge() {
|
|
|
50
50
|
activeRequests ??= createUpDownCounter('mcp.requests.active', 'Number of in-flight tool, resource, and prompt handler executions', '{requests}');
|
|
51
51
|
return activeRequests;
|
|
52
52
|
}
|
|
53
|
-
/**
|
|
54
|
-
* @deprecated No longer needed. `globalThis.performance.now` is universally
|
|
55
|
-
* available on Node ≥24 and Bun ≥1.3. Kept as a no-op export to avoid a
|
|
56
|
-
* breaking change for consumers that call it during startup.
|
|
57
|
-
*/
|
|
58
|
-
export function loadPerfHooks() {
|
|
59
|
-
// performance is an ambient global declared by @types/node (perf_hooks.d.ts)
|
|
60
|
-
// and available in all supported environments (Node ≥24, Bun ≥1.3, workerd).
|
|
61
|
-
return Promise.resolve({ performance });
|
|
62
|
-
}
|
|
63
|
-
/**
|
|
64
|
-
* @deprecated No longer needed. `nowMs` now delegates directly to
|
|
65
|
-
* `globalThis.performance.now()`, which is universally available on Node ≥24
|
|
66
|
-
* and Bun ≥1.3. This function is a no-op and will be removed in a future
|
|
67
|
-
* major release.
|
|
68
|
-
*
|
|
69
|
-
* @returns A promise that resolves immediately.
|
|
70
|
-
*/
|
|
71
|
-
export function initHighResTimer(_perfLoader) {
|
|
72
|
-
// No-op: globalThis.performance.now is guaranteed on all supported floors.
|
|
73
|
-
return Promise.resolve();
|
|
74
|
-
}
|
|
75
53
|
/**
|
|
76
54
|
* Returns the current time in milliseconds using `globalThis.performance.now()`.
|
|
77
55
|
*
|
|
@@ -169,89 +147,40 @@ const toBytes = (payload) => {
|
|
|
169
147
|
}
|
|
170
148
|
}
|
|
171
149
|
};
|
|
172
|
-
// ==========================================================================
|
|
173
|
-
// Tool execution measurement
|
|
174
|
-
// ==========================================================================
|
|
175
|
-
/*
|
|
176
|
-
* Measured-region semantics, settled in #346 and shared by
|
|
177
|
-
* {@link measureToolExecution} and {@link measureResourceExecution}.
|
|
178
|
-
*
|
|
179
|
-
* The measured region spans everything that decides the client-visible
|
|
180
|
-
* outcome: the handler **and** the response pipeline that follows it
|
|
181
|
-
* (output-schema validation, `format()`, the enrichment merge and its trailer
|
|
182
|
-
* render). Telemetry that closed when the handler returned reported a
|
|
183
|
-
* successful call while the client was handed `isError: true`.
|
|
184
|
-
*
|
|
185
|
-
* Two consequences of that width:
|
|
186
|
-
*
|
|
187
|
-
* 1. `mcp.*.duration` covers validation, formatting, and the merge, not the
|
|
188
|
-
* handler alone. It is time-to-produce-the-result, which is what the
|
|
189
|
-
* caller waited for.
|
|
190
|
-
* 2. The callback's return value is the assembled client result, so it is no
|
|
191
|
-
* longer what `mcp.*.output_bytes` should measure — `content[]` re-renders
|
|
192
|
-
* the same data the structured payload carries, and counting both would
|
|
193
|
-
* silently redefine an existing series. Callers therefore designate the
|
|
194
|
-
* payload explicitly via the `recordOutput` argument, which also feeds
|
|
195
|
-
* partial-success detection. `output_bytes` keeps measuring the handler's
|
|
196
|
-
* returned domain value, unchanged from 0.12.2. When nothing is
|
|
197
|
-
* designated, the callback's return value is measured — the single-value
|
|
198
|
-
* form for callers with no assembly step.
|
|
199
|
-
*/
|
|
200
150
|
/**
|
|
201
|
-
*
|
|
202
|
-
*
|
|
203
|
-
*
|
|
204
|
-
*
|
|
205
|
-
*
|
|
206
|
-
*
|
|
207
|
-
*
|
|
208
|
-
* On failure the error is re-thrown after being recorded on the span and metrics;
|
|
209
|
-
* `McpError` instances surface their numeric `code` as the error code attribute.
|
|
210
|
-
* A failure anywhere in the callback — handler or response pipeline — is
|
|
211
|
-
* recorded, and no output-size histogram is emitted for it.
|
|
212
|
-
*
|
|
213
|
-
* @template T - The resolved type of the tool's return value.
|
|
214
|
-
* @param toolLogicFn - Async function containing the tool's business logic and
|
|
215
|
-
* the response assembly that follows it. Receives `context` re-bound to the
|
|
216
|
-
* execution span this function opens, so a handler context built from it
|
|
217
|
-
* correlates to the span the handler actually runs in rather than to the
|
|
218
|
-
* enclosing request span, plus `recordOutput` — call it with the handler's
|
|
219
|
-
* domain value to designate what `mcp.tool.output_bytes` and partial-success
|
|
220
|
-
* detection measure. Without a call, the callback's return value is measured.
|
|
221
|
-
* @param context - Request context extended with `toolName`; used for span/log correlation.
|
|
222
|
-
* @param inputPayload - The raw input object passed to the tool, serialized to compute byte size.
|
|
223
|
-
* @param successAttributes - Optional thunk evaluated after a successful run; its
|
|
224
|
-
* returned key/value map is set on the span as extra attributes. Lets callers
|
|
225
|
-
* attach post-hoc signals (e.g. `mcp.tool.enriched`) without coupling this
|
|
226
|
-
* function to their domain. Not called on the error path.
|
|
227
|
-
* @returns A promise that resolves with the tool's return value or rejects with the original error.
|
|
151
|
+
* Opens `<spanPrefix>:<name>`, runs `logic` inside it with `context` re-bound
|
|
152
|
+
* to that span, and settles the outcome the same way for every kind: an
|
|
153
|
+
* `input_required` signal is protocol control flow and counts as success
|
|
154
|
+
* (recording it as a failure would mark the span ERROR, count an error, and
|
|
155
|
+
* log `isSuccess: false` for every legitimate multi-round-trip request); an
|
|
156
|
+
* `McpError` surfaces its numeric code; anything else is `UNHANDLED_ERROR` or
|
|
157
|
+
* `UNKNOWN_ERROR`. The in-flight gauge and duration bracket the whole run.
|
|
228
158
|
*/
|
|
229
|
-
|
|
159
|
+
async function measure(kind, name, context, startAttributes, logic, hooks) {
|
|
230
160
|
const tracer = trace.getTracer(config.openTelemetry.serviceName, config.openTelemetry.serviceVersion);
|
|
231
|
-
|
|
232
|
-
return await tracer.startActiveSpan(`tool_execution:${toolName}`, async (span) => {
|
|
161
|
+
return await tracer.startActiveSpan(`${kind.spanPrefix}:${name}`, async (span) => {
|
|
233
162
|
// The span is active from here down, so everything below — the handler
|
|
234
|
-
// context the logic function builds and
|
|
235
|
-
//
|
|
236
|
-
//
|
|
163
|
+
// context the logic function builds and the completion log — correlates
|
|
164
|
+
// to this span rather than to whatever was active when the caller built
|
|
165
|
+
// `context`.
|
|
237
166
|
const spanContext = withActiveSpan(context);
|
|
238
167
|
const activeGauge = getActiveRequestsGauge();
|
|
239
168
|
activeGauge.add(1);
|
|
240
169
|
const t0 = nowMs();
|
|
241
|
-
const inputBytes = toBytes(inputPayload);
|
|
242
170
|
span.setAttributes({
|
|
243
|
-
[ATTR_CODE_FUNCTION_NAME]:
|
|
244
|
-
[ATTR_CODE_NAMESPACE]:
|
|
245
|
-
|
|
171
|
+
[ATTR_CODE_FUNCTION_NAME]: name,
|
|
172
|
+
[ATTR_CODE_NAMESPACE]: kind.namespace,
|
|
173
|
+
...startAttributes,
|
|
246
174
|
});
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
175
|
+
const outcome = {
|
|
176
|
+
durationMs: 0,
|
|
177
|
+
errorCategory: undefined,
|
|
178
|
+
errorCode: undefined,
|
|
179
|
+
inputRequired: false,
|
|
180
|
+
measuredOutput: undefined,
|
|
181
|
+
ok: false,
|
|
182
|
+
outputBytes: 0,
|
|
183
|
+
};
|
|
255
184
|
let designatedOutput;
|
|
256
185
|
let outputDesignated = false;
|
|
257
186
|
const recordOutput = (payload) => {
|
|
@@ -259,59 +188,29 @@ export async function measureToolExecution(toolLogicFn, context, inputPayload, s
|
|
|
259
188
|
outputDesignated = true;
|
|
260
189
|
};
|
|
261
190
|
try {
|
|
262
|
-
const result = await
|
|
263
|
-
ok = true;
|
|
264
|
-
|
|
265
|
-
outputBytes = toBytes(measuredOutput);
|
|
266
|
-
// Detect partial success: the measured payload contains a non-empty `failed` array.
|
|
267
|
-
// Convention-based — matches the batch response pattern recommended by the design skill.
|
|
268
|
-
if (measuredOutput != null &&
|
|
269
|
-
typeof measuredOutput === 'object' &&
|
|
270
|
-
!Array.isArray(measuredOutput)) {
|
|
271
|
-
const obj = measuredOutput;
|
|
272
|
-
if (Array.isArray(obj.failed) && obj.failed.length > 0) {
|
|
273
|
-
partialSuccess = true;
|
|
274
|
-
batchFailed = obj.failed.length;
|
|
275
|
-
if (Array.isArray(obj.succeeded))
|
|
276
|
-
batchSucceeded = obj.succeeded.length;
|
|
277
|
-
}
|
|
278
|
-
}
|
|
191
|
+
const result = await logic(spanContext, recordOutput);
|
|
192
|
+
outcome.ok = true;
|
|
193
|
+
outcome.measuredOutput = outputDesignated ? designatedOutput : result;
|
|
194
|
+
outcome.outputBytes = toBytes(outcome.measuredOutput);
|
|
279
195
|
span.setStatus({ code: SpanStatusCode.OK });
|
|
280
|
-
|
|
281
|
-
if (partialSuccess) {
|
|
282
|
-
span.setAttribute(ATTR_MCP_TOOL_PARTIAL_SUCCESS, true);
|
|
283
|
-
if (batchFailed !== undefined)
|
|
284
|
-
span.setAttribute(ATTR_MCP_TOOL_BATCH_FAILED, batchFailed);
|
|
285
|
-
if (batchSucceeded !== undefined)
|
|
286
|
-
span.setAttribute(ATTR_MCP_TOOL_BATCH_SUCCEEDED, batchSucceeded);
|
|
287
|
-
}
|
|
288
|
-
if (successAttributes) {
|
|
289
|
-
for (const [key, value] of Object.entries(successAttributes())) {
|
|
290
|
-
span.setAttribute(key, value);
|
|
291
|
-
}
|
|
292
|
-
}
|
|
196
|
+
hooks.onSuccess(span, outcome);
|
|
293
197
|
return result;
|
|
294
|
-
// `ctx.requestInput(...)` unwinds the handler as a thrown signal, but the
|
|
295
|
-
// round ended in `input_required` — protocol control flow, not a failure.
|
|
296
|
-
// Recording it as one would mark the span ERROR, increment the error
|
|
297
|
-
// counter, and log `isSuccess: false` for every legitimate
|
|
298
|
-
// multi-round-trip request.
|
|
299
198
|
}
|
|
300
199
|
catch (err) {
|
|
301
200
|
if (isInputRequiredSignal(err)) {
|
|
302
|
-
ok = true;
|
|
303
|
-
inputRequired = true;
|
|
201
|
+
outcome.ok = true;
|
|
202
|
+
outcome.inputRequired = true;
|
|
304
203
|
span.setStatus({ code: SpanStatusCode.OK });
|
|
305
|
-
span.setAttribute(
|
|
204
|
+
span.setAttribute(kind.attrs.inputRequired, true);
|
|
306
205
|
throw err;
|
|
307
206
|
}
|
|
308
207
|
if (err instanceof McpError) {
|
|
309
|
-
errorCode = String(err.code);
|
|
310
|
-
errorCategory = getErrorCategory(err.code);
|
|
208
|
+
outcome.errorCode = String(err.code);
|
|
209
|
+
outcome.errorCategory = getErrorCategory(err.code);
|
|
311
210
|
}
|
|
312
211
|
else {
|
|
313
|
-
errorCode = err instanceof Error ? 'UNHANDLED_ERROR' : 'UNKNOWN_ERROR';
|
|
314
|
-
errorCategory = 'server';
|
|
212
|
+
outcome.errorCode = err instanceof Error ? 'UNHANDLED_ERROR' : 'UNKNOWN_ERROR';
|
|
213
|
+
outcome.errorCategory = 'server';
|
|
315
214
|
}
|
|
316
215
|
if (err instanceof Error)
|
|
317
216
|
span.recordException(err);
|
|
@@ -323,16 +222,97 @@ export async function measureToolExecution(toolLogicFn, context, inputPayload, s
|
|
|
323
222
|
}
|
|
324
223
|
finally {
|
|
325
224
|
activeGauge.add(-1);
|
|
326
|
-
|
|
327
|
-
const durationMs = Math.round((t1 - t0) * 100) / 100;
|
|
225
|
+
outcome.durationMs = Math.round((nowMs() - t0) * 100) / 100;
|
|
328
226
|
span.setAttributes({
|
|
329
|
-
[
|
|
330
|
-
[
|
|
227
|
+
[kind.attrs.durationMs]: outcome.durationMs,
|
|
228
|
+
[kind.attrs.success]: outcome.ok,
|
|
331
229
|
});
|
|
332
|
-
if (errorCode)
|
|
333
|
-
span.setAttribute(
|
|
230
|
+
if (outcome.errorCode)
|
|
231
|
+
span.setAttribute(kind.attrs.errorCode, outcome.errorCode);
|
|
334
232
|
span.end();
|
|
335
|
-
|
|
233
|
+
hooks.onSettled(spanContext, outcome);
|
|
234
|
+
}
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
// ==========================================================================
|
|
238
|
+
// Tool execution measurement
|
|
239
|
+
// ==========================================================================
|
|
240
|
+
const TOOL_KIND = {
|
|
241
|
+
attrs: {
|
|
242
|
+
durationMs: ATTR_MCP_TOOL_DURATION_MS,
|
|
243
|
+
errorCode: ATTR_MCP_TOOL_ERROR_CODE,
|
|
244
|
+
inputRequired: ATTR_MCP_TOOL_INPUT_REQUIRED,
|
|
245
|
+
success: ATTR_MCP_TOOL_SUCCESS,
|
|
246
|
+
},
|
|
247
|
+
namespace: 'mcp-tools',
|
|
248
|
+
spanPrefix: 'tool_execution',
|
|
249
|
+
};
|
|
250
|
+
/**
|
|
251
|
+
* Convention-based partial-success detection: a measured payload carrying a
|
|
252
|
+
* non-empty `failed` array — the batch response shape the design skill
|
|
253
|
+
* recommends. `batchSucceeded` is reported only when a `succeeded` array sits
|
|
254
|
+
* beside it.
|
|
255
|
+
*/
|
|
256
|
+
function detectPartialSuccess(output) {
|
|
257
|
+
if (output == null || typeof output !== 'object' || Array.isArray(output))
|
|
258
|
+
return undefined;
|
|
259
|
+
const { failed, succeeded } = output;
|
|
260
|
+
if (!Array.isArray(failed) || failed.length === 0)
|
|
261
|
+
return undefined;
|
|
262
|
+
return {
|
|
263
|
+
batchFailed: failed.length,
|
|
264
|
+
batchSucceeded: Array.isArray(succeeded) ? succeeded.length : undefined,
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Wraps a tool's logic function with observability: an OpenTelemetry span,
|
|
269
|
+
* OTel metric counters/histogram, payload size capture, and structured log.
|
|
270
|
+
*
|
|
271
|
+
* On success the resolved value is passed through transparently. On failure
|
|
272
|
+
* the error is re-thrown after being recorded on the span and metrics;
|
|
273
|
+
* `McpError` instances surface their numeric `code` as the error code
|
|
274
|
+
* attribute. A failure anywhere in the callback — handler or response
|
|
275
|
+
* pipeline — is recorded, and no output-size histogram is emitted for it.
|
|
276
|
+
*
|
|
277
|
+
* @template T - The resolved type of the tool's return value.
|
|
278
|
+
* @param toolLogicFn - Async function containing the tool's business logic and
|
|
279
|
+
* the response assembly that follows it. Receives `context` re-bound to the
|
|
280
|
+
* execution span this function opens, so a handler context built from it
|
|
281
|
+
* correlates to the span the handler actually runs in rather than to the
|
|
282
|
+
* enclosing request span, plus `recordOutput` — call it with the handler's
|
|
283
|
+
* domain value to designate what `mcp.tool.output_bytes` and partial-success
|
|
284
|
+
* detection measure. Without a call, the callback's return value is measured.
|
|
285
|
+
* @param context - Request context extended with `toolName`; used for span/log correlation.
|
|
286
|
+
* @param inputPayload - The raw input object passed to the tool, serialized to compute byte size.
|
|
287
|
+
* @param successAttributes - Optional thunk evaluated after a successful run; its
|
|
288
|
+
* returned key/value map is set on the span as extra attributes. Lets callers
|
|
289
|
+
* attach post-hoc signals (e.g. `mcp.tool.enriched`) without coupling this
|
|
290
|
+
* function to their domain. Not called on the error path.
|
|
291
|
+
* @returns A promise that resolves with the tool's return value or rejects with the original error.
|
|
292
|
+
*/
|
|
293
|
+
export async function measureToolExecution(toolLogicFn, context, inputPayload, successAttributes) {
|
|
294
|
+
const { toolName } = context;
|
|
295
|
+
const inputBytes = toBytes(inputPayload);
|
|
296
|
+
let partial;
|
|
297
|
+
return await measure(TOOL_KIND, toolName, context, { [ATTR_MCP_TOOL_INPUT_BYTES]: inputBytes }, toolLogicFn, {
|
|
298
|
+
onSuccess: (span, outcome) => {
|
|
299
|
+
span.setAttribute(ATTR_MCP_TOOL_OUTPUT_BYTES, outcome.outputBytes);
|
|
300
|
+
partial = detectPartialSuccess(outcome.measuredOutput);
|
|
301
|
+
if (partial) {
|
|
302
|
+
span.setAttribute(ATTR_MCP_TOOL_PARTIAL_SUCCESS, true);
|
|
303
|
+
span.setAttribute(ATTR_MCP_TOOL_BATCH_FAILED, partial.batchFailed);
|
|
304
|
+
if (partial.batchSucceeded !== undefined) {
|
|
305
|
+
span.setAttribute(ATTR_MCP_TOOL_BATCH_SUCCEEDED, partial.batchSucceeded);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
if (successAttributes) {
|
|
309
|
+
for (const [key, value] of Object.entries(successAttributes())) {
|
|
310
|
+
span.setAttribute(key, value);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
},
|
|
314
|
+
onSettled: (spanContext, outcome) => {
|
|
315
|
+
const { durationMs, errorCategory, errorCode, inputRequired, ok, outputBytes } = outcome;
|
|
336
316
|
const m = getToolMetrics();
|
|
337
317
|
const metricAttrs = { [ATTR_MCP_TOOL_NAME]: toolName, [ATTR_MCP_TOOL_SUCCESS]: ok };
|
|
338
318
|
const toolAttrs = { [ATTR_MCP_TOOL_NAME]: toolName };
|
|
@@ -362,10 +342,14 @@ export async function measureToolExecution(toolLogicFn, context, inputPayload, s
|
|
|
362
342
|
inputBytes,
|
|
363
343
|
outputBytes,
|
|
364
344
|
...(inputRequired && { inputRequired }),
|
|
365
|
-
...(
|
|
345
|
+
...(partial && {
|
|
346
|
+
partialSuccess: true,
|
|
347
|
+
batchSucceeded: partial.batchSucceeded,
|
|
348
|
+
batchFailed: partial.batchFailed,
|
|
349
|
+
}),
|
|
366
350
|
},
|
|
367
351
|
}));
|
|
368
|
-
}
|
|
352
|
+
},
|
|
369
353
|
});
|
|
370
354
|
}
|
|
371
355
|
// ==========================================================================
|
|
@@ -382,10 +366,20 @@ function getResourceMetrics() {
|
|
|
382
366
|
resourceOutputBytes ??= createHistogram('mcp.resource.output_bytes', 'Resource output payload size', 'bytes');
|
|
383
367
|
return { resourceReadCounter, resourceReadDuration, resourceReadErrors, resourceOutputBytes };
|
|
384
368
|
}
|
|
369
|
+
const RESOURCE_KIND = {
|
|
370
|
+
attrs: {
|
|
371
|
+
durationMs: ATTR_MCP_RESOURCE_DURATION_MS,
|
|
372
|
+
errorCode: ATTR_MCP_RESOURCE_ERROR_CODE,
|
|
373
|
+
inputRequired: ATTR_MCP_RESOURCE_INPUT_REQUIRED,
|
|
374
|
+
success: ATTR_MCP_RESOURCE_SUCCESS,
|
|
375
|
+
},
|
|
376
|
+
namespace: 'mcp-resources',
|
|
377
|
+
spanPrefix: 'resource_read',
|
|
378
|
+
};
|
|
385
379
|
/**
|
|
386
380
|
* Wraps a resource handler with observability: OTel span, metric counters/histogram,
|
|
387
381
|
* and a structured log. Mirrors {@link measureToolExecution} but tuned for resource reads,
|
|
388
|
-
* including the measured-region semantics documented
|
|
382
|
+
* including the measured-region semantics documented above.
|
|
389
383
|
*
|
|
390
384
|
* @template T - The resolved type of the resource handler's return value.
|
|
391
385
|
* @param resourceLogicFn - Async function containing the resource handler and the
|
|
@@ -398,76 +392,13 @@ function getResourceMetrics() {
|
|
|
398
392
|
* @returns A promise that resolves with the handler's return value or rejects with the original error.
|
|
399
393
|
*/
|
|
400
394
|
export async function measureResourceExecution(resourceLogicFn, context, meta) {
|
|
401
|
-
const tracer = trace.getTracer(config.openTelemetry.serviceName, config.openTelemetry.serviceVersion);
|
|
402
395
|
const { resourceName } = context;
|
|
403
|
-
return await
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
span.setAttributes({
|
|
410
|
-
[ATTR_CODE_FUNCTION_NAME]: resourceName,
|
|
411
|
-
[ATTR_CODE_NAMESPACE]: 'mcp-resources',
|
|
412
|
-
[ATTR_MCP_RESOURCE_URI]: meta.uri,
|
|
413
|
-
[ATTR_MCP_RESOURCE_MIME_TYPE]: meta.mimeType,
|
|
414
|
-
});
|
|
415
|
-
let ok = false;
|
|
416
|
-
let inputRequired = false;
|
|
417
|
-
let errorCode;
|
|
418
|
-
let outputBytes = 0;
|
|
419
|
-
let designatedOutput;
|
|
420
|
-
let outputDesignated = false;
|
|
421
|
-
const recordOutput = (payload) => {
|
|
422
|
-
designatedOutput = payload;
|
|
423
|
-
outputDesignated = true;
|
|
424
|
-
};
|
|
425
|
-
try {
|
|
426
|
-
const result = await resourceLogicFn(spanContext, recordOutput);
|
|
427
|
-
ok = true;
|
|
428
|
-
outputBytes = toBytes(outputDesignated ? designatedOutput : result);
|
|
429
|
-
span.setStatus({ code: SpanStatusCode.OK });
|
|
430
|
-
span.setAttribute(ATTR_MCP_RESOURCE_SIZE_BYTES, outputBytes);
|
|
431
|
-
return result;
|
|
432
|
-
// `ctx.requestInput(...)` unwinds the handler as a thrown signal, but the
|
|
433
|
-
// round ended in `input_required` — protocol control flow, not a failure.
|
|
434
|
-
// Recording it as one would mark the span ERROR, increment the error
|
|
435
|
-
// counter, and log `isSuccess: false` for every legitimate
|
|
436
|
-
// multi-round-trip request.
|
|
437
|
-
}
|
|
438
|
-
catch (err) {
|
|
439
|
-
if (isInputRequiredSignal(err)) {
|
|
440
|
-
ok = true;
|
|
441
|
-
inputRequired = true;
|
|
442
|
-
span.setStatus({ code: SpanStatusCode.OK });
|
|
443
|
-
span.setAttribute(ATTR_MCP_RESOURCE_INPUT_REQUIRED, true);
|
|
444
|
-
throw err;
|
|
445
|
-
}
|
|
446
|
-
if (err instanceof McpError)
|
|
447
|
-
errorCode = String(err.code);
|
|
448
|
-
else if (err instanceof Error)
|
|
449
|
-
errorCode = 'UNHANDLED_ERROR';
|
|
450
|
-
else
|
|
451
|
-
errorCode = 'UNKNOWN_ERROR';
|
|
452
|
-
if (err instanceof Error)
|
|
453
|
-
span.recordException(err);
|
|
454
|
-
span.setStatus({
|
|
455
|
-
code: SpanStatusCode.ERROR,
|
|
456
|
-
message: err instanceof Error ? err.message : String(err),
|
|
457
|
-
});
|
|
458
|
-
throw err;
|
|
459
|
-
}
|
|
460
|
-
finally {
|
|
461
|
-
activeGauge.add(-1);
|
|
462
|
-
const t1 = nowMs();
|
|
463
|
-
const durationMs = Math.round((t1 - t0) * 100) / 100;
|
|
464
|
-
span.setAttributes({
|
|
465
|
-
[ATTR_MCP_RESOURCE_DURATION_MS]: durationMs,
|
|
466
|
-
[ATTR_MCP_RESOURCE_SUCCESS]: ok,
|
|
467
|
-
});
|
|
468
|
-
if (errorCode)
|
|
469
|
-
span.setAttribute(ATTR_MCP_RESOURCE_ERROR_CODE, errorCode);
|
|
470
|
-
span.end();
|
|
396
|
+
return await measure(RESOURCE_KIND, resourceName, context, { [ATTR_MCP_RESOURCE_URI]: meta.uri, [ATTR_MCP_RESOURCE_MIME_TYPE]: meta.mimeType }, resourceLogicFn, {
|
|
397
|
+
onSuccess: (span, outcome) => {
|
|
398
|
+
span.setAttribute(ATTR_MCP_RESOURCE_SIZE_BYTES, outcome.outputBytes);
|
|
399
|
+
},
|
|
400
|
+
onSettled: (spanContext, outcome) => {
|
|
401
|
+
const { durationMs, errorCode, inputRequired, ok, outputBytes } = outcome;
|
|
471
402
|
const m = getResourceMetrics();
|
|
472
403
|
const metricAttrs = {
|
|
473
404
|
[ATTR_MCP_RESOURCE_NAME]: resourceName,
|
|
@@ -492,7 +423,7 @@ export async function measureResourceExecution(resourceLogicFn, context, meta) {
|
|
|
492
423
|
mimeType: meta.mimeType,
|
|
493
424
|
},
|
|
494
425
|
}));
|
|
495
|
-
}
|
|
426
|
+
},
|
|
496
427
|
});
|
|
497
428
|
}
|
|
498
429
|
// ==========================================================================
|
|
@@ -520,14 +451,23 @@ function getPromptMetrics() {
|
|
|
520
451
|
promptMessageCount,
|
|
521
452
|
};
|
|
522
453
|
}
|
|
454
|
+
const PROMPT_KIND = {
|
|
455
|
+
attrs: {
|
|
456
|
+
durationMs: ATTR_MCP_PROMPT_DURATION_MS,
|
|
457
|
+
errorCode: ATTR_MCP_PROMPT_ERROR_CODE,
|
|
458
|
+
inputRequired: ATTR_MCP_PROMPT_INPUT_REQUIRED,
|
|
459
|
+
success: ATTR_MCP_PROMPT_SUCCESS,
|
|
460
|
+
},
|
|
461
|
+
namespace: 'mcp-prompts',
|
|
462
|
+
spanPrefix: 'prompt_generation',
|
|
463
|
+
};
|
|
523
464
|
/**
|
|
524
465
|
* Wraps a prompt generate function with observability: an OpenTelemetry span,
|
|
525
466
|
* OTel metric counters/histograms, payload size capture, and structured log.
|
|
526
467
|
*
|
|
527
|
-
* Prompts can
|
|
468
|
+
* Prompts can perform meaningful work (conditional logic, async data fetches,
|
|
528
469
|
* multi-message assembly), so they get the same instrumentation depth as tools
|
|
529
|
-
* and resources.
|
|
530
|
-
* {@link measureResourceExecution}.
|
|
470
|
+
* and resources.
|
|
531
471
|
*
|
|
532
472
|
* @template T - The resolved type of the prompt generate function's return value.
|
|
533
473
|
* @param promptLogicFn - Zero-argument async function containing the prompt's generate logic.
|
|
@@ -536,79 +476,18 @@ function getPromptMetrics() {
|
|
|
536
476
|
* @returns A promise that resolves with the generate result or rejects with the original error.
|
|
537
477
|
*/
|
|
538
478
|
export async function measurePromptGeneration(promptLogicFn, context, inputPayload) {
|
|
539
|
-
const tracer = trace.getTracer(config.openTelemetry.serviceName, config.openTelemetry.serviceVersion);
|
|
540
479
|
const { promptName } = context;
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
const t0 = nowMs();
|
|
549
|
-
const inputBytes = toBytes(inputPayload);
|
|
550
|
-
span.setAttributes({
|
|
551
|
-
[ATTR_CODE_FUNCTION_NAME]: promptName,
|
|
552
|
-
[ATTR_CODE_NAMESPACE]: 'mcp-prompts',
|
|
553
|
-
[ATTR_MCP_PROMPT_INPUT_BYTES]: inputBytes,
|
|
554
|
-
});
|
|
555
|
-
let ok = false;
|
|
556
|
-
let inputRequired = false;
|
|
557
|
-
let errorCode;
|
|
558
|
-
let errorCategory;
|
|
559
|
-
let outputBytes = 0;
|
|
560
|
-
let messageCount = 0;
|
|
561
|
-
try {
|
|
562
|
-
const result = await promptLogicFn();
|
|
563
|
-
ok = true;
|
|
564
|
-
outputBytes = toBytes(result);
|
|
565
|
-
if (Array.isArray(result))
|
|
566
|
-
messageCount = result.length;
|
|
567
|
-
span.setStatus({ code: SpanStatusCode.OK });
|
|
568
|
-
span.setAttribute(ATTR_MCP_PROMPT_OUTPUT_BYTES, outputBytes);
|
|
480
|
+
const inputBytes = toBytes(inputPayload);
|
|
481
|
+
let messageCount = 0;
|
|
482
|
+
return await measure(PROMPT_KIND, promptName, context, { [ATTR_MCP_PROMPT_INPUT_BYTES]: inputBytes }, promptLogicFn, {
|
|
483
|
+
onSuccess: (span, outcome) => {
|
|
484
|
+
if (Array.isArray(outcome.measuredOutput))
|
|
485
|
+
messageCount = outcome.measuredOutput.length;
|
|
486
|
+
span.setAttribute(ATTR_MCP_PROMPT_OUTPUT_BYTES, outcome.outputBytes);
|
|
569
487
|
span.setAttribute(ATTR_MCP_PROMPT_MESSAGE_COUNT, messageCount);
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
// Recording it as one would mark the span ERROR, increment the error
|
|
574
|
-
// counter, and log `isSuccess: false` for every legitimate
|
|
575
|
-
// multi-round-trip request.
|
|
576
|
-
}
|
|
577
|
-
catch (err) {
|
|
578
|
-
if (isInputRequiredSignal(err)) {
|
|
579
|
-
ok = true;
|
|
580
|
-
inputRequired = true;
|
|
581
|
-
span.setStatus({ code: SpanStatusCode.OK });
|
|
582
|
-
span.setAttribute(ATTR_MCP_PROMPT_INPUT_REQUIRED, true);
|
|
583
|
-
throw err;
|
|
584
|
-
}
|
|
585
|
-
if (err instanceof McpError) {
|
|
586
|
-
errorCode = String(err.code);
|
|
587
|
-
errorCategory = getErrorCategory(err.code);
|
|
588
|
-
}
|
|
589
|
-
else {
|
|
590
|
-
errorCode = err instanceof Error ? 'UNHANDLED_ERROR' : 'UNKNOWN_ERROR';
|
|
591
|
-
errorCategory = 'server';
|
|
592
|
-
}
|
|
593
|
-
if (err instanceof Error)
|
|
594
|
-
span.recordException(err);
|
|
595
|
-
span.setStatus({
|
|
596
|
-
code: SpanStatusCode.ERROR,
|
|
597
|
-
message: err instanceof Error ? err.message : String(err),
|
|
598
|
-
});
|
|
599
|
-
throw err;
|
|
600
|
-
}
|
|
601
|
-
finally {
|
|
602
|
-
activeGauge.add(-1);
|
|
603
|
-
const t1 = nowMs();
|
|
604
|
-
const durationMs = Math.round((t1 - t0) * 100) / 100;
|
|
605
|
-
span.setAttributes({
|
|
606
|
-
[ATTR_MCP_PROMPT_DURATION_MS]: durationMs,
|
|
607
|
-
[ATTR_MCP_PROMPT_SUCCESS]: ok,
|
|
608
|
-
});
|
|
609
|
-
if (errorCode)
|
|
610
|
-
span.setAttribute(ATTR_MCP_PROMPT_ERROR_CODE, errorCode);
|
|
611
|
-
span.end();
|
|
488
|
+
},
|
|
489
|
+
onSettled: (spanContext, outcome) => {
|
|
490
|
+
const { durationMs, errorCategory, errorCode, inputRequired, ok, outputBytes } = outcome;
|
|
612
491
|
const m = getPromptMetrics();
|
|
613
492
|
const metricAttrs = { [ATTR_MCP_PROMPT_NAME]: promptName, [ATTR_MCP_PROMPT_SUCCESS]: ok };
|
|
614
493
|
const promptAttrs = { [ATTR_MCP_PROMPT_NAME]: promptName };
|
|
@@ -626,10 +505,9 @@ export async function measurePromptGeneration(promptLogicFn, context, inputPaylo
|
|
|
626
505
|
});
|
|
627
506
|
}
|
|
628
507
|
const logFn = ok ? logger.info : logger.error;
|
|
629
|
-
|
|
508
|
+
logFn.call(logger, ok
|
|
630
509
|
? TELEMETRY_LOG_MESSAGES.promptGenerationFinished
|
|
631
|
-
: TELEMETRY_LOG_MESSAGES.promptGenerationFailed
|
|
632
|
-
logFn.call(logger, promptMessage, withExtra(spanContext, {
|
|
510
|
+
: TELEMETRY_LOG_MESSAGES.promptGenerationFailed, withExtra(spanContext, {
|
|
633
511
|
promptName,
|
|
634
512
|
metrics: {
|
|
635
513
|
durationMs,
|
|
@@ -641,7 +519,7 @@ export async function measurePromptGeneration(promptLogicFn, context, inputPaylo
|
|
|
641
519
|
...(inputRequired && { inputRequired }),
|
|
642
520
|
},
|
|
643
521
|
}));
|
|
644
|
-
}
|
|
522
|
+
},
|
|
645
523
|
});
|
|
646
524
|
}
|
|
647
525
|
//# sourceMappingURL=performance.js.map
|