agents 0.20.0 → 0.20.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{agent-tool-types-Btk9ETS-.d.ts → agent-tool-types-BC-WFlsz.d.ts} +30 -45
- package/dist/agent-tool-types.d.ts +1 -1
- package/dist/{agent-tools-UuScsJg3.d.ts → agent-tools-DeHe9Xov.d.ts} +2 -2
- package/dist/agent-tools.d.ts +1 -1
- package/dist/chat/index.d.ts +2 -2
- package/dist/chat-sdk/index.d.ts +1 -1
- package/dist/client.d.ts +1 -1
- package/dist/cloudflare-BduZwmYK.js +204 -0
- package/dist/cloudflare-BduZwmYK.js.map +1 -0
- package/dist/{handler-stateless-8hQN_kC3.js → handler-stateless-CIkKPETH.js} +20 -69
- package/dist/handler-stateless-CIkKPETH.js.map +1 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.js +27 -18
- package/dist/index.js.map +1 -1
- package/dist/mcp/client.d.ts +1 -1
- package/dist/mcp/index.d.ts +1 -1
- package/dist/mcp/index.js +32 -98
- package/dist/mcp/index.js.map +1 -1
- package/dist/mcp/server.js +1 -1
- package/dist/observability/ai/index.d.ts +9 -1
- package/dist/observability/ai/index.js +188 -63
- package/dist/observability/ai/index.js.map +1 -1
- package/dist/react.d.ts +1 -1
- package/dist/serializable.d.ts +1 -1
- package/dist/sub-routing.d.ts +1 -1
- package/dist/workflows.d.ts +1 -1
- package/docs/mcp-client.md +1 -1
- package/docs/mcp-servers.md +1 -1
- package/docs/observability.md +2 -1
- package/package.json +7 -7
- package/dist/cloudflare-BldFV0Pa.js +0 -117
- package/dist/cloudflare-BldFV0Pa.js.map +0 -1
- package/dist/handler-stateless-8hQN_kC3.js.map +0 -1
|
@@ -100,6 +100,33 @@ import {
|
|
|
100
100
|
} from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
101
101
|
import { AuthInfo } from "@modelcontextprotocol/sdk/server/auth/types.js";
|
|
102
102
|
|
|
103
|
+
//#region src/observability/tracing/tracer.d.ts
|
|
104
|
+
type InvocationScopeOptions = {
|
|
105
|
+
/**
|
|
106
|
+
* Open a scope even inside a live one, for work deliberately detached from
|
|
107
|
+
* the handler that started it — `ctx.waitUntil` bodies, queue drains — which
|
|
108
|
+
* runs on past that handler and must not be cut off with it.
|
|
109
|
+
*/
|
|
110
|
+
readonly detached?: boolean;
|
|
111
|
+
};
|
|
112
|
+
/**
|
|
113
|
+
* Runs `body` as one traced invocation.
|
|
114
|
+
*
|
|
115
|
+
* Work that escapes its native invocation cannot be traced from the context it
|
|
116
|
+
* started in: the still-open span is force-closed against the invocation that
|
|
117
|
+
* owned that context, which reports a negative duration or `span_not_ended`.
|
|
118
|
+
* Spans opened with {@link SpanLifetime.boundToInvocation} inside this scope
|
|
119
|
+
* are therefore closed before `body` settles — but not one moment earlier, so
|
|
120
|
+
* everything that completes during the invocation (the normal case: a chat
|
|
121
|
+
* turn is awaited by the handler that received it) still records its finish
|
|
122
|
+
* attributes. A span truncated this way is marked
|
|
123
|
+
* `cloudflare.agents.span.truncated` rather than passing as complete.
|
|
124
|
+
*/
|
|
125
|
+
declare function withInvocationScope<T>(
|
|
126
|
+
body: () => T,
|
|
127
|
+
options?: InvocationScopeOptions
|
|
128
|
+
): T;
|
|
129
|
+
//#endregion
|
|
103
130
|
//#region src/sub-routing.d.ts
|
|
104
131
|
/**
|
|
105
132
|
* URL segment marking a parent↔child boundary.
|
|
@@ -281,19 +308,6 @@ declare class WorkerTransport extends WebStandardStreamableHTTPServerTransport$1
|
|
|
281
308
|
private _capturedInitializeParams?;
|
|
282
309
|
private _userOnSessionInitialized?;
|
|
283
310
|
private _bridgeInstalled;
|
|
284
|
-
/**
|
|
285
|
-
* Tracks keepalive interval cleanups so we can fire them eagerly when the
|
|
286
|
-
* SDK closes the underlying SSE stream via `closeSSEStream(requestId)` or
|
|
287
|
-
* `closeStandaloneSSEStream()`. Keyed by the JSON-RPC request id that
|
|
288
|
-
* triggered the stream, or the sentinel for the standalone GET stream.
|
|
289
|
-
*/
|
|
290
|
-
private readonly _keepaliveCleanups;
|
|
291
|
-
/**
|
|
292
|
-
* Most recent JSON-RPC request id seen on an incoming POST. Used to key
|
|
293
|
-
* keepalive cleanups when the response is an SSE stream tied to that
|
|
294
|
-
* request (so `closeSSEStream(id)` can find and clear the interval).
|
|
295
|
-
*/
|
|
296
|
-
private _pendingRequestId?;
|
|
297
311
|
/**
|
|
298
312
|
* Request ids whose SSE stream was deliberately torn down via
|
|
299
313
|
* `closeSSEStream`. The SDK's `send()` throws "No connection established"
|
|
@@ -314,8 +328,7 @@ declare class WorkerTransport extends WebStandardStreamableHTTPServerTransport$1
|
|
|
314
328
|
/**
|
|
315
329
|
* Top-level request entry point. Handles CORS preflight, restores any
|
|
316
330
|
* persisted state on first invocation, then delegates to the SDK transport
|
|
317
|
-
* and finally appends CORS headers
|
|
318
|
-
* back.
|
|
331
|
+
* and finally appends CORS headers to whatever response comes back.
|
|
319
332
|
*/
|
|
320
333
|
handleRequest(
|
|
321
334
|
request: Request,
|
|
@@ -331,7 +344,6 @@ declare class WorkerTransport extends WebStandardStreamableHTTPServerTransport$1
|
|
|
331
344
|
*/
|
|
332
345
|
private normalizeAllowHeader;
|
|
333
346
|
closeSSEStream(requestId: RequestId): void;
|
|
334
|
-
closeStandaloneSSEStream(): void;
|
|
335
347
|
close(): Promise<void>;
|
|
336
348
|
/**
|
|
337
349
|
* Swallow two classes of message that would otherwise surface as
|
|
@@ -356,34 +368,6 @@ declare class WorkerTransport extends WebStandardStreamableHTTPServerTransport$1
|
|
|
356
368
|
message: JSONRPCMessage$1,
|
|
357
369
|
options?: TransportSendOptions$1
|
|
358
370
|
): Promise<void>;
|
|
359
|
-
/**
|
|
360
|
-
* If the response is an SSE stream, tee the body through a TransformStream
|
|
361
|
-
* that injects a `: keepalive\n\n` comment frame every 25s. The interval
|
|
362
|
-
* is cleared when the wrapped stream closes — which happens both when the
|
|
363
|
-
* SDK ends the underlying stream naturally and when `closeSSEStream` is
|
|
364
|
-
* called.
|
|
365
|
-
*
|
|
366
|
-
* Keepalive policy:
|
|
367
|
-
* - POST response streams (`key` is a request id): always keepalive.
|
|
368
|
-
* In-progress tool calls have no recovery path — if the stream drops
|
|
369
|
-
* mid-execution the result is lost — so we keep it under the
|
|
370
|
-
* Cloudflare edge ~5min idle watchdog.
|
|
371
|
-
* - Standalone GET stream (`key === "_standalone"`): keepalive only
|
|
372
|
-
* when no `eventStore` is configured. When resumability is enabled,
|
|
373
|
-
* clients reconnect with `Last-Event-ID` after an idle drop, so we
|
|
374
|
-
* skip the keepalive and let the DO hibernate.
|
|
375
|
-
*
|
|
376
|
-
* Uses the shared `sse-keepalive` constants so both this wrapper and
|
|
377
|
-
* `McpAgent.serve()` write identical frames at the same cadence.
|
|
378
|
-
* See cloudflare/agents#1583.
|
|
379
|
-
*/
|
|
380
|
-
private withKeepalive;
|
|
381
|
-
/**
|
|
382
|
-
* Does the SDK transport have an `eventStore`? Reaches into the SDK's
|
|
383
|
-
* private field because the option isn't surfaced on the public API —
|
|
384
|
-
* we only need a yes/no for keepalive policy.
|
|
385
|
-
*/
|
|
386
|
-
private eventStoreConfigured;
|
|
387
371
|
private getCorsHeaders;
|
|
388
372
|
private withCorsHeaders;
|
|
389
373
|
private installOnSessionInitializedBridge;
|
|
@@ -6109,6 +6093,7 @@ export {
|
|
|
6109
6093
|
createLegacyMcpHandler as en,
|
|
6110
6094
|
Schedule as et,
|
|
6111
6095
|
AgentToolProgress as f,
|
|
6096
|
+
withInvocationScope as fn,
|
|
6112
6097
|
getAgentByName as ft,
|
|
6113
6098
|
AgentToolRunPart as g,
|
|
6114
6099
|
unstable_callable as gt,
|
|
@@ -6159,4 +6144,4 @@ export {
|
|
|
6159
6144
|
EmailRoutingOptions as z,
|
|
6160
6145
|
RPCClientTransportOptions as zt
|
|
6161
6146
|
};
|
|
6162
|
-
//# sourceMappingURL=agent-tool-types-
|
|
6147
|
+
//# sourceMappingURL=agent-tool-types-BC-WFlsz.d.ts.map
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
o as AgentToolEventMessage,
|
|
5
5
|
s as AgentToolEventState,
|
|
6
6
|
y as AgentToolStoredChunk
|
|
7
|
-
} from "./agent-tool-types-
|
|
7
|
+
} from "./agent-tool-types-BC-WFlsz.js";
|
|
8
8
|
|
|
9
9
|
//#region src/chat/agent-tools.d.ts
|
|
10
10
|
type AgentToolProgressEmitResult = "emitted" | "coalesced" | "inactive";
|
|
@@ -130,4 +130,4 @@ export {
|
|
|
130
130
|
interceptAgentToolBroadcast as s,
|
|
131
131
|
AgentToolBroadcastHooks as t
|
|
132
132
|
};
|
|
133
|
-
//# sourceMappingURL=agent-tools-
|
|
133
|
+
//# sourceMappingURL=agent-tools-DeHe9Xov.d.ts.map
|
package/dist/agent-tools.d.ts
CHANGED
package/dist/chat/index.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
a as AgentToolEvent,
|
|
5
5
|
o as AgentToolEventMessage,
|
|
6
6
|
s as AgentToolEventState
|
|
7
|
-
} from "../agent-tool-types-
|
|
7
|
+
} from "../agent-tool-types-BC-WFlsz.js";
|
|
8
8
|
import {
|
|
9
9
|
n as ClientToolSchema,
|
|
10
10
|
r as createToolsFromClientSchemas,
|
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
r as AgentToolProgressEmitResult,
|
|
19
19
|
s as interceptAgentToolBroadcast,
|
|
20
20
|
t as AgentToolBroadcastHooks
|
|
21
|
-
} from "../agent-tools-
|
|
21
|
+
} from "../agent-tools-DeHe9Xov.js";
|
|
22
22
|
import { JSONSchema7, UIMessage } from "ai";
|
|
23
23
|
import { Connection } from "agents";
|
|
24
24
|
|
package/dist/chat-sdk/index.d.ts
CHANGED
package/dist/client.d.ts
CHANGED
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import { i as _classPrivateFieldInitSpec, n as _classPrivateFieldSet2, t as _classPrivateFieldGet2 } from "./classPrivateFieldGet2-DZBYAB34.js";
|
|
2
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
3
|
+
import * as cloudflareWorkers from "cloudflare:workers";
|
|
4
|
+
//#region src/observability/tracing/tracer.ts
|
|
5
|
+
/**
|
|
6
|
+
* Spans that asked to be invocation-bounded while a scope was active. Closed
|
|
7
|
+
* when that scope ends; see {@link withInvocationScope}.
|
|
8
|
+
*/
|
|
9
|
+
const invocationScope = new AsyncLocalStorage();
|
|
10
|
+
/**
|
|
11
|
+
* Runs `body` as one traced invocation.
|
|
12
|
+
*
|
|
13
|
+
* Work that escapes its native invocation cannot be traced from the context it
|
|
14
|
+
* started in: the still-open span is force-closed against the invocation that
|
|
15
|
+
* owned that context, which reports a negative duration or `span_not_ended`.
|
|
16
|
+
* Spans opened with {@link SpanLifetime.boundToInvocation} inside this scope
|
|
17
|
+
* are therefore closed before `body` settles — but not one moment earlier, so
|
|
18
|
+
* everything that completes during the invocation (the normal case: a chat
|
|
19
|
+
* turn is awaited by the handler that received it) still records its finish
|
|
20
|
+
* attributes. A span truncated this way is marked
|
|
21
|
+
* `cloudflare.agents.span.truncated` rather than passing as complete.
|
|
22
|
+
*/
|
|
23
|
+
function withInvocationScope(body, options) {
|
|
24
|
+
const current = invocationScope.getStore();
|
|
25
|
+
if (options?.detached !== true && current !== void 0 && !current.ended) return body();
|
|
26
|
+
const scope = {
|
|
27
|
+
ended: false,
|
|
28
|
+
open: /* @__PURE__ */ new Set()
|
|
29
|
+
};
|
|
30
|
+
const endInvocation = () => {
|
|
31
|
+
scope.ended = true;
|
|
32
|
+
for (const span of scope.open) try {
|
|
33
|
+
span.truncate();
|
|
34
|
+
} catch {}
|
|
35
|
+
scope.open.clear();
|
|
36
|
+
};
|
|
37
|
+
return invocationScope.run(scope, () => {
|
|
38
|
+
let result;
|
|
39
|
+
try {
|
|
40
|
+
result = body();
|
|
41
|
+
} catch (cause) {
|
|
42
|
+
endInvocation();
|
|
43
|
+
throw cause;
|
|
44
|
+
}
|
|
45
|
+
if (isPromiseLike(result)) return Promise.resolve(result).finally(endInvocation);
|
|
46
|
+
endInvocation();
|
|
47
|
+
return result;
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
/** Creates a tracer from a runtime span capability. */
|
|
51
|
+
function createTracer(runtime) {
|
|
52
|
+
return new RuntimeTracer(runtime);
|
|
53
|
+
}
|
|
54
|
+
var RuntimeTracer = class {
|
|
55
|
+
constructor(runtime) {
|
|
56
|
+
this.runtime = runtime;
|
|
57
|
+
}
|
|
58
|
+
withSpan(name, attributes, run, lifetime) {
|
|
59
|
+
return this.activate(name, attributes, (span) => {
|
|
60
|
+
const outOfBand = lifetime?.boundToInvocation === true && bindToInvocation(span);
|
|
61
|
+
const result = run(span);
|
|
62
|
+
if (isPromiseLike(result)) {
|
|
63
|
+
if (outOfBand) span.truncate();
|
|
64
|
+
return Promise.resolve(result).catch((cause) => {
|
|
65
|
+
span.fail(cause);
|
|
66
|
+
throw cause;
|
|
67
|
+
}).finally(() => {
|
|
68
|
+
span.close();
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
if (outOfBand) span.truncate();
|
|
72
|
+
span.close();
|
|
73
|
+
return result;
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
openSpan(name, attributes, activate, lifetime) {
|
|
77
|
+
if (!lifetime?.boundToInvocation) return this.activate(name, attributes, activate);
|
|
78
|
+
return this.activate(name, attributes, (span) => {
|
|
79
|
+
const invocationEnded = bindToInvocation(span);
|
|
80
|
+
try {
|
|
81
|
+
return activate(span);
|
|
82
|
+
} finally {
|
|
83
|
+
if (invocationEnded) span.truncate();
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Shared scaffold: opens an active span, seeds its attributes, and fails the
|
|
89
|
+
* span on a thrown defect before rethrowing. The `body` decides the span's
|
|
90
|
+
* finishing policy (managed vs. caller-owned).
|
|
91
|
+
*/
|
|
92
|
+
activate(name, attributes, body) {
|
|
93
|
+
return this.runtime.startActiveSpan(name, (writer) => {
|
|
94
|
+
setAttributes(writer, attributes);
|
|
95
|
+
const span = new ManagedSpan(writer);
|
|
96
|
+
try {
|
|
97
|
+
return body(span);
|
|
98
|
+
} catch (cause) {
|
|
99
|
+
span.fail(cause);
|
|
100
|
+
throw cause;
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
var _closed = /* @__PURE__ */ new WeakMap();
|
|
106
|
+
var ManagedSpan = class {
|
|
107
|
+
constructor(span) {
|
|
108
|
+
this.span = span;
|
|
109
|
+
_classPrivateFieldInitSpec(this, _closed, false);
|
|
110
|
+
}
|
|
111
|
+
get isTraced() {
|
|
112
|
+
return this.span.isTraced;
|
|
113
|
+
}
|
|
114
|
+
/** INTERNAL: see {@link writeSpanAttributes}. */
|
|
115
|
+
writeAttributes(attributes) {
|
|
116
|
+
if (_classPrivateFieldGet2(_closed, this)) return;
|
|
117
|
+
setAttributes(this.span, attributes);
|
|
118
|
+
}
|
|
119
|
+
finish(attributes = {}) {
|
|
120
|
+
if (_classPrivateFieldGet2(_closed, this)) return;
|
|
121
|
+
setAttributes(this.span, attributes);
|
|
122
|
+
this.close();
|
|
123
|
+
}
|
|
124
|
+
fail(cause) {
|
|
125
|
+
if (_classPrivateFieldGet2(_closed, this)) return;
|
|
126
|
+
if (isCancellation(cause)) setAttributes(this.span, { "cloudflare.agents.canceled": true });
|
|
127
|
+
else setAttributes(this.span, { "error.type": cause instanceof Error ? cause.name || "Error" : typeof cause });
|
|
128
|
+
this.close();
|
|
129
|
+
}
|
|
130
|
+
close() {
|
|
131
|
+
if (_classPrivateFieldGet2(_closed, this)) return;
|
|
132
|
+
_classPrivateFieldSet2(_closed, this, true);
|
|
133
|
+
this.span.end();
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Closes a span whose work has not finished because its invocation is ending.
|
|
137
|
+
* The marker distinguishes "this span has no tokens because the turn escaped
|
|
138
|
+
* its invocation" from "this span completed and reported none".
|
|
139
|
+
*/
|
|
140
|
+
truncate() {
|
|
141
|
+
if (_classPrivateFieldGet2(_closed, this)) return;
|
|
142
|
+
setAttributes(this.span, { "cloudflare.agents.span.truncated": true });
|
|
143
|
+
this.close();
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
/**
|
|
147
|
+
* Registers a span for closure at the end of the current invocation, and
|
|
148
|
+
* reports whether that invocation has already ended.
|
|
149
|
+
*
|
|
150
|
+
* Outside any scope the span keeps its natural lifetime: with no known
|
|
151
|
+
* invocation boundary there is nothing to bound it to, and closing early would
|
|
152
|
+
* discard finish attributes for no gain. Inside a scope that has already
|
|
153
|
+
* ended — work resumed later while still carrying this context — the span
|
|
154
|
+
* cannot outlive an invocation that is already gone, so the caller truncates
|
|
155
|
+
* it as soon as it has written what it knows.
|
|
156
|
+
*/
|
|
157
|
+
function bindToInvocation(span) {
|
|
158
|
+
const scope = invocationScope.getStore();
|
|
159
|
+
if (scope === void 0) return false;
|
|
160
|
+
if (scope.ended) return true;
|
|
161
|
+
scope.open.add(span);
|
|
162
|
+
return false;
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* INTERNAL: writes attributes onto an open managed span. Lets instrumentation
|
|
166
|
+
* defer expensive attribute computation until after the isTraced check (span
|
|
167
|
+
* names must exist at open time; attributes need not). Not part of the public
|
|
168
|
+
* barrel surface.
|
|
169
|
+
*/
|
|
170
|
+
function writeSpanAttributes(span, attributes) {
|
|
171
|
+
if (span instanceof ManagedSpan) span.writeAttributes(attributes);
|
|
172
|
+
}
|
|
173
|
+
function setAttributes(span, attributes) {
|
|
174
|
+
if (!span.isTraced) return;
|
|
175
|
+
try {
|
|
176
|
+
for (const [key, value] of Object.entries(attributes)) if (value !== void 0) span.setAttribute(key, value);
|
|
177
|
+
} catch {}
|
|
178
|
+
}
|
|
179
|
+
function isPromiseLike(value) {
|
|
180
|
+
return value !== null && value !== void 0 && (typeof value === "object" || typeof value === "function") && "then" in value && typeof value.then === "function";
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Recognizes caller/runtime cancellation (an `AbortError`, e.g. from an aborted
|
|
184
|
+
* `AbortSignal`) so it can be classified separately from genuine failures. A
|
|
185
|
+
* `DOMException` named `AbortError` is not always an `Error` instance, so this
|
|
186
|
+
* probes the `name` field structurally rather than via `instanceof`.
|
|
187
|
+
*/
|
|
188
|
+
function isCancellation(cause) {
|
|
189
|
+
return typeof cause === "object" && cause !== null && "name" in cause && cause.name === "AbortError";
|
|
190
|
+
}
|
|
191
|
+
//#endregion
|
|
192
|
+
//#region src/observability/tracing/cloudflare.ts
|
|
193
|
+
const noopSpan = {
|
|
194
|
+
isTraced: false,
|
|
195
|
+
setAttribute() {},
|
|
196
|
+
end() {}
|
|
197
|
+
};
|
|
198
|
+
const tracer = createTracer(cloudflareWorkers.tracing ?? { startActiveSpan(_name, run) {
|
|
199
|
+
return run(noopSpan);
|
|
200
|
+
} });
|
|
201
|
+
//#endregion
|
|
202
|
+
export { withInvocationScope as n, writeSpanAttributes as r, tracer as t };
|
|
203
|
+
|
|
204
|
+
//# sourceMappingURL=cloudflare-BduZwmYK.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cloudflare-BduZwmYK.js","names":[],"sources":["../src/observability/tracing/tracer.ts","../src/observability/tracing/cloudflare.ts"],"sourcesContent":["import { AsyncLocalStorage } from \"node:async_hooks\";\n\n/** Attribute values accepted by custom spans. */\nexport type TraceAttributeValue = string | number | boolean | undefined;\n\n/** Initial or finish attributes attached to a span. */\nexport type TraceAttributes = Readonly<Record<string, TraceAttributeValue>>;\n\n/** A value that may complete synchronously or through a promise-like result. */\nexport type MaybePromise<T> = T | PromiseLike<T>;\n\n/** Minimal runtime span surface used by tracers. */\nexport type SpanWriter = {\n readonly isTraced: boolean;\n setAttribute(key: string, value: TraceAttributeValue): void;\n end(): void;\n};\n\n/** Runtime capability for starting an active span in the current async context. */\nexport type SpanRuntime = {\n startActiveSpan<T>(name: string, run: (span: SpanWriter) => T): T;\n};\n\n/** Optional automatic lifetime policy for invocation-bounded spans. */\nexport type SpanLifetime = {\n /**\n * Close the span no later than the end of the surrounding\n * {@link withInvocationScope}, so it cannot outlive the native invocation\n * that owns its tracing context. Ignored outside such a scope.\n */\n readonly boundToInvocation?: boolean;\n};\n\n/** AgentTracer seam used by integrations. */\nexport type AgentTracer = {\n /**\n * Runs `run` inside an active span whose lifetime the tracer owns: the span\n * finishes when `run` returns (or its promise resolves) and fails when `run`\n * throws or rejects. Callers do not call {@link AgentSpan.finish}/{@link AgentSpan.fail};\n * doing so early is safe but the tracer guarantees closure.\n *\n * @template T The value produced by the instrumented work.\n */\n withSpan<T>(\n name: string,\n attributes: TraceAttributes,\n run: (span: AgentSpan) => MaybePromise<T>,\n lifetime?: SpanLifetime\n ): T | Promise<T>;\n /**\n * Activates a span and returns whatever `activate` returns (typically the\n * {@link AgentSpan} handle itself). The caller owns the span lifetime and MUST call\n * {@link AgentSpan.finish} or {@link AgentSpan.fail}; an unfinished span leaks. Use this\n * for work that outlives the callback, such as streams and event-driven\n * telemetry. A throw from `activate` still fails the span before rethrowing.\n *\n * @template T The value returned to the caller, usually the span handle.\n */\n openSpan<T>(\n name: string,\n attributes: TraceAttributes,\n activate: (span: AgentSpan) => T,\n lifetime?: SpanLifetime\n ): T;\n};\n\n/** Active span handle passed to instrumented work. */\nexport type AgentSpan = {\n /**\n * Whether this invocation is actually being traced. Instrumentation can use\n * this to skip expensive capture work when nobody is listening.\n */\n readonly isTraced: boolean;\n /** Records the optional finish attributes and ends the span. Idempotent. */\n finish(attributes?: TraceAttributes): void;\n /**\n * Ends the span as not-successful. Genuine failures record `error.type`;\n * recognized cancellations (an `AbortError`) record `canceled` instead so aborts\n * are not counted as errors. The cause message is never recorded. Idempotent.\n */\n fail(cause: unknown): void;\n};\n\ntype InvocationScope = {\n /** Bounded spans still open. Emptied when the invocation ends. */\n readonly open: Set<ManagedSpan>;\n /** Whether the invocation this scope represents has already ended. */\n ended: boolean;\n};\n\nexport type InvocationScopeOptions = {\n /**\n * Open a scope even inside a live one, for work deliberately detached from\n * the handler that started it — `ctx.waitUntil` bodies, queue drains — which\n * runs on past that handler and must not be cut off with it.\n */\n readonly detached?: boolean;\n};\n\n/**\n * Spans that asked to be invocation-bounded while a scope was active. Closed\n * when that scope ends; see {@link withInvocationScope}.\n */\nconst invocationScope = new AsyncLocalStorage<InvocationScope>();\n\n/**\n * Runs `body` as one traced invocation.\n *\n * Work that escapes its native invocation cannot be traced from the context it\n * started in: the still-open span is force-closed against the invocation that\n * owned that context, which reports a negative duration or `span_not_ended`.\n * Spans opened with {@link SpanLifetime.boundToInvocation} inside this scope\n * are therefore closed before `body` settles — but not one moment earlier, so\n * everything that completes during the invocation (the normal case: a chat\n * turn is awaited by the handler that received it) still records its finish\n * attributes. A span truncated this way is marked\n * `cloudflare.agents.span.truncated` rather than passing as complete.\n */\nexport function withInvocationScope<T>(\n body: () => T,\n options?: InvocationScopeOptions\n): T {\n // Nested scopes would truncate spans at an inner boundary that is not an\n // invocation edge, so the outermost live scope owns the lifetime. A scope\n // that has already ended is not an enclosing invocation at all — it is a\n // leftover context on work that resumed later — so `body` starts a new one.\n const current = invocationScope.getStore();\n if (options?.detached !== true && current !== undefined && !current.ended) {\n return body();\n }\n\n const scope: InvocationScope = { ended: false, open: new Set() };\n const endInvocation = () => {\n scope.ended = true;\n for (const span of scope.open) {\n // Fail open: this runs on the return path of every agent handler, so a\n // span writer that throws must not take the handler's result with it,\n // nor stop the remaining spans from closing.\n try {\n span.truncate();\n } catch {\n // Nothing useful to do with a broken span writer.\n }\n }\n scope.open.clear();\n };\n\n return invocationScope.run(scope, () => {\n let result: T;\n try {\n result = body();\n } catch (cause: unknown) {\n endInvocation();\n throw cause;\n }\n\n if (isPromiseLike(result)) {\n // SAFETY: T is promise-like here, so the settled promise is still a T.\n return Promise.resolve(result).finally(endInvocation) as T;\n }\n\n endInvocation();\n return result;\n });\n}\n\n/** Creates a tracer from a runtime span capability. */\nexport function createTracer(runtime: SpanRuntime): AgentTracer {\n return new RuntimeTracer(runtime);\n}\n\nclass RuntimeTracer implements AgentTracer {\n constructor(private readonly runtime: SpanRuntime) {}\n\n withSpan<T>(\n name: string,\n attributes: TraceAttributes,\n run: (span: AgentSpan) => MaybePromise<T>,\n lifetime?: SpanLifetime\n ): T | Promise<T> {\n return this.activate(name, attributes, (span) => {\n // Ask before running: a span that opens and closes in one tick still\n // needs to know whether that tick happened after its invocation ended.\n const outOfBand =\n lifetime?.boundToInvocation === true && bindToInvocation(span);\n const result = run(span);\n if (isPromiseLike(result)) {\n if (outOfBand) {\n span.truncate();\n }\n return Promise.resolve(result)\n .catch((cause: unknown) => {\n span.fail(cause);\n throw cause;\n })\n .finally(() => {\n span.close();\n });\n }\n\n if (outOfBand) {\n span.truncate();\n }\n span.close();\n return result;\n });\n }\n\n openSpan<T>(\n name: string,\n attributes: TraceAttributes,\n activate: (span: AgentSpan) => T,\n lifetime?: SpanLifetime\n ): T {\n if (!lifetime?.boundToInvocation) {\n return this.activate(name, attributes, activate);\n }\n\n return this.activate(name, attributes, (span) => {\n const invocationEnded = bindToInvocation(span);\n try {\n return activate(span);\n } finally {\n // Truncate only once `activate` has had its turn: callers that open\n // with an empty attribute set and write the real one lazily (the AI\n // operation span does, to stay cheap for untraced calls) would\n // otherwise be closed before writing anything at all.\n if (invocationEnded) {\n span.truncate();\n }\n }\n });\n }\n\n /**\n * Shared scaffold: opens an active span, seeds its attributes, and fails the\n * span on a thrown defect before rethrowing. The `body` decides the span's\n * finishing policy (managed vs. caller-owned).\n */\n private activate<T>(\n name: string,\n attributes: TraceAttributes,\n body: (span: ManagedSpan) => T\n ): T {\n return this.runtime.startActiveSpan(name, (writer) => {\n setAttributes(writer, attributes);\n const span = new ManagedSpan(writer);\n\n try {\n return body(span);\n } catch (cause: unknown) {\n span.fail(cause);\n throw cause;\n }\n });\n }\n}\n\nclass ManagedSpan implements AgentSpan {\n #closed = false;\n\n constructor(private readonly span: SpanWriter) {}\n\n get isTraced(): boolean {\n return this.span.isTraced;\n }\n\n /** INTERNAL: see {@link writeSpanAttributes}. */\n writeAttributes(attributes: TraceAttributes): void {\n if (this.#closed) {\n return;\n }\n\n setAttributes(this.span, attributes);\n }\n\n finish(attributes: TraceAttributes = {}): void {\n if (this.#closed) {\n return;\n }\n\n setAttributes(this.span, attributes);\n this.close();\n }\n\n fail(cause: unknown): void {\n if (this.#closed) {\n return;\n }\n\n if (isCancellation(cause)) {\n // Cancellation is a control path, not a failure: OTel semconv leaves\n // status Unset and records no error.type for cancellations, so aborted\n // operations do not inflate error rates. The vendor marker is additive.\n setAttributes(this.span, { \"cloudflare.agents.canceled\": true });\n } else {\n // Workers' custom Span API does not currently expose setStatus(). Do not\n // invent an `otel.status_code` attribute: status is span state in OTel,\n // not an attribute. error.type remains the standard queryable marker.\n setAttributes(this.span, {\n \"error.type\":\n cause instanceof Error ? cause.name || \"Error\" : typeof cause\n });\n }\n\n this.close();\n }\n\n close(): void {\n if (this.#closed) {\n return;\n }\n\n this.#closed = true;\n this.span.end();\n }\n\n /**\n * Closes a span whose work has not finished because its invocation is ending.\n * The marker distinguishes \"this span has no tokens because the turn escaped\n * its invocation\" from \"this span completed and reported none\".\n */\n truncate(): void {\n if (this.#closed) {\n return;\n }\n\n setAttributes(this.span, { \"cloudflare.agents.span.truncated\": true });\n this.close();\n }\n}\n\n/**\n * Registers a span for closure at the end of the current invocation, and\n * reports whether that invocation has already ended.\n *\n * Outside any scope the span keeps its natural lifetime: with no known\n * invocation boundary there is nothing to bound it to, and closing early would\n * discard finish attributes for no gain. Inside a scope that has already\n * ended — work resumed later while still carrying this context — the span\n * cannot outlive an invocation that is already gone, so the caller truncates\n * it as soon as it has written what it knows.\n */\nfunction bindToInvocation(span: ManagedSpan): boolean {\n const scope = invocationScope.getStore();\n if (scope === undefined) {\n return false;\n }\n\n if (scope.ended) {\n return true;\n }\n\n scope.open.add(span);\n return false;\n}\n\n/**\n * INTERNAL: writes attributes onto an open managed span. Lets instrumentation\n * defer expensive attribute computation until after the isTraced check (span\n * names must exist at open time; attributes need not). Not part of the public\n * barrel surface.\n */\nexport function writeSpanAttributes(\n span: AgentSpan,\n attributes: TraceAttributes\n): void {\n if (span instanceof ManagedSpan) {\n span.writeAttributes(attributes);\n }\n}\n\nfunction setAttributes(span: SpanWriter, attributes: TraceAttributes): void {\n if (!span.isTraced) {\n return;\n }\n\n // Fail-safe: a throwing writer must not leak the span or replace the\n // application's original error with a telemetry one.\n try {\n for (const [key, value] of Object.entries(attributes)) {\n if (value !== undefined) {\n span.setAttribute(key, value);\n }\n }\n } catch {\n // Drop the attributes; the span still closes.\n }\n}\n\nfunction isPromiseLike<T>(value: MaybePromise<T>): value is PromiseLike<T> {\n return (\n value !== null &&\n value !== undefined &&\n (typeof value === \"object\" || typeof value === \"function\") &&\n \"then\" in value &&\n typeof value.then === \"function\"\n );\n}\n\n/**\n * Recognizes caller/runtime cancellation (an `AbortError`, e.g. from an aborted\n * `AbortSignal`) so it can be classified separately from genuine failures. A\n * `DOMException` named `AbortError` is not always an `Error` instance, so this\n * probes the `name` field structurally rather than via `instanceof`.\n */\nfunction isCancellation(cause: unknown): boolean {\n return (\n typeof cause === \"object\" &&\n cause !== null &&\n \"name\" in cause &&\n cause.name === \"AbortError\"\n );\n}\n","import * as cloudflareWorkers from \"cloudflare:workers\";\nimport { createTracer } from \"./tracer\";\nimport type { SpanRuntime, SpanWriter, AgentTracer } from \"./tracer\";\n\nconst noopSpan: SpanWriter = {\n isTraced: false,\n setAttribute() {},\n end() {}\n};\n\nconst noopRuntime: SpanRuntime = {\n startActiveSpan(_name, run) {\n return run(noopSpan);\n }\n};\n\n// Accessed via the namespace so runtimes that predate the `tracing` export\n// degrade to a no-op tracer instead of failing at module-link time — this\n// module loads with the main `agents` entry, not just for tracing users.\nconst runtime: SpanRuntime =\n (cloudflareWorkers as { tracing?: SpanRuntime }).tracing ?? noopRuntime;\n\nexport const tracer: AgentTracer = createTracer(runtime);\n"],"mappings":"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"}
|
|
@@ -1,37 +1,5 @@
|
|
|
1
1
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2
2
|
import { WebStandardStreamableHTTPServerTransport, createMcpHandler, hostHeaderValidationResponse, isJSONRPCRequest, isLegacyRequest, localhostAllowedHostnames, localhostAllowedOrigins, originValidationResponse } from "@modelcontextprotocol/server";
|
|
3
|
-
//#region src/mcp/sse-keepalive.ts
|
|
4
|
-
/**
|
|
5
|
-
* Shared SSE keepalive utility for MCP transports.
|
|
6
|
-
*
|
|
7
|
-
* Cloudflare's edge closes idle SSE responses after ~5 minutes. Writers
|
|
8
|
-
* that may sit silent for that long (long-running tool calls, idle
|
|
9
|
-
* standalone GET streams) arm a keepalive to keep the response under the
|
|
10
|
-
* watchdog.
|
|
11
|
-
*
|
|
12
|
-
* See cloudflare/agents#1583.
|
|
13
|
-
*/
|
|
14
|
-
/** Interval between SSE keepalive comment frames, in ms.
|
|
15
|
-
*
|
|
16
|
-
* The WHATWG SSE spec recommends a comment line every "15 seconds or so"
|
|
17
|
-
* (html.spec.whatwg.org §9.2.7). 25s gives comfortable headroom below
|
|
18
|
-
* both the ~30s post-handler background-work cancellation window on
|
|
19
|
-
* Workers and the ~5min Cloudflare edge idle-stream watchdog.
|
|
20
|
-
*/
|
|
21
|
-
const KEEPALIVE_INTERVAL_MS = 25e3;
|
|
22
|
-
/** SSE comment frame the parser drops before any event dispatch. */
|
|
23
|
-
const KEEPALIVE_FRAME = ": keepalive\n\n";
|
|
24
|
-
/**
|
|
25
|
-
* Start an SSE keepalive on `writer`. Returns a `clearInterval` handle
|
|
26
|
-
* that the stream cleanup must invoke when the stream closes.
|
|
27
|
-
*/
|
|
28
|
-
function startKeepalive(writer, encoder) {
|
|
29
|
-
const handle = setInterval(() => {
|
|
30
|
-
writer.write(encoder.encode(KEEPALIVE_FRAME)).catch(() => clearInterval(handle));
|
|
31
|
-
}, KEEPALIVE_INTERVAL_MS);
|
|
32
|
-
return handle;
|
|
33
|
-
}
|
|
34
|
-
//#endregion
|
|
35
3
|
//#region src/mcp/auth-context.ts
|
|
36
4
|
const VERIFIED_OAUTH_CONTEXT = Symbol.for("cloudflare.workers-oauth-provider.verified-context.v1");
|
|
37
5
|
const authContextStorage = new AsyncLocalStorage();
|
|
@@ -109,13 +77,14 @@ function reportHandlerError(onerror, error) {
|
|
|
109
77
|
* Local deltas from the upstream stateless fallback:
|
|
110
78
|
*
|
|
111
79
|
* - impossible stateless server-to-client requests fail immediately rather
|
|
112
|
-
* than leaving the tool handler waiting for a session response
|
|
113
|
-
* - streamed POST responses receive Cloudflare's 25-second SSE keepalive.
|
|
80
|
+
* than leaving the tool handler waiting for a session response.
|
|
114
81
|
*
|
|
115
|
-
*
|
|
82
|
+
* Streaming and keepalive behavior remain delegated to the SDK transport.
|
|
83
|
+
* Remove this adapter once the SDK exposes the reverse-request policy directly.
|
|
116
84
|
*/
|
|
117
|
-
function createLegacyCompatibilityRequestHandler(factory,
|
|
118
|
-
const
|
|
85
|
+
function createLegacyCompatibilityRequestHandler(factory, handlerOptions = {}) {
|
|
86
|
+
const { keepAliveMs, onerror } = handlerOptions;
|
|
87
|
+
const fetch = async (request, requestOptions) => {
|
|
119
88
|
if (request.method.toUpperCase() !== "POST") return Response.json({
|
|
120
89
|
jsonrpc: "2.0",
|
|
121
90
|
error: {
|
|
@@ -127,20 +96,21 @@ function createLegacyCompatibilityRequestHandler(factory, onerror) {
|
|
|
127
96
|
if (request.signal.aborted) return new Response(null, { status: 499 });
|
|
128
97
|
let product;
|
|
129
98
|
let transport;
|
|
130
|
-
let clearResponseKeepalive = () => {};
|
|
131
99
|
let teardownPromise;
|
|
132
100
|
const teardown = () => teardownPromise ??= (async () => {
|
|
133
|
-
clearResponseKeepalive();
|
|
134
101
|
await Promise.all([transport?.close().catch(() => {}), product?.close().catch(() => {})]);
|
|
135
102
|
})();
|
|
136
103
|
const onAbort = () => void teardown();
|
|
137
104
|
try {
|
|
138
105
|
product = await factory({
|
|
139
106
|
era: "legacy",
|
|
140
|
-
...
|
|
107
|
+
...requestOptions?.authInfo !== void 0 && { authInfo: requestOptions.authInfo },
|
|
141
108
|
requestInfo: request
|
|
142
109
|
});
|
|
143
|
-
transport = new WebStandardStreamableHTTPServerTransport({
|
|
110
|
+
transport = new WebStandardStreamableHTTPServerTransport({
|
|
111
|
+
keepAliveMs,
|
|
112
|
+
sessionIdGenerator: void 0
|
|
113
|
+
});
|
|
144
114
|
const send = transport.send.bind(transport);
|
|
145
115
|
transport.send = async (message, sendOptions) => {
|
|
146
116
|
if (isJSONRPCRequest(message)) {
|
|
@@ -163,8 +133,8 @@ function createLegacyCompatibilityRequestHandler(factory, onerror) {
|
|
|
163
133
|
}
|
|
164
134
|
request.signal.addEventListener("abort", onAbort, { once: true });
|
|
165
135
|
const response = await transport.handleRequest(request, {
|
|
166
|
-
...
|
|
167
|
-
...
|
|
136
|
+
...requestOptions?.authInfo !== void 0 && { authInfo: requestOptions.authInfo },
|
|
137
|
+
...requestOptions?.parsedBody !== void 0 && { parsedBody: requestOptions.parsedBody }
|
|
168
138
|
});
|
|
169
139
|
if (response.body === null || !response.headers.get("content-type")?.includes("text/event-stream")) {
|
|
170
140
|
request.signal.removeEventListener("abort", onAbort);
|
|
@@ -172,44 +142,22 @@ function createLegacyCompatibilityRequestHandler(factory, onerror) {
|
|
|
172
142
|
return response;
|
|
173
143
|
}
|
|
174
144
|
const reader = response.body.getReader();
|
|
175
|
-
const encoder = new TextEncoder();
|
|
176
|
-
let keepalive;
|
|
177
|
-
const clearKeepalive = () => {
|
|
178
|
-
if (keepalive !== void 0) {
|
|
179
|
-
clearInterval(keepalive);
|
|
180
|
-
keepalive = void 0;
|
|
181
|
-
}
|
|
182
|
-
};
|
|
183
|
-
clearResponseKeepalive = clearKeepalive;
|
|
184
145
|
const body = new ReadableStream({
|
|
185
|
-
start(controller) {
|
|
186
|
-
if (teardownPromise) return;
|
|
187
|
-
keepalive = setInterval(() => {
|
|
188
|
-
try {
|
|
189
|
-
controller.enqueue(encoder.encode(KEEPALIVE_FRAME));
|
|
190
|
-
} catch {
|
|
191
|
-
clearKeepalive();
|
|
192
|
-
}
|
|
193
|
-
}, KEEPALIVE_INTERVAL_MS);
|
|
194
|
-
},
|
|
195
146
|
async pull(controller) {
|
|
196
147
|
try {
|
|
197
148
|
const { done, value } = await reader.read();
|
|
198
149
|
if (done) {
|
|
199
|
-
clearKeepalive();
|
|
200
150
|
request.signal.removeEventListener("abort", onAbort);
|
|
201
151
|
await teardown();
|
|
202
152
|
controller.close();
|
|
203
153
|
} else if (value !== void 0) controller.enqueue(value);
|
|
204
154
|
} catch (error) {
|
|
205
|
-
clearKeepalive();
|
|
206
155
|
request.signal.removeEventListener("abort", onAbort);
|
|
207
156
|
await teardown();
|
|
208
157
|
controller.error(error);
|
|
209
158
|
}
|
|
210
159
|
},
|
|
211
160
|
async cancel(reason) {
|
|
212
|
-
clearKeepalive();
|
|
213
161
|
request.signal.removeEventListener("abort", onAbort);
|
|
214
162
|
await reader.cancel(reason).catch(() => {});
|
|
215
163
|
await teardown();
|
|
@@ -224,7 +172,7 @@ function createLegacyCompatibilityRequestHandler(factory, onerror) {
|
|
|
224
172
|
request.signal.removeEventListener("abort", onAbort);
|
|
225
173
|
await teardown();
|
|
226
174
|
reportHandlerError(onerror, error);
|
|
227
|
-
return internalErrorResponse(requestIdFromParsedBody(
|
|
175
|
+
return internalErrorResponse(requestIdFromParsedBody(requestOptions?.parsedBody));
|
|
228
176
|
}
|
|
229
177
|
};
|
|
230
178
|
return { fetch };
|
|
@@ -309,7 +257,10 @@ function createStatelessMcpHandler(factory, options = {}) {
|
|
|
309
257
|
...sdkOptions,
|
|
310
258
|
legacy: "reject"
|
|
311
259
|
});
|
|
312
|
-
const legacyCompatibilityHandler = legacy === "stateless" ? createLegacyCompatibilityRequestHandler(factory,
|
|
260
|
+
const legacyCompatibilityHandler = legacy === "stateless" ? createLegacyCompatibilityRequestHandler(factory, {
|
|
261
|
+
keepAliveMs: sdkOptions.keepAliveMs,
|
|
262
|
+
onerror: sdkOptions.onerror
|
|
263
|
+
}) : void 0;
|
|
313
264
|
const serve = async (request, requestOptions, workerCtx) => {
|
|
314
265
|
const requestUrl = new URL(request.url);
|
|
315
266
|
if (requestUrl.pathname !== route) return withCors(new Response("Not Found", { status: 404 }), corsOptions);
|
|
@@ -362,6 +313,6 @@ function createStatelessMcpHandler(factory, options = {}) {
|
|
|
362
313
|
});
|
|
363
314
|
}
|
|
364
315
|
//#endregion
|
|
365
|
-
export {
|
|
316
|
+
export { getMcpAuthContext as n, runWithAuthContext as r, createStatelessMcpHandler as t };
|
|
366
317
|
|
|
367
|
-
//# sourceMappingURL=handler-stateless-
|
|
318
|
+
//# sourceMappingURL=handler-stateless-CIkKPETH.js.map
|