agents 0.0.0-c69f616 → 0.0.0-c6d9bf1
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/README.md +129 -7
- package/dist/_esm-LV5FJ3HK.js +3922 -0
- package/dist/_esm-LV5FJ3HK.js.map +1 -0
- package/dist/ai-chat-agent.d.ts +10 -8
- package/dist/ai-chat-agent.js +444 -60
- package/dist/ai-chat-agent.js.map +1 -1
- package/dist/ai-chat-v5-migration.d.ts +152 -0
- package/dist/ai-chat-v5-migration.js +20 -0
- package/dist/ai-chat-v5-migration.js.map +1 -0
- package/dist/ai-react.d.ts +66 -70
- package/dist/ai-react.js +252 -99
- package/dist/ai-react.js.map +1 -1
- package/dist/ai-types.d.ts +37 -19
- package/dist/ai-types.js +7 -0
- package/dist/ccip-CMBYN64O.js +15 -0
- package/dist/ccip-CMBYN64O.js.map +1 -0
- package/dist/{chunk-OJFA7RKX.js → chunk-254F4GDT.js} +188 -115
- package/dist/chunk-254F4GDT.js.map +1 -0
- package/dist/{chunk-HY7ZLHJB.js → chunk-3OT2NNEW.js} +412 -69
- package/dist/chunk-3OT2NNEW.js.map +1 -0
- package/dist/chunk-5Y6BEZDY.js +276 -0
- package/dist/chunk-5Y6BEZDY.js.map +1 -0
- package/dist/chunk-BER7KXUJ.js +18 -0
- package/dist/chunk-BER7KXUJ.js.map +1 -0
- package/dist/chunk-JJBFIGUC.js +5202 -0
- package/dist/chunk-JJBFIGUC.js.map +1 -0
- package/dist/chunk-PR4QN5HX.js +43 -0
- package/dist/chunk-PR4QN5HX.js.map +1 -0
- package/dist/{chunk-KUH345EY.js → chunk-QEVM4BVL.js} +5 -5
- package/dist/chunk-QEVM4BVL.js.map +1 -0
- package/dist/chunk-TYAY6AU6.js +159 -0
- package/dist/chunk-TYAY6AU6.js.map +1 -0
- package/dist/chunk-UJVEAURM.js +150 -0
- package/dist/chunk-UJVEAURM.js.map +1 -0
- package/dist/{chunk-PVQZBKN7.js → chunk-Z44WASMA.js} +11 -3
- package/dist/chunk-Z44WASMA.js.map +1 -0
- package/dist/{client-CH-eFIfq.d.ts → client-DVoPb3-C.d.ts} +762 -99
- package/dist/client.js +3 -1
- package/dist/codemode/ai.d.ts +25 -0
- package/dist/codemode/ai.js +5112 -0
- package/dist/codemode/ai.js.map +1 -0
- package/dist/index.d.ts +548 -32
- package/dist/index.js +8 -4
- package/dist/mcp/client.d.ts +2 -1
- package/dist/mcp/client.js +2 -1
- package/dist/mcp/do-oauth-client-provider.d.ts +1 -0
- package/dist/mcp/do-oauth-client-provider.js +2 -1
- package/dist/mcp/index.d.ts +50 -72
- package/dist/mcp/index.js +909 -718
- package/dist/mcp/index.js.map +1 -1
- package/dist/mcp/x402.d.ts +39 -0
- package/dist/mcp/x402.js +3195 -0
- package/dist/mcp/x402.js.map +1 -0
- package/dist/mcp-BH1fJeiU.d.ts +58 -0
- package/dist/observability/index.d.ts +34 -14
- package/dist/observability/index.js +6 -4
- package/dist/react.d.ts +13 -7
- package/dist/react.js +107 -7
- package/dist/react.js.map +1 -1
- package/dist/schedule.d.ts +79 -5
- package/dist/schedule.js +17 -2
- package/dist/schedule.js.map +1 -1
- package/dist/secp256k1-M22GZP2U.js +2193 -0
- package/dist/secp256k1-M22GZP2U.js.map +1 -0
- package/package.json +32 -9
- package/src/index.ts +272 -136
- package/dist/chunk-HY7ZLHJB.js.map +0 -1
- package/dist/chunk-KUH345EY.js.map +0 -1
- package/dist/chunk-OJFA7RKX.js.map +0 -1
- package/dist/chunk-PVQZBKN7.js.map +0 -1
- package/dist/index-BVoermIz.d.ts +0 -615
package/src/index.ts
CHANGED
|
@@ -22,10 +22,13 @@ import {
|
|
|
22
22
|
routePartykitRequest
|
|
23
23
|
} from "partyserver";
|
|
24
24
|
import { camelCaseToKebabCase } from "./client";
|
|
25
|
-
import { MCPClientManager } from "./mcp/client";
|
|
26
|
-
|
|
25
|
+
import { MCPClientManager, type MCPClientOAuthResult } from "./mcp/client";
|
|
26
|
+
import type { MCPConnectionState } from "./mcp/client-connection";
|
|
27
27
|
import { DurableObjectOAuthClientProvider } from "./mcp/do-oauth-client-provider";
|
|
28
|
+
import type { TransportType } from "./mcp/types";
|
|
28
29
|
import { genericObservability, type Observability } from "./observability";
|
|
30
|
+
import { DisposableStore } from "./core/events";
|
|
31
|
+
import { MessageType } from "./ai-types";
|
|
29
32
|
|
|
30
33
|
export type { Connection, ConnectionContext, WSMessage } from "partyserver";
|
|
31
34
|
|
|
@@ -43,7 +46,7 @@ export type RPCRequest = {
|
|
|
43
46
|
* State update message from client
|
|
44
47
|
*/
|
|
45
48
|
export type StateUpdateMessage = {
|
|
46
|
-
type:
|
|
49
|
+
type: MessageType.CF_AGENT_STATE;
|
|
47
50
|
state: unknown;
|
|
48
51
|
};
|
|
49
52
|
|
|
@@ -51,7 +54,7 @@ export type StateUpdateMessage = {
|
|
|
51
54
|
* RPC response message to client
|
|
52
55
|
*/
|
|
53
56
|
export type RPCResponse = {
|
|
54
|
-
type:
|
|
57
|
+
type: MessageType.RPC;
|
|
55
58
|
id: string;
|
|
56
59
|
} & (
|
|
57
60
|
| {
|
|
@@ -78,7 +81,7 @@ function isRPCRequest(msg: unknown): msg is RPCRequest {
|
|
|
78
81
|
typeof msg === "object" &&
|
|
79
82
|
msg !== null &&
|
|
80
83
|
"type" in msg &&
|
|
81
|
-
msg.type ===
|
|
84
|
+
msg.type === MessageType.RPC &&
|
|
82
85
|
"id" in msg &&
|
|
83
86
|
typeof msg.id === "string" &&
|
|
84
87
|
"method" in msg &&
|
|
@@ -96,7 +99,7 @@ function isStateUpdateMessage(msg: unknown): msg is StateUpdateMessage {
|
|
|
96
99
|
typeof msg === "object" &&
|
|
97
100
|
msg !== null &&
|
|
98
101
|
"type" in msg &&
|
|
99
|
-
msg.type ===
|
|
102
|
+
msg.type === MessageType.CF_AGENT_STATE &&
|
|
100
103
|
"state" in msg
|
|
101
104
|
);
|
|
102
105
|
}
|
|
@@ -117,7 +120,7 @@ const callableMetadata = new Map<Function, CallableMetadata>();
|
|
|
117
120
|
* Decorator that marks a method as callable by clients
|
|
118
121
|
* @param metadata Optional metadata about the callable method
|
|
119
122
|
*/
|
|
120
|
-
export function
|
|
123
|
+
export function callable(metadata: CallableMetadata = {}) {
|
|
121
124
|
return function callableDecorator<This, Args extends unknown[], Return>(
|
|
122
125
|
target: (this: This, ...args: Args) => Return,
|
|
123
126
|
// biome-ignore lint/correctness/noUnusedFunctionParameters: later
|
|
@@ -131,6 +134,23 @@ export function unstable_callable(metadata: CallableMetadata = {}) {
|
|
|
131
134
|
};
|
|
132
135
|
}
|
|
133
136
|
|
|
137
|
+
let didWarnAboutUnstableCallable = false;
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Decorator that marks a method as callable by clients
|
|
141
|
+
* @deprecated this has been renamed to callable, and unstable_callable will be removed in the next major version
|
|
142
|
+
* @param metadata Optional metadata about the callable method
|
|
143
|
+
*/
|
|
144
|
+
export const unstable_callable = (metadata: CallableMetadata = {}) => {
|
|
145
|
+
if (!didWarnAboutUnstableCallable) {
|
|
146
|
+
didWarnAboutUnstableCallable = true;
|
|
147
|
+
console.warn(
|
|
148
|
+
"unstable_callable is deprecated, use callable instead. unstable_callable will be removed in the next major version."
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
callable(metadata);
|
|
152
|
+
};
|
|
153
|
+
|
|
134
154
|
export type QueueItem<T = string> = {
|
|
135
155
|
id: string;
|
|
136
156
|
payload: T;
|
|
@@ -179,11 +199,13 @@ function getNextCronTime(cron: string) {
|
|
|
179
199
|
return interval.getNextDate();
|
|
180
200
|
}
|
|
181
201
|
|
|
202
|
+
export type { TransportType } from "./mcp/types";
|
|
203
|
+
|
|
182
204
|
/**
|
|
183
205
|
* MCP Server state update message from server -> Client
|
|
184
206
|
*/
|
|
185
207
|
export type MCPServerMessage = {
|
|
186
|
-
type:
|
|
208
|
+
type: MessageType.CF_AGENT_MCP_SERVERS;
|
|
187
209
|
mcp: MCPServersState;
|
|
188
210
|
};
|
|
189
211
|
|
|
@@ -203,7 +225,7 @@ export type MCPServer = {
|
|
|
203
225
|
// This state is specifically about the temporary process of getting a token (if needed).
|
|
204
226
|
// Scope outside of that can't be relied upon because when the DO sleeps, there's no way
|
|
205
227
|
// to communicate a change to a non-ready state.
|
|
206
|
-
state:
|
|
228
|
+
state: MCPConnectionState;
|
|
207
229
|
instructions: string | null;
|
|
208
230
|
capabilities: ServerCapabilities | null;
|
|
209
231
|
};
|
|
@@ -272,7 +294,13 @@ function withAgentContext<T extends (...args: any[]) => any>(
|
|
|
272
294
|
method: T
|
|
273
295
|
): (this: Agent<unknown, unknown>, ...args: Parameters<T>) => ReturnType<T> {
|
|
274
296
|
return function (...args: Parameters<T>): ReturnType<T> {
|
|
275
|
-
const { connection, request, email } = getCurrentAgent();
|
|
297
|
+
const { connection, request, email, agent } = getCurrentAgent();
|
|
298
|
+
|
|
299
|
+
if (agent === this) {
|
|
300
|
+
// already wrapped, so we can just call the method
|
|
301
|
+
return method.apply(this, args);
|
|
302
|
+
}
|
|
303
|
+
// not wrapped, so we need to wrap it
|
|
276
304
|
return agentContext.run({ agent: this, connection, request, email }, () => {
|
|
277
305
|
return method.apply(this, args);
|
|
278
306
|
});
|
|
@@ -284,13 +312,21 @@ function withAgentContext<T extends (...args: any[]) => any>(
|
|
|
284
312
|
* @template Env Environment type containing bindings
|
|
285
313
|
* @template State State type to store within the Agent
|
|
286
314
|
*/
|
|
287
|
-
export class Agent<
|
|
315
|
+
export class Agent<
|
|
316
|
+
Env = typeof env,
|
|
317
|
+
State = unknown,
|
|
318
|
+
Props extends Record<string, unknown> = Record<string, unknown>
|
|
319
|
+
> extends Server<Env, Props> {
|
|
288
320
|
private _state = DEFAULT_STATE as State;
|
|
321
|
+
private _disposables = new DisposableStore();
|
|
289
322
|
|
|
290
323
|
private _ParentClass: typeof Agent<Env, State> =
|
|
291
324
|
Object.getPrototypeOf(this).constructor;
|
|
292
325
|
|
|
293
|
-
mcp: MCPClientManager = new MCPClientManager(
|
|
326
|
+
readonly mcp: MCPClientManager = new MCPClientManager(
|
|
327
|
+
this._ParentClass.name,
|
|
328
|
+
"0.0.1"
|
|
329
|
+
);
|
|
294
330
|
|
|
295
331
|
/**
|
|
296
332
|
* Initial state for the Agent
|
|
@@ -383,8 +419,25 @@ export class Agent<Env = typeof env, State = unknown> extends Server<Env> {
|
|
|
383
419
|
constructor(ctx: AgentContext, env: Env) {
|
|
384
420
|
super(ctx, env);
|
|
385
421
|
|
|
386
|
-
|
|
387
|
-
|
|
422
|
+
if (!wrappedClasses.has(this.constructor)) {
|
|
423
|
+
// Auto-wrap custom methods with agent context
|
|
424
|
+
this._autoWrapCustomMethods();
|
|
425
|
+
wrappedClasses.add(this.constructor);
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
// Broadcast server state after background connects (for OAuth servers)
|
|
429
|
+
this._disposables.add(
|
|
430
|
+
this.mcp.onConnected(async () => {
|
|
431
|
+
this.broadcastMcpServers();
|
|
432
|
+
})
|
|
433
|
+
);
|
|
434
|
+
|
|
435
|
+
// Emit MCP observability events
|
|
436
|
+
this._disposables.add(
|
|
437
|
+
this.mcp.onObservabilityEvent((event) => {
|
|
438
|
+
this.observability?.emit(event);
|
|
439
|
+
})
|
|
440
|
+
);
|
|
388
441
|
|
|
389
442
|
this.sql`
|
|
390
443
|
CREATE TABLE IF NOT EXISTS cf_agents_state (
|
|
@@ -441,21 +494,24 @@ export class Agent<Env = typeof env, State = unknown> extends Server<Env> {
|
|
|
441
494
|
{ agent: this, connection: undefined, request, email: undefined },
|
|
442
495
|
async () => {
|
|
443
496
|
if (this.mcp.isCallbackRequest(request)) {
|
|
444
|
-
await this.mcp.handleCallbackRequest(request);
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
497
|
+
const result = await this.mcp.handleCallbackRequest(request);
|
|
498
|
+
this.broadcastMcpServers();
|
|
499
|
+
|
|
500
|
+
if (result.authSuccess) {
|
|
501
|
+
// Start background connection if auth was successful
|
|
502
|
+
this.mcp
|
|
503
|
+
.establishConnection(result.serverId)
|
|
504
|
+
.catch((error) => {
|
|
505
|
+
console.error("Background connection failed:", error);
|
|
506
|
+
})
|
|
507
|
+
.finally(() => {
|
|
508
|
+
// Broadcast after background connection resolves (success/failure)
|
|
509
|
+
this.broadcastMcpServers();
|
|
510
|
+
});
|
|
511
|
+
}
|
|
453
512
|
|
|
454
|
-
//
|
|
455
|
-
return
|
|
456
|
-
headers: { "content-type": "text/html" },
|
|
457
|
-
status: 200
|
|
458
|
-
});
|
|
513
|
+
// Handle OAuth callback response using MCPClientManager configuration
|
|
514
|
+
return this.handleOAuthCallbackResponse(result, request);
|
|
459
515
|
}
|
|
460
516
|
|
|
461
517
|
return this._tryCatch(() => _onRequest(request));
|
|
@@ -516,10 +572,8 @@ export class Agent<Env = typeof env, State = unknown> extends Server<Env> {
|
|
|
516
572
|
displayMessage: `RPC call to ${method}`,
|
|
517
573
|
id: nanoid(),
|
|
518
574
|
payload: {
|
|
519
|
-
args,
|
|
520
575
|
method,
|
|
521
|
-
streaming: metadata?.streaming
|
|
522
|
-
success: true
|
|
576
|
+
streaming: metadata?.streaming
|
|
523
577
|
},
|
|
524
578
|
timestamp: Date.now(),
|
|
525
579
|
type: "rpc"
|
|
@@ -532,7 +586,7 @@ export class Agent<Env = typeof env, State = unknown> extends Server<Env> {
|
|
|
532
586
|
id,
|
|
533
587
|
result,
|
|
534
588
|
success: true,
|
|
535
|
-
type:
|
|
589
|
+
type: MessageType.RPC
|
|
536
590
|
};
|
|
537
591
|
connection.send(JSON.stringify(response));
|
|
538
592
|
} catch (e) {
|
|
@@ -542,7 +596,7 @@ export class Agent<Env = typeof env, State = unknown> extends Server<Env> {
|
|
|
542
596
|
e instanceof Error ? e.message : "Unknown error occurred",
|
|
543
597
|
id: parsed.id,
|
|
544
598
|
success: false,
|
|
545
|
-
type:
|
|
599
|
+
type: MessageType.RPC
|
|
546
600
|
};
|
|
547
601
|
connection.send(JSON.stringify(response));
|
|
548
602
|
console.error("RPC error:", e);
|
|
@@ -561,44 +615,42 @@ export class Agent<Env = typeof env, State = unknown> extends Server<Env> {
|
|
|
561
615
|
// must fix this
|
|
562
616
|
return agentContext.run(
|
|
563
617
|
{ agent: this, connection, request: ctx.request, email: undefined },
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
if (this.state) {
|
|
567
|
-
connection.send(
|
|
568
|
-
JSON.stringify({
|
|
569
|
-
state: this.state,
|
|
570
|
-
type: "cf_agent_state"
|
|
571
|
-
})
|
|
572
|
-
);
|
|
573
|
-
}
|
|
574
|
-
|
|
618
|
+
() => {
|
|
619
|
+
if (this.state) {
|
|
575
620
|
connection.send(
|
|
576
621
|
JSON.stringify({
|
|
577
|
-
|
|
578
|
-
type:
|
|
622
|
+
state: this.state,
|
|
623
|
+
type: MessageType.CF_AGENT_STATE
|
|
579
624
|
})
|
|
580
625
|
);
|
|
626
|
+
}
|
|
581
627
|
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
628
|
+
connection.send(
|
|
629
|
+
JSON.stringify({
|
|
630
|
+
mcp: this.getMcpServers(),
|
|
631
|
+
type: MessageType.CF_AGENT_MCP_SERVERS
|
|
632
|
+
})
|
|
633
|
+
);
|
|
634
|
+
|
|
635
|
+
this.observability?.emit(
|
|
636
|
+
{
|
|
637
|
+
displayMessage: "Connection established",
|
|
638
|
+
id: nanoid(),
|
|
639
|
+
payload: {
|
|
640
|
+
connectionId: connection.id
|
|
591
641
|
},
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
642
|
+
timestamp: Date.now(),
|
|
643
|
+
type: "connect"
|
|
644
|
+
},
|
|
645
|
+
this.ctx
|
|
646
|
+
);
|
|
647
|
+
return this._tryCatch(() => _onConnect(connection, ctx));
|
|
596
648
|
}
|
|
597
649
|
);
|
|
598
650
|
};
|
|
599
651
|
|
|
600
652
|
const _onStart = this.onStart.bind(this);
|
|
601
|
-
this.onStart = async () => {
|
|
653
|
+
this.onStart = async (props?: Props) => {
|
|
602
654
|
return agentContext.run(
|
|
603
655
|
{
|
|
604
656
|
agent: this,
|
|
@@ -607,15 +659,27 @@ export class Agent<Env = typeof env, State = unknown> extends Server<Env> {
|
|
|
607
659
|
email: undefined
|
|
608
660
|
},
|
|
609
661
|
async () => {
|
|
610
|
-
|
|
662
|
+
await this._tryCatch(() => {
|
|
663
|
+
const servers = this.sql<MCPServerRow>`
|
|
611
664
|
SELECT id, name, server_url, client_id, auth_url, callback_url, server_options FROM cf_agents_mcp_servers;
|
|
612
665
|
`;
|
|
613
666
|
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
667
|
+
this.broadcastMcpServers();
|
|
668
|
+
|
|
669
|
+
// from DO storage, reconnect to all servers not currently in the oauth flow using our saved auth information
|
|
670
|
+
if (servers && Array.isArray(servers) && servers.length > 0) {
|
|
671
|
+
// Restore callback URLs for OAuth-enabled servers
|
|
672
|
+
servers.forEach((server) => {
|
|
673
|
+
if (server.callback_url) {
|
|
674
|
+
// Register the full redirect URL including serverId to avoid ambiguous matches
|
|
675
|
+
this.mcp.registerCallbackUrl(
|
|
676
|
+
`${server.callback_url}/${server.id}`
|
|
677
|
+
);
|
|
678
|
+
}
|
|
679
|
+
});
|
|
680
|
+
|
|
681
|
+
servers.forEach((server) => {
|
|
682
|
+
this._connectToMcpServerInternal(
|
|
619
683
|
server.name,
|
|
620
684
|
server.server_url,
|
|
621
685
|
server.callback_url,
|
|
@@ -626,18 +690,23 @@ export class Agent<Env = typeof env, State = unknown> extends Server<Env> {
|
|
|
626
690
|
id: server.id,
|
|
627
691
|
oauthClientId: server.client_id ?? undefined
|
|
628
692
|
}
|
|
629
|
-
)
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
693
|
+
)
|
|
694
|
+
.then(() => {
|
|
695
|
+
// Broadcast updated MCP servers state after each server connects
|
|
696
|
+
this.broadcastMcpServers();
|
|
697
|
+
})
|
|
698
|
+
.catch((error) => {
|
|
699
|
+
console.error(
|
|
700
|
+
`Error connecting to MCP server: ${server.name} (${server.server_url})`,
|
|
701
|
+
error
|
|
702
|
+
);
|
|
703
|
+
// Still broadcast even if connection fails, so clients know about the failure
|
|
704
|
+
this.broadcastMcpServers();
|
|
705
|
+
});
|
|
706
|
+
});
|
|
707
|
+
}
|
|
708
|
+
return _onStart(props);
|
|
709
|
+
});
|
|
641
710
|
}
|
|
642
711
|
);
|
|
643
712
|
};
|
|
@@ -647,7 +716,6 @@ export class Agent<Env = typeof env, State = unknown> extends Server<Env> {
|
|
|
647
716
|
state: State,
|
|
648
717
|
source: Connection | "server" = "server"
|
|
649
718
|
) {
|
|
650
|
-
const previousState = this._state;
|
|
651
719
|
this._state = state;
|
|
652
720
|
this.sql`
|
|
653
721
|
INSERT OR REPLACE INTO cf_agents_state (id, state)
|
|
@@ -660,7 +728,7 @@ export class Agent<Env = typeof env, State = unknown> extends Server<Env> {
|
|
|
660
728
|
this.broadcast(
|
|
661
729
|
JSON.stringify({
|
|
662
730
|
state: state,
|
|
663
|
-
type:
|
|
731
|
+
type: MessageType.CF_AGENT_STATE
|
|
664
732
|
}),
|
|
665
733
|
source !== "server" ? [source.id] : []
|
|
666
734
|
);
|
|
@@ -673,10 +741,7 @@ export class Agent<Env = typeof env, State = unknown> extends Server<Env> {
|
|
|
673
741
|
{
|
|
674
742
|
displayMessage: "State updated",
|
|
675
743
|
id: nanoid(),
|
|
676
|
-
payload: {
|
|
677
|
-
previousState,
|
|
678
|
-
state
|
|
679
|
-
},
|
|
744
|
+
payload: {},
|
|
680
745
|
timestamp: Date.now(),
|
|
681
746
|
type: "state:update"
|
|
682
747
|
},
|
|
@@ -816,41 +881,37 @@ export class Agent<Env = typeof env, State = unknown> extends Server<Env> {
|
|
|
816
881
|
while (proto && proto !== Object.prototype && depth < 10) {
|
|
817
882
|
const methodNames = Object.getOwnPropertyNames(proto);
|
|
818
883
|
for (const methodName of methodNames) {
|
|
819
|
-
|
|
884
|
+
const descriptor = Object.getOwnPropertyDescriptor(proto, methodName);
|
|
885
|
+
|
|
886
|
+
// Skip if it's a private method, a base method, a getter, or not a function,
|
|
820
887
|
if (
|
|
821
888
|
baseMethods.has(methodName) ||
|
|
822
889
|
methodName.startsWith("_") ||
|
|
823
|
-
|
|
890
|
+
!descriptor ||
|
|
891
|
+
!!descriptor.get ||
|
|
892
|
+
typeof descriptor.value !== "function"
|
|
824
893
|
) {
|
|
825
894
|
continue;
|
|
826
895
|
}
|
|
827
|
-
// If the method doesn't exist in base prototypes, it's a custom method
|
|
828
|
-
if (!baseMethods.has(methodName)) {
|
|
829
|
-
const descriptor = Object.getOwnPropertyDescriptor(proto, methodName);
|
|
830
|
-
if (descriptor && typeof descriptor.value === "function") {
|
|
831
|
-
// Wrap the custom method with context
|
|
832
|
-
|
|
833
|
-
const wrappedFunction = withAgentContext(
|
|
834
|
-
// biome-ignore lint/suspicious/noExplicitAny: I can't typescript
|
|
835
|
-
this[methodName as keyof this] as (...args: any[]) => any
|
|
836
|
-
// biome-ignore lint/suspicious/noExplicitAny: I can't typescript
|
|
837
|
-
) as any;
|
|
838
|
-
|
|
839
|
-
// if the method is callable, copy the metadata from the original method
|
|
840
|
-
if (this._isCallable(methodName)) {
|
|
841
|
-
callableMetadata.set(
|
|
842
|
-
wrappedFunction,
|
|
843
|
-
callableMetadata.get(
|
|
844
|
-
this[methodName as keyof this] as Function
|
|
845
|
-
)!
|
|
846
|
-
);
|
|
847
|
-
}
|
|
848
896
|
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
897
|
+
// Now, methodName is confirmed to be a custom method/function
|
|
898
|
+
// Wrap the custom method with context
|
|
899
|
+
const wrappedFunction = withAgentContext(
|
|
900
|
+
// biome-ignore lint/suspicious/noExplicitAny: I can't typescript
|
|
901
|
+
this[methodName as keyof this] as (...args: any[]) => any
|
|
902
|
+
// biome-ignore lint/suspicious/noExplicitAny: I can't typescript
|
|
903
|
+
) as any;
|
|
904
|
+
|
|
905
|
+
// if the method is callable, copy the metadata from the original method
|
|
906
|
+
if (this._isCallable(methodName)) {
|
|
907
|
+
callableMetadata.set(
|
|
908
|
+
wrappedFunction,
|
|
909
|
+
callableMetadata.get(this[methodName as keyof this] as Function)!
|
|
910
|
+
);
|
|
853
911
|
}
|
|
912
|
+
|
|
913
|
+
// set the wrapped function on the prototype
|
|
914
|
+
this.constructor.prototype[methodName as keyof this] = wrappedFunction;
|
|
854
915
|
}
|
|
855
916
|
|
|
856
917
|
proto = Object.getPrototypeOf(proto);
|
|
@@ -1037,7 +1098,10 @@ export class Agent<Env = typeof env, State = unknown> extends Server<Env> {
|
|
|
1037
1098
|
{
|
|
1038
1099
|
displayMessage: `Schedule ${schedule.id} created`,
|
|
1039
1100
|
id: nanoid(),
|
|
1040
|
-
payload:
|
|
1101
|
+
payload: {
|
|
1102
|
+
callback: callback as string,
|
|
1103
|
+
id: id
|
|
1104
|
+
},
|
|
1041
1105
|
timestamp: Date.now(),
|
|
1042
1106
|
type: "schedule:create"
|
|
1043
1107
|
},
|
|
@@ -1207,7 +1271,10 @@ export class Agent<Env = typeof env, State = unknown> extends Server<Env> {
|
|
|
1207
1271
|
{
|
|
1208
1272
|
displayMessage: `Schedule ${id} cancelled`,
|
|
1209
1273
|
id: nanoid(),
|
|
1210
|
-
payload:
|
|
1274
|
+
payload: {
|
|
1275
|
+
callback: schedule.callback,
|
|
1276
|
+
id: schedule.id
|
|
1277
|
+
},
|
|
1211
1278
|
timestamp: Date.now(),
|
|
1212
1279
|
type: "schedule:cancel"
|
|
1213
1280
|
},
|
|
@@ -1272,7 +1339,10 @@ export class Agent<Env = typeof env, State = unknown> extends Server<Env> {
|
|
|
1272
1339
|
{
|
|
1273
1340
|
displayMessage: `Schedule ${row.id} executed`,
|
|
1274
1341
|
id: nanoid(),
|
|
1275
|
-
payload:
|
|
1342
|
+
payload: {
|
|
1343
|
+
callback: row.callback,
|
|
1344
|
+
id: row.id
|
|
1345
|
+
},
|
|
1276
1346
|
timestamp: Date.now(),
|
|
1277
1347
|
type: "schedule:execute"
|
|
1278
1348
|
},
|
|
@@ -1324,6 +1394,8 @@ export class Agent<Env = typeof env, State = unknown> extends Server<Env> {
|
|
|
1324
1394
|
// delete all alarms
|
|
1325
1395
|
await this.ctx.storage.deleteAlarm();
|
|
1326
1396
|
await this.ctx.storage.deleteAll();
|
|
1397
|
+
this._disposables.dispose();
|
|
1398
|
+
await this.mcp.dispose?.();
|
|
1327
1399
|
this.ctx.abort("destroyed"); // enforce that the agent is evicted
|
|
1328
1400
|
|
|
1329
1401
|
this.observability?.emit(
|
|
@@ -1349,25 +1421,42 @@ export class Agent<Env = typeof env, State = unknown> extends Server<Env> {
|
|
|
1349
1421
|
/**
|
|
1350
1422
|
* Connect to a new MCP Server
|
|
1351
1423
|
*
|
|
1424
|
+
* @param serverName Name of the MCP server
|
|
1352
1425
|
* @param url MCP Server SSE URL
|
|
1353
|
-
* @param callbackHost Base host for the agent, used for the redirect URI.
|
|
1426
|
+
* @param callbackHost Base host for the agent, used for the redirect URI. If not provided, will be derived from the current request.
|
|
1354
1427
|
* @param agentsPrefix agents routing prefix if not using `agents`
|
|
1355
|
-
* @param options MCP client and transport
|
|
1428
|
+
* @param options MCP client and transport options
|
|
1356
1429
|
* @returns authUrl
|
|
1357
1430
|
*/
|
|
1358
1431
|
async addMcpServer(
|
|
1359
1432
|
serverName: string,
|
|
1360
1433
|
url: string,
|
|
1361
|
-
callbackHost
|
|
1434
|
+
callbackHost?: string,
|
|
1362
1435
|
agentsPrefix = "agents",
|
|
1363
1436
|
options?: {
|
|
1364
1437
|
client?: ConstructorParameters<typeof Client>[1];
|
|
1365
1438
|
transport?: {
|
|
1366
|
-
headers
|
|
1439
|
+
headers?: HeadersInit;
|
|
1440
|
+
type?: TransportType;
|
|
1367
1441
|
};
|
|
1368
1442
|
}
|
|
1369
1443
|
): Promise<{ id: string; authUrl: string | undefined }> {
|
|
1370
|
-
|
|
1444
|
+
// If callbackHost is not provided, derive it from the current request
|
|
1445
|
+
let resolvedCallbackHost = callbackHost;
|
|
1446
|
+
if (!resolvedCallbackHost) {
|
|
1447
|
+
const { request } = getCurrentAgent();
|
|
1448
|
+
if (!request) {
|
|
1449
|
+
throw new Error(
|
|
1450
|
+
"callbackHost is required when not called within a request context"
|
|
1451
|
+
);
|
|
1452
|
+
}
|
|
1453
|
+
|
|
1454
|
+
// Extract the origin from the request
|
|
1455
|
+
const requestUrl = new URL(request.url);
|
|
1456
|
+
resolvedCallbackHost = `${requestUrl.protocol}//${requestUrl.host}`;
|
|
1457
|
+
}
|
|
1458
|
+
|
|
1459
|
+
const callbackUrl = `${resolvedCallbackHost}/${agentsPrefix}/${camelCaseToKebabCase(this._ParentClass.name)}/${this.name}/callback`;
|
|
1371
1460
|
|
|
1372
1461
|
const result = await this._connectToMcpServerInternal(
|
|
1373
1462
|
serverName,
|
|
@@ -1375,6 +1464,7 @@ export class Agent<Env = typeof env, State = unknown> extends Server<Env> {
|
|
|
1375
1464
|
callbackUrl,
|
|
1376
1465
|
options
|
|
1377
1466
|
);
|
|
1467
|
+
|
|
1378
1468
|
this.sql`
|
|
1379
1469
|
INSERT
|
|
1380
1470
|
OR REPLACE INTO cf_agents_mcp_servers (id, name, server_url, client_id, auth_url, callback_url, server_options)
|
|
@@ -1389,17 +1479,12 @@ export class Agent<Env = typeof env, State = unknown> extends Server<Env> {
|
|
|
1389
1479
|
);
|
|
1390
1480
|
`;
|
|
1391
1481
|
|
|
1392
|
-
this.
|
|
1393
|
-
JSON.stringify({
|
|
1394
|
-
mcp: this.getMcpServers(),
|
|
1395
|
-
type: "cf_agent_mcp_servers"
|
|
1396
|
-
})
|
|
1397
|
-
);
|
|
1482
|
+
this.broadcastMcpServers();
|
|
1398
1483
|
|
|
1399
1484
|
return result;
|
|
1400
1485
|
}
|
|
1401
1486
|
|
|
1402
|
-
async _connectToMcpServerInternal(
|
|
1487
|
+
private async _connectToMcpServerInternal(
|
|
1403
1488
|
_serverName: string,
|
|
1404
1489
|
url: string,
|
|
1405
1490
|
callbackUrl: string,
|
|
@@ -1415,6 +1500,7 @@ export class Agent<Env = typeof env, State = unknown> extends Server<Env> {
|
|
|
1415
1500
|
*/
|
|
1416
1501
|
transport?: {
|
|
1417
1502
|
headers?: HeadersInit;
|
|
1503
|
+
type?: TransportType;
|
|
1418
1504
|
};
|
|
1419
1505
|
},
|
|
1420
1506
|
reconnect?: {
|
|
@@ -1439,6 +1525,9 @@ export class Agent<Env = typeof env, State = unknown> extends Server<Env> {
|
|
|
1439
1525
|
}
|
|
1440
1526
|
}
|
|
1441
1527
|
|
|
1528
|
+
// Use the transport type specified in options, or default to "auto"
|
|
1529
|
+
const transportType: TransportType = options?.transport?.type ?? "auto";
|
|
1530
|
+
|
|
1442
1531
|
// allows passing through transport headers if necessary
|
|
1443
1532
|
// this handles some non-standard bearer auth setups (i.e. MCP server behind CF access instead of OAuth)
|
|
1444
1533
|
let headerTransportOpts: SSEClientTransportOptions = {};
|
|
@@ -1462,7 +1551,8 @@ export class Agent<Env = typeof env, State = unknown> extends Server<Env> {
|
|
|
1462
1551
|
reconnect,
|
|
1463
1552
|
transport: {
|
|
1464
1553
|
...headerTransportOpts,
|
|
1465
|
-
authProvider
|
|
1554
|
+
authProvider,
|
|
1555
|
+
type: transportType
|
|
1466
1556
|
}
|
|
1467
1557
|
});
|
|
1468
1558
|
|
|
@@ -1475,15 +1565,11 @@ export class Agent<Env = typeof env, State = unknown> extends Server<Env> {
|
|
|
1475
1565
|
|
|
1476
1566
|
async removeMcpServer(id: string) {
|
|
1477
1567
|
this.mcp.closeConnection(id);
|
|
1568
|
+
this.mcp.unregisterCallbackUrl(id);
|
|
1478
1569
|
this.sql`
|
|
1479
1570
|
DELETE FROM cf_agents_mcp_servers WHERE id = ${id};
|
|
1480
1571
|
`;
|
|
1481
|
-
this.
|
|
1482
|
-
JSON.stringify({
|
|
1483
|
-
mcp: this.getMcpServers(),
|
|
1484
|
-
type: "cf_agent_mcp_servers"
|
|
1485
|
-
})
|
|
1486
|
-
);
|
|
1572
|
+
this.broadcastMcpServers();
|
|
1487
1573
|
}
|
|
1488
1574
|
|
|
1489
1575
|
getMcpServers(): MCPServersState {
|
|
@@ -1515,8 +1601,53 @@ export class Agent<Env = typeof env, State = unknown> extends Server<Env> {
|
|
|
1515
1601
|
|
|
1516
1602
|
return mcpState;
|
|
1517
1603
|
}
|
|
1604
|
+
|
|
1605
|
+
private broadcastMcpServers() {
|
|
1606
|
+
this.broadcast(
|
|
1607
|
+
JSON.stringify({
|
|
1608
|
+
mcp: this.getMcpServers(),
|
|
1609
|
+
type: MessageType.CF_AGENT_MCP_SERVERS
|
|
1610
|
+
})
|
|
1611
|
+
);
|
|
1612
|
+
}
|
|
1613
|
+
|
|
1614
|
+
/**
|
|
1615
|
+
* Handle OAuth callback response using MCPClientManager configuration
|
|
1616
|
+
* @param result OAuth callback result
|
|
1617
|
+
* @param request The original request (needed for base URL)
|
|
1618
|
+
* @returns Response for the OAuth callback
|
|
1619
|
+
*/
|
|
1620
|
+
private handleOAuthCallbackResponse(
|
|
1621
|
+
result: MCPClientOAuthResult,
|
|
1622
|
+
request: Request
|
|
1623
|
+
): Response {
|
|
1624
|
+
const config = this.mcp.getOAuthCallbackConfig();
|
|
1625
|
+
|
|
1626
|
+
// Use custom handler if configured
|
|
1627
|
+
if (config?.customHandler) {
|
|
1628
|
+
return config.customHandler(result);
|
|
1629
|
+
}
|
|
1630
|
+
|
|
1631
|
+
// Use redirect URLs if configured
|
|
1632
|
+
if (config?.successRedirect && result.authSuccess) {
|
|
1633
|
+
return Response.redirect(config.successRedirect);
|
|
1634
|
+
}
|
|
1635
|
+
|
|
1636
|
+
if (config?.errorRedirect && !result.authSuccess) {
|
|
1637
|
+
return Response.redirect(
|
|
1638
|
+
`${config.errorRedirect}?error=${encodeURIComponent(result.authError || "Unknown error")}`
|
|
1639
|
+
);
|
|
1640
|
+
}
|
|
1641
|
+
|
|
1642
|
+
// Default behavior - redirect to base URL
|
|
1643
|
+
const baseUrl = new URL(request.url).origin;
|
|
1644
|
+
return Response.redirect(baseUrl);
|
|
1645
|
+
}
|
|
1518
1646
|
}
|
|
1519
1647
|
|
|
1648
|
+
// A set of classes that have been wrapped with agent context
|
|
1649
|
+
const wrappedClasses = new Set<typeof Agent.prototype.constructor>();
|
|
1650
|
+
|
|
1520
1651
|
/**
|
|
1521
1652
|
* Namespace for creating Agent instances
|
|
1522
1653
|
* @template Agentic Type of the Agent class
|
|
@@ -1832,12 +1963,17 @@ export type EmailSendOptions = {
|
|
|
1832
1963
|
* @param options Options for Agent creation
|
|
1833
1964
|
* @returns Promise resolving to an Agent instance stub
|
|
1834
1965
|
*/
|
|
1835
|
-
export async function getAgentByName<
|
|
1966
|
+
export async function getAgentByName<
|
|
1967
|
+
Env,
|
|
1968
|
+
T extends Agent<Env>,
|
|
1969
|
+
Props extends Record<string, unknown> = Record<string, unknown>
|
|
1970
|
+
>(
|
|
1836
1971
|
namespace: AgentNamespace<T>,
|
|
1837
1972
|
name: string,
|
|
1838
1973
|
options?: {
|
|
1839
1974
|
jurisdiction?: DurableObjectJurisdiction;
|
|
1840
1975
|
locationHint?: DurableObjectLocationHint;
|
|
1976
|
+
props?: Props;
|
|
1841
1977
|
}
|
|
1842
1978
|
) {
|
|
1843
1979
|
return getServerByName<Env, T>(namespace, name, options);
|
|
@@ -1869,7 +2005,7 @@ export class StreamingResponse {
|
|
|
1869
2005
|
id: this._id,
|
|
1870
2006
|
result: chunk,
|
|
1871
2007
|
success: true,
|
|
1872
|
-
type:
|
|
2008
|
+
type: MessageType.RPC
|
|
1873
2009
|
};
|
|
1874
2010
|
this._connection.send(JSON.stringify(response));
|
|
1875
2011
|
}
|
|
@@ -1888,7 +2024,7 @@ export class StreamingResponse {
|
|
|
1888
2024
|
id: this._id,
|
|
1889
2025
|
result: finalChunk,
|
|
1890
2026
|
success: true,
|
|
1891
|
-
type:
|
|
2027
|
+
type: MessageType.RPC
|
|
1892
2028
|
};
|
|
1893
2029
|
this._connection.send(JSON.stringify(response));
|
|
1894
2030
|
}
|