agents 0.0.0-d1f6c02 → 0.0.0-d40512c
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 +22 -22
- package/dist/ai-chat-agent.d.ts +5 -4
- package/dist/ai-chat-agent.js +64 -26
- package/dist/ai-chat-agent.js.map +1 -1
- package/dist/ai-react.d.ts +10 -9
- package/dist/ai-react.js +27 -27
- package/dist/ai-react.js.map +1 -1
- package/dist/{chunk-Y67CHZBI.js → chunk-4RBEYCWK.js} +23 -18
- package/dist/chunk-4RBEYCWK.js.map +1 -0
- package/dist/{chunk-QSGN3REV.js → chunk-KUH345EY.js} +8 -15
- package/dist/chunk-KUH345EY.js.map +1 -0
- package/dist/{chunk-AXSPGBHI.js → chunk-LU2RSO54.js} +208 -81
- package/dist/chunk-LU2RSO54.js.map +1 -0
- package/dist/{chunk-BZXOAZUX.js → chunk-PVQZBKN7.js} +5 -5
- package/dist/chunk-PVQZBKN7.js.map +1 -0
- package/dist/client.d.ts +8 -2
- package/dist/client.js +1 -1
- package/dist/index-CITGJflw.d.ts +486 -0
- package/dist/index.d.ts +25 -405
- package/dist/index.js +4 -4
- package/dist/mcp/client.d.ts +281 -9
- package/dist/mcp/client.js +1 -1
- package/dist/mcp/do-oauth-client-provider.js +1 -1
- package/dist/mcp/index.d.ts +9 -9
- package/dist/mcp/index.js +53 -49
- package/dist/mcp/index.js.map +1 -1
- package/dist/observability/index.d.ts +12 -0
- package/dist/observability/index.js +10 -0
- package/dist/observability/index.js.map +1 -0
- package/dist/react.d.ts +56 -38
- package/dist/react.js +16 -6
- package/dist/react.js.map +1 -1
- package/dist/schedule.d.ts +6 -6
- package/dist/schedule.js +4 -4
- package/dist/schedule.js.map +1 -1
- package/dist/serializable.d.ts +32 -0
- package/dist/serializable.js +1 -0
- package/dist/serializable.js.map +1 -0
- package/package.json +75 -72
- package/src/index.ts +232 -117
- package/dist/chunk-AXSPGBHI.js.map +0 -1
- package/dist/chunk-BZXOAZUX.js.map +0 -1
- package/dist/chunk-QSGN3REV.js.map +0 -1
- package/dist/chunk-Y67CHZBI.js.map +0 -1
package/src/index.ts
CHANGED
|
@@ -1,35 +1,31 @@
|
|
|
1
|
-
import {
|
|
2
|
-
Server,
|
|
3
|
-
routePartykitRequest,
|
|
4
|
-
type PartyServerOptions,
|
|
5
|
-
getServerByName,
|
|
6
|
-
type Connection,
|
|
7
|
-
type ConnectionContext,
|
|
8
|
-
type WSMessage,
|
|
9
|
-
} from "partyserver";
|
|
10
|
-
|
|
11
|
-
import { parseCronExpression } from "cron-schedule";
|
|
12
|
-
import { nanoid } from "nanoid";
|
|
13
|
-
|
|
14
1
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
|
|
18
|
-
type AgentsOAuthProvider,
|
|
19
|
-
} from "./mcp/do-oauth-client-provider";
|
|
2
|
+
import type { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
3
|
+
import type { SSEClientTransportOptions } from "@modelcontextprotocol/sdk/client/sse.js";
|
|
4
|
+
|
|
20
5
|
import type {
|
|
21
|
-
Tool,
|
|
22
|
-
Resource,
|
|
23
6
|
Prompt,
|
|
7
|
+
Resource,
|
|
24
8
|
ServerCapabilities,
|
|
9
|
+
Tool
|
|
25
10
|
} from "@modelcontextprotocol/sdk/types.js";
|
|
26
|
-
|
|
27
|
-
import
|
|
28
|
-
import
|
|
29
|
-
|
|
11
|
+
import { parseCronExpression } from "cron-schedule";
|
|
12
|
+
import { nanoid } from "nanoid";
|
|
13
|
+
import {
|
|
14
|
+
type Connection,
|
|
15
|
+
type ConnectionContext,
|
|
16
|
+
getServerByName,
|
|
17
|
+
type PartyServerOptions,
|
|
18
|
+
routePartykitRequest,
|
|
19
|
+
Server,
|
|
20
|
+
type WSMessage
|
|
21
|
+
} from "partyserver";
|
|
30
22
|
import { camelCaseToKebabCase } from "./client";
|
|
23
|
+
import { MCPClientManager } from "./mcp/client";
|
|
24
|
+
// import type { MCPClientConnection } from "./mcp/client-connection";
|
|
25
|
+
import { DurableObjectOAuthClientProvider } from "./mcp/do-oauth-client-provider";
|
|
26
|
+
import { genericObservability, type Observability } from "./observability";
|
|
31
27
|
|
|
32
|
-
export type { Connection,
|
|
28
|
+
export type { Connection, ConnectionContext, WSMessage } from "partyserver";
|
|
33
29
|
|
|
34
30
|
/**
|
|
35
31
|
* RPC request message from client
|
|
@@ -122,6 +118,7 @@ const callableMetadata = new Map<Function, CallableMetadata>();
|
|
|
122
118
|
export function unstable_callable(metadata: CallableMetadata = {}) {
|
|
123
119
|
return function callableDecorator<This, Args extends unknown[], Return>(
|
|
124
120
|
target: (this: This, ...args: Args) => Return,
|
|
121
|
+
// biome-ignore lint/correctness/noUnusedFunctionParameters: later
|
|
125
122
|
context: ClassMethodDecoratorContext
|
|
126
123
|
) {
|
|
127
124
|
if (!callableMetadata.has(target)) {
|
|
@@ -194,6 +191,9 @@ export type MCPServer = {
|
|
|
194
191
|
name: string;
|
|
195
192
|
server_url: string;
|
|
196
193
|
auth_url: string | null;
|
|
194
|
+
// This state is specifically about the temporary process of getting a token (if needed).
|
|
195
|
+
// Scope outside of that can't be relied upon because when the DO sleeps, there's no way
|
|
196
|
+
// to communicate a change to a non-ready state.
|
|
197
197
|
state: "authenticating" | "connecting" | "ready" | "discovering" | "failed";
|
|
198
198
|
instructions: string | null;
|
|
199
199
|
capabilities: ServerCapabilities | null;
|
|
@@ -224,7 +224,7 @@ const agentContext = new AsyncLocalStorage<{
|
|
|
224
224
|
}>();
|
|
225
225
|
|
|
226
226
|
export function getCurrentAgent<
|
|
227
|
-
T extends Agent<unknown, unknown> = Agent<unknown, unknown
|
|
227
|
+
T extends Agent<unknown, unknown> = Agent<unknown, unknown>
|
|
228
228
|
>(): {
|
|
229
229
|
agent: T | undefined;
|
|
230
230
|
connection: Connection | undefined;
|
|
@@ -241,7 +241,7 @@ export function getCurrentAgent<
|
|
|
241
241
|
return {
|
|
242
242
|
agent: undefined,
|
|
243
243
|
connection: undefined,
|
|
244
|
-
request: undefined
|
|
244
|
+
request: undefined
|
|
245
245
|
};
|
|
246
246
|
}
|
|
247
247
|
return store;
|
|
@@ -314,9 +314,14 @@ export class Agent<Env, State = unknown> extends Server<Env> {
|
|
|
314
314
|
*/
|
|
315
315
|
static options = {
|
|
316
316
|
/** Whether the Agent should hibernate when inactive */
|
|
317
|
-
hibernate: true
|
|
317
|
+
hibernate: true // default to hibernate
|
|
318
318
|
};
|
|
319
319
|
|
|
320
|
+
/**
|
|
321
|
+
* The observability implementation to use for the Agent
|
|
322
|
+
*/
|
|
323
|
+
observability?: Observability = genericObservability;
|
|
324
|
+
|
|
320
325
|
/**
|
|
321
326
|
* Execute SQL queries against the Agent's database
|
|
322
327
|
* @template T Type of the returned rows
|
|
@@ -397,15 +402,15 @@ export class Agent<Env, State = unknown> extends Server<Env> {
|
|
|
397
402
|
// after the MCP connection handshake, we can send updated mcp state
|
|
398
403
|
this.broadcast(
|
|
399
404
|
JSON.stringify({
|
|
400
|
-
|
|
401
|
-
|
|
405
|
+
mcp: this.getMcpServers(),
|
|
406
|
+
type: "cf_agent_mcp_servers"
|
|
402
407
|
})
|
|
403
408
|
);
|
|
404
409
|
|
|
405
410
|
// We probably should let the user configure this response/redirect, but this is fine for now.
|
|
406
411
|
return new Response("<script>window.close();</script>", {
|
|
407
|
-
status: 200,
|
|
408
412
|
headers: { "content-type": "text/html" },
|
|
413
|
+
status: 200
|
|
409
414
|
});
|
|
410
415
|
}
|
|
411
416
|
|
|
@@ -426,7 +431,7 @@ export class Agent<Env, State = unknown> extends Server<Env> {
|
|
|
426
431
|
let parsed: unknown;
|
|
427
432
|
try {
|
|
428
433
|
parsed = JSON.parse(message);
|
|
429
|
-
} catch (
|
|
434
|
+
} catch (_e) {
|
|
430
435
|
// silently fail and let the onMessage handler handle it
|
|
431
436
|
return this._tryCatch(() => _onMessage(connection, message));
|
|
432
437
|
}
|
|
@@ -461,22 +466,39 @@ export class Agent<Env, State = unknown> extends Server<Env> {
|
|
|
461
466
|
|
|
462
467
|
// For regular methods, execute and send response
|
|
463
468
|
const result = await methodFn.apply(this, args);
|
|
469
|
+
|
|
470
|
+
this.observability?.emit(
|
|
471
|
+
{
|
|
472
|
+
displayMessage: `RPC call to ${method}`,
|
|
473
|
+
id: nanoid(),
|
|
474
|
+
payload: {
|
|
475
|
+
args,
|
|
476
|
+
method,
|
|
477
|
+
streaming: metadata?.streaming,
|
|
478
|
+
success: true
|
|
479
|
+
},
|
|
480
|
+
timestamp: Date.now(),
|
|
481
|
+
type: "rpc"
|
|
482
|
+
},
|
|
483
|
+
this.ctx
|
|
484
|
+
);
|
|
485
|
+
|
|
464
486
|
const response: RPCResponse = {
|
|
465
|
-
|
|
487
|
+
done: true,
|
|
466
488
|
id,
|
|
467
|
-
success: true,
|
|
468
489
|
result,
|
|
469
|
-
|
|
490
|
+
success: true,
|
|
491
|
+
type: "rpc"
|
|
470
492
|
};
|
|
471
493
|
connection.send(JSON.stringify(response));
|
|
472
494
|
} catch (e) {
|
|
473
495
|
// Send error response
|
|
474
496
|
const response: RPCResponse = {
|
|
475
|
-
type: "rpc",
|
|
476
|
-
id: parsed.id,
|
|
477
|
-
success: false,
|
|
478
497
|
error:
|
|
479
498
|
e instanceof Error ? e.message : "Unknown error occurred",
|
|
499
|
+
id: parsed.id,
|
|
500
|
+
success: false,
|
|
501
|
+
type: "rpc"
|
|
480
502
|
};
|
|
481
503
|
connection.send(JSON.stringify(response));
|
|
482
504
|
console.error("RPC error:", e);
|
|
@@ -500,19 +522,31 @@ export class Agent<Env, State = unknown> extends Server<Env> {
|
|
|
500
522
|
if (this.state) {
|
|
501
523
|
connection.send(
|
|
502
524
|
JSON.stringify({
|
|
503
|
-
type: "cf_agent_state",
|
|
504
525
|
state: this.state,
|
|
526
|
+
type: "cf_agent_state"
|
|
505
527
|
})
|
|
506
528
|
);
|
|
507
529
|
}
|
|
508
530
|
|
|
509
531
|
connection.send(
|
|
510
532
|
JSON.stringify({
|
|
511
|
-
|
|
512
|
-
|
|
533
|
+
mcp: this.getMcpServers(),
|
|
534
|
+
type: "cf_agent_mcp_servers"
|
|
513
535
|
})
|
|
514
536
|
);
|
|
515
537
|
|
|
538
|
+
this.observability?.emit(
|
|
539
|
+
{
|
|
540
|
+
displayMessage: "Connection established",
|
|
541
|
+
id: nanoid(),
|
|
542
|
+
payload: {
|
|
543
|
+
connectionId: connection.id
|
|
544
|
+
},
|
|
545
|
+
timestamp: Date.now(),
|
|
546
|
+
type: "connect"
|
|
547
|
+
},
|
|
548
|
+
this.ctx
|
|
549
|
+
);
|
|
516
550
|
return this._tryCatch(() => _onConnect(connection, ctx));
|
|
517
551
|
}, 20);
|
|
518
552
|
}
|
|
@@ -528,8 +562,8 @@ export class Agent<Env, State = unknown> extends Server<Env> {
|
|
|
528
562
|
SELECT id, name, server_url, client_id, auth_url, callback_url, server_options FROM cf_agents_mcp_servers;
|
|
529
563
|
`;
|
|
530
564
|
|
|
531
|
-
// from DO storage, reconnect to all servers using our saved auth information
|
|
532
|
-
|
|
565
|
+
// from DO storage, reconnect to all servers not currently in the oauth flow using our saved auth information
|
|
566
|
+
Promise.allSettled(
|
|
533
567
|
servers.map((server) => {
|
|
534
568
|
return this._connectToMcpServerInternal(
|
|
535
569
|
server.name,
|
|
@@ -540,19 +574,18 @@ export class Agent<Env, State = unknown> extends Server<Env> {
|
|
|
540
574
|
: undefined,
|
|
541
575
|
{
|
|
542
576
|
id: server.id,
|
|
543
|
-
oauthClientId: server.client_id ?? undefined
|
|
577
|
+
oauthClientId: server.client_id ?? undefined
|
|
544
578
|
}
|
|
545
579
|
);
|
|
546
580
|
})
|
|
547
|
-
)
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
);
|
|
555
|
-
|
|
581
|
+
).then((_results) => {
|
|
582
|
+
this.broadcast(
|
|
583
|
+
JSON.stringify({
|
|
584
|
+
mcp: this.getMcpServers(),
|
|
585
|
+
type: "cf_agent_mcp_servers"
|
|
586
|
+
})
|
|
587
|
+
);
|
|
588
|
+
});
|
|
556
589
|
await this._tryCatch(() => _onStart());
|
|
557
590
|
}
|
|
558
591
|
);
|
|
@@ -563,6 +596,7 @@ export class Agent<Env, State = unknown> extends Server<Env> {
|
|
|
563
596
|
state: State,
|
|
564
597
|
source: Connection | "server" = "server"
|
|
565
598
|
) {
|
|
599
|
+
const previousState = this._state;
|
|
566
600
|
this._state = state;
|
|
567
601
|
this.sql`
|
|
568
602
|
INSERT OR REPLACE INTO cf_agents_state (id, state)
|
|
@@ -574,8 +608,8 @@ export class Agent<Env, State = unknown> extends Server<Env> {
|
|
|
574
608
|
`;
|
|
575
609
|
this.broadcast(
|
|
576
610
|
JSON.stringify({
|
|
577
|
-
type: "cf_agent_state",
|
|
578
611
|
state: state,
|
|
612
|
+
type: "cf_agent_state"
|
|
579
613
|
}),
|
|
580
614
|
source !== "server" ? [source.id] : []
|
|
581
615
|
);
|
|
@@ -584,6 +618,19 @@ export class Agent<Env, State = unknown> extends Server<Env> {
|
|
|
584
618
|
return agentContext.run(
|
|
585
619
|
{ agent: this, connection, request },
|
|
586
620
|
async () => {
|
|
621
|
+
this.observability?.emit(
|
|
622
|
+
{
|
|
623
|
+
displayMessage: "State updated",
|
|
624
|
+
id: nanoid(),
|
|
625
|
+
payload: {
|
|
626
|
+
previousState,
|
|
627
|
+
state
|
|
628
|
+
},
|
|
629
|
+
timestamp: Date.now(),
|
|
630
|
+
type: "state:update"
|
|
631
|
+
},
|
|
632
|
+
this.ctx
|
|
633
|
+
);
|
|
587
634
|
return this.onStateUpdate(state, source);
|
|
588
635
|
}
|
|
589
636
|
);
|
|
@@ -603,6 +650,7 @@ export class Agent<Env, State = unknown> extends Server<Env> {
|
|
|
603
650
|
* @param state Updated state
|
|
604
651
|
* @param source Source of the state update ("server" or a client connection)
|
|
605
652
|
*/
|
|
653
|
+
// biome-ignore lint/correctness/noUnusedFunctionParameters: overridden later
|
|
606
654
|
onStateUpdate(state: State | undefined, source: Connection | "server") {
|
|
607
655
|
// override this to handle state updates
|
|
608
656
|
}
|
|
@@ -611,6 +659,7 @@ export class Agent<Env, State = unknown> extends Server<Env> {
|
|
|
611
659
|
* Called when the Agent receives an email
|
|
612
660
|
* @param email Email message to process
|
|
613
661
|
*/
|
|
662
|
+
// biome-ignore lint/correctness/noUnusedFunctionParameters: overridden later
|
|
614
663
|
onEmail(email: ForwardableEmailMessage) {
|
|
615
664
|
return agentContext.run(
|
|
616
665
|
{ agent: this, connection: undefined, request: undefined },
|
|
@@ -677,6 +726,18 @@ export class Agent<Env, State = unknown> extends Server<Env> {
|
|
|
677
726
|
): Promise<Schedule<T>> {
|
|
678
727
|
const id = nanoid(9);
|
|
679
728
|
|
|
729
|
+
const emitScheduleCreate = (schedule: Schedule<T>) =>
|
|
730
|
+
this.observability?.emit(
|
|
731
|
+
{
|
|
732
|
+
displayMessage: `Schedule ${schedule.id} created`,
|
|
733
|
+
id: nanoid(),
|
|
734
|
+
payload: schedule,
|
|
735
|
+
timestamp: Date.now(),
|
|
736
|
+
type: "schedule:create"
|
|
737
|
+
},
|
|
738
|
+
this.ctx
|
|
739
|
+
);
|
|
740
|
+
|
|
680
741
|
if (typeof callback !== "string") {
|
|
681
742
|
throw new Error("Callback must be a string");
|
|
682
743
|
}
|
|
@@ -696,13 +757,17 @@ export class Agent<Env, State = unknown> extends Server<Env> {
|
|
|
696
757
|
|
|
697
758
|
await this._scheduleNextAlarm();
|
|
698
759
|
|
|
699
|
-
|
|
700
|
-
id,
|
|
760
|
+
const schedule: Schedule<T> = {
|
|
701
761
|
callback: callback,
|
|
762
|
+
id,
|
|
702
763
|
payload: payload as T,
|
|
703
764
|
time: timestamp,
|
|
704
|
-
type: "scheduled"
|
|
765
|
+
type: "scheduled"
|
|
705
766
|
};
|
|
767
|
+
|
|
768
|
+
emitScheduleCreate(schedule);
|
|
769
|
+
|
|
770
|
+
return schedule;
|
|
706
771
|
}
|
|
707
772
|
if (typeof when === "number") {
|
|
708
773
|
const time = new Date(Date.now() + when * 1000);
|
|
@@ -717,14 +782,18 @@ export class Agent<Env, State = unknown> extends Server<Env> {
|
|
|
717
782
|
|
|
718
783
|
await this._scheduleNextAlarm();
|
|
719
784
|
|
|
720
|
-
|
|
721
|
-
id,
|
|
785
|
+
const schedule: Schedule<T> = {
|
|
722
786
|
callback: callback,
|
|
723
|
-
payload: payload as T,
|
|
724
787
|
delayInSeconds: when,
|
|
788
|
+
id,
|
|
789
|
+
payload: payload as T,
|
|
725
790
|
time: timestamp,
|
|
726
|
-
type: "delayed"
|
|
791
|
+
type: "delayed"
|
|
727
792
|
};
|
|
793
|
+
|
|
794
|
+
emitScheduleCreate(schedule);
|
|
795
|
+
|
|
796
|
+
return schedule;
|
|
728
797
|
}
|
|
729
798
|
if (typeof when === "string") {
|
|
730
799
|
const nextExecutionTime = getNextCronTime(when);
|
|
@@ -739,14 +808,18 @@ export class Agent<Env, State = unknown> extends Server<Env> {
|
|
|
739
808
|
|
|
740
809
|
await this._scheduleNextAlarm();
|
|
741
810
|
|
|
742
|
-
|
|
743
|
-
id,
|
|
811
|
+
const schedule: Schedule<T> = {
|
|
744
812
|
callback: callback,
|
|
745
|
-
payload: payload as T,
|
|
746
813
|
cron: when,
|
|
814
|
+
id,
|
|
815
|
+
payload: payload as T,
|
|
747
816
|
time: timestamp,
|
|
748
|
-
type: "cron"
|
|
817
|
+
type: "cron"
|
|
749
818
|
};
|
|
819
|
+
|
|
820
|
+
emitScheduleCreate(schedule);
|
|
821
|
+
|
|
822
|
+
return schedule;
|
|
750
823
|
}
|
|
751
824
|
throw new Error("Invalid schedule type");
|
|
752
825
|
}
|
|
@@ -810,7 +883,7 @@ export class Agent<Env, State = unknown> extends Server<Env> {
|
|
|
810
883
|
.toArray()
|
|
811
884
|
.map((row) => ({
|
|
812
885
|
...row,
|
|
813
|
-
payload: JSON.parse(row.payload as string) as T
|
|
886
|
+
payload: JSON.parse(row.payload as string) as T
|
|
814
887
|
})) as Schedule<T>[];
|
|
815
888
|
|
|
816
889
|
return result;
|
|
@@ -822,6 +895,19 @@ export class Agent<Env, State = unknown> extends Server<Env> {
|
|
|
822
895
|
* @returns true if the task was cancelled, false otherwise
|
|
823
896
|
*/
|
|
824
897
|
async cancelSchedule(id: string): Promise<boolean> {
|
|
898
|
+
const schedule = await this.getSchedule(id);
|
|
899
|
+
if (schedule) {
|
|
900
|
+
this.observability?.emit(
|
|
901
|
+
{
|
|
902
|
+
displayMessage: `Schedule ${id} cancelled`,
|
|
903
|
+
id: nanoid(),
|
|
904
|
+
payload: schedule,
|
|
905
|
+
timestamp: Date.now(),
|
|
906
|
+
type: "schedule:cancel"
|
|
907
|
+
},
|
|
908
|
+
this.ctx
|
|
909
|
+
);
|
|
910
|
+
}
|
|
825
911
|
this.sql`DELETE FROM cf_agents_schedules WHERE id = ${id}`;
|
|
826
912
|
|
|
827
913
|
await this._scheduleNextAlarm();
|
|
@@ -870,6 +956,17 @@ export class Agent<Env, State = unknown> extends Server<Env> {
|
|
|
870
956
|
{ agent: this, connection: undefined, request: undefined },
|
|
871
957
|
async () => {
|
|
872
958
|
try {
|
|
959
|
+
this.observability?.emit(
|
|
960
|
+
{
|
|
961
|
+
displayMessage: `Schedule ${row.id} executed`,
|
|
962
|
+
id: nanoid(),
|
|
963
|
+
payload: row,
|
|
964
|
+
timestamp: Date.now(),
|
|
965
|
+
type: "schedule:execute"
|
|
966
|
+
},
|
|
967
|
+
this.ctx
|
|
968
|
+
);
|
|
969
|
+
|
|
873
970
|
await (
|
|
874
971
|
callback as (
|
|
875
972
|
payload: unknown,
|
|
@@ -913,6 +1010,18 @@ export class Agent<Env, State = unknown> extends Server<Env> {
|
|
|
913
1010
|
// delete all alarms
|
|
914
1011
|
await this.ctx.storage.deleteAlarm();
|
|
915
1012
|
await this.ctx.storage.deleteAll();
|
|
1013
|
+
this.ctx.abort("destroyed"); // enforce that the agent is evicted
|
|
1014
|
+
|
|
1015
|
+
this.observability?.emit(
|
|
1016
|
+
{
|
|
1017
|
+
displayMessage: "Agent destroyed",
|
|
1018
|
+
id: nanoid(),
|
|
1019
|
+
payload: {},
|
|
1020
|
+
timestamp: Date.now(),
|
|
1021
|
+
type: "destroy"
|
|
1022
|
+
},
|
|
1023
|
+
this.ctx
|
|
1024
|
+
);
|
|
916
1025
|
}
|
|
917
1026
|
|
|
918
1027
|
/**
|
|
@@ -952,11 +1061,24 @@ export class Agent<Env, State = unknown> extends Server<Env> {
|
|
|
952
1061
|
callbackUrl,
|
|
953
1062
|
options
|
|
954
1063
|
);
|
|
1064
|
+
this.sql`
|
|
1065
|
+
INSERT
|
|
1066
|
+
OR REPLACE INTO cf_agents_mcp_servers (id, name, server_url, client_id, auth_url, callback_url, server_options)
|
|
1067
|
+
VALUES (
|
|
1068
|
+
${result.id},
|
|
1069
|
+
${serverName},
|
|
1070
|
+
${url},
|
|
1071
|
+
${result.clientId ?? null},
|
|
1072
|
+
${result.authUrl ?? null},
|
|
1073
|
+
${callbackUrl},
|
|
1074
|
+
${options ? JSON.stringify(options) : null}
|
|
1075
|
+
);
|
|
1076
|
+
`;
|
|
955
1077
|
|
|
956
1078
|
this.broadcast(
|
|
957
1079
|
JSON.stringify({
|
|
958
|
-
|
|
959
|
-
|
|
1080
|
+
mcp: this.getMcpServers(),
|
|
1081
|
+
type: "cf_agent_mcp_servers"
|
|
960
1082
|
})
|
|
961
1083
|
);
|
|
962
1084
|
|
|
@@ -964,7 +1086,7 @@ export class Agent<Env, State = unknown> extends Server<Env> {
|
|
|
964
1086
|
}
|
|
965
1087
|
|
|
966
1088
|
async _connectToMcpServerInternal(
|
|
967
|
-
|
|
1089
|
+
_serverName: string,
|
|
968
1090
|
url: string,
|
|
969
1091
|
callbackUrl: string,
|
|
970
1092
|
// it's important that any options here are serializable because we put them into our sqlite DB for reconnection purposes
|
|
@@ -985,7 +1107,11 @@ export class Agent<Env, State = unknown> extends Server<Env> {
|
|
|
985
1107
|
id: string;
|
|
986
1108
|
oauthClientId?: string;
|
|
987
1109
|
}
|
|
988
|
-
): Promise<{
|
|
1110
|
+
): Promise<{
|
|
1111
|
+
id: string;
|
|
1112
|
+
authUrl: string | undefined;
|
|
1113
|
+
clientId: string | undefined;
|
|
1114
|
+
}> {
|
|
989
1115
|
const authProvider = new DurableObjectOAuthClientProvider(
|
|
990
1116
|
this.ctx.storage,
|
|
991
1117
|
this.name,
|
|
@@ -1008,40 +1134,28 @@ export class Agent<Env, State = unknown> extends Server<Env> {
|
|
|
1008
1134
|
fetch: (url, init) =>
|
|
1009
1135
|
fetch(url, {
|
|
1010
1136
|
...init,
|
|
1011
|
-
headers: options?.transport?.headers
|
|
1012
|
-
})
|
|
1137
|
+
headers: options?.transport?.headers
|
|
1138
|
+
})
|
|
1013
1139
|
},
|
|
1014
1140
|
requestInit: {
|
|
1015
|
-
headers: options?.transport?.headers
|
|
1016
|
-
}
|
|
1141
|
+
headers: options?.transport?.headers
|
|
1142
|
+
}
|
|
1017
1143
|
};
|
|
1018
1144
|
}
|
|
1019
1145
|
|
|
1020
1146
|
const { id, authUrl, clientId } = await this.mcp.connect(url, {
|
|
1147
|
+
client: options?.client,
|
|
1021
1148
|
reconnect,
|
|
1022
1149
|
transport: {
|
|
1023
1150
|
...headerTransportOpts,
|
|
1024
|
-
authProvider
|
|
1025
|
-
}
|
|
1026
|
-
client: options?.client,
|
|
1151
|
+
authProvider
|
|
1152
|
+
}
|
|
1027
1153
|
});
|
|
1028
1154
|
|
|
1029
|
-
this.sql`
|
|
1030
|
-
INSERT OR REPLACE INTO cf_agents_mcp_servers (id, name, server_url, client_id, auth_url, callback_url, server_options)
|
|
1031
|
-
VALUES (
|
|
1032
|
-
${id},
|
|
1033
|
-
${serverName},
|
|
1034
|
-
${url},
|
|
1035
|
-
${clientId ?? null},
|
|
1036
|
-
${authUrl ?? null},
|
|
1037
|
-
${callbackUrl},
|
|
1038
|
-
${options ? JSON.stringify(options) : null}
|
|
1039
|
-
);
|
|
1040
|
-
`;
|
|
1041
|
-
|
|
1042
1155
|
return {
|
|
1043
|
-
id,
|
|
1044
1156
|
authUrl,
|
|
1157
|
+
clientId,
|
|
1158
|
+
id
|
|
1045
1159
|
};
|
|
1046
1160
|
}
|
|
1047
1161
|
|
|
@@ -1052,18 +1166,18 @@ export class Agent<Env, State = unknown> extends Server<Env> {
|
|
|
1052
1166
|
`;
|
|
1053
1167
|
this.broadcast(
|
|
1054
1168
|
JSON.stringify({
|
|
1055
|
-
|
|
1056
|
-
|
|
1169
|
+
mcp: this.getMcpServers(),
|
|
1170
|
+
type: "cf_agent_mcp_servers"
|
|
1057
1171
|
})
|
|
1058
1172
|
);
|
|
1059
1173
|
}
|
|
1060
1174
|
|
|
1061
|
-
|
|
1175
|
+
getMcpServers(): MCPServersState {
|
|
1062
1176
|
const mcpState: MCPServersState = {
|
|
1063
|
-
servers: {},
|
|
1064
|
-
tools: this.mcp.listTools(),
|
|
1065
1177
|
prompts: this.mcp.listPrompts(),
|
|
1066
1178
|
resources: this.mcp.listResources(),
|
|
1179
|
+
servers: {},
|
|
1180
|
+
tools: this.mcp.listTools()
|
|
1067
1181
|
};
|
|
1068
1182
|
|
|
1069
1183
|
const servers = this.sql<MCPServerRow>`
|
|
@@ -1071,14 +1185,15 @@ export class Agent<Env, State = unknown> extends Server<Env> {
|
|
|
1071
1185
|
`;
|
|
1072
1186
|
|
|
1073
1187
|
for (const server of servers) {
|
|
1188
|
+
const serverConn = this.mcp.mcpConnections[server.id];
|
|
1074
1189
|
mcpState.servers[server.id] = {
|
|
1190
|
+
auth_url: server.auth_url,
|
|
1191
|
+
capabilities: serverConn?.serverCapabilities ?? null,
|
|
1192
|
+
instructions: serverConn?.instructions ?? null,
|
|
1075
1193
|
name: server.name,
|
|
1076
1194
|
server_url: server.server_url,
|
|
1077
|
-
|
|
1078
|
-
state:
|
|
1079
|
-
instructions: this.mcp.mcpConnections[server.id].instructions ?? null,
|
|
1080
|
-
capabilities:
|
|
1081
|
-
this.mcp.mcpConnections[server.id].serverCapabilities ?? null,
|
|
1195
|
+
// mark as "authenticating" because the server isn't automatically connected, so it's pending authenticating
|
|
1196
|
+
state: serverConn?.connectionState ?? "authenticating"
|
|
1082
1197
|
};
|
|
1083
1198
|
}
|
|
1084
1199
|
|
|
@@ -1123,17 +1238,17 @@ export async function routeAgentRequest<Env>(
|
|
|
1123
1238
|
const corsHeaders =
|
|
1124
1239
|
options?.cors === true
|
|
1125
1240
|
? {
|
|
1126
|
-
"Access-Control-Allow-Origin": "*",
|
|
1127
|
-
"Access-Control-Allow-Methods": "GET, POST, HEAD, OPTIONS",
|
|
1128
1241
|
"Access-Control-Allow-Credentials": "true",
|
|
1129
|
-
"Access-Control-
|
|
1242
|
+
"Access-Control-Allow-Methods": "GET, POST, HEAD, OPTIONS",
|
|
1243
|
+
"Access-Control-Allow-Origin": "*",
|
|
1244
|
+
"Access-Control-Max-Age": "86400"
|
|
1130
1245
|
}
|
|
1131
1246
|
: options?.cors;
|
|
1132
1247
|
|
|
1133
1248
|
if (request.method === "OPTIONS") {
|
|
1134
1249
|
if (corsHeaders) {
|
|
1135
1250
|
return new Response(null, {
|
|
1136
|
-
headers: corsHeaders
|
|
1251
|
+
headers: corsHeaders
|
|
1137
1252
|
});
|
|
1138
1253
|
}
|
|
1139
1254
|
console.warn(
|
|
@@ -1146,7 +1261,7 @@ export async function routeAgentRequest<Env>(
|
|
|
1146
1261
|
env as Record<string, unknown>,
|
|
1147
1262
|
{
|
|
1148
1263
|
prefix: "agents",
|
|
1149
|
-
...(options as PartyServerOptions<Record<string, unknown>>)
|
|
1264
|
+
...(options as PartyServerOptions<Record<string, unknown>>)
|
|
1150
1265
|
}
|
|
1151
1266
|
);
|
|
1152
1267
|
|
|
@@ -1159,8 +1274,8 @@ export async function routeAgentRequest<Env>(
|
|
|
1159
1274
|
response = new Response(response.body, {
|
|
1160
1275
|
headers: {
|
|
1161
1276
|
...response.headers,
|
|
1162
|
-
...corsHeaders
|
|
1163
|
-
}
|
|
1277
|
+
...corsHeaders
|
|
1278
|
+
}
|
|
1164
1279
|
});
|
|
1165
1280
|
}
|
|
1166
1281
|
return response;
|
|
@@ -1173,9 +1288,9 @@ export async function routeAgentRequest<Env>(
|
|
|
1173
1288
|
* @param options Routing options
|
|
1174
1289
|
*/
|
|
1175
1290
|
export async function routeAgentEmail<Env>(
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1291
|
+
_email: ForwardableEmailMessage,
|
|
1292
|
+
_env: Env,
|
|
1293
|
+
_options?: AgentOptions<Env>
|
|
1179
1294
|
): Promise<void> {}
|
|
1180
1295
|
|
|
1181
1296
|
/**
|
|
@@ -1220,11 +1335,11 @@ export class StreamingResponse {
|
|
|
1220
1335
|
throw new Error("StreamingResponse is already closed");
|
|
1221
1336
|
}
|
|
1222
1337
|
const response: RPCResponse = {
|
|
1223
|
-
|
|
1338
|
+
done: false,
|
|
1224
1339
|
id: this._id,
|
|
1225
|
-
success: true,
|
|
1226
1340
|
result: chunk,
|
|
1227
|
-
|
|
1341
|
+
success: true,
|
|
1342
|
+
type: "rpc"
|
|
1228
1343
|
};
|
|
1229
1344
|
this._connection.send(JSON.stringify(response));
|
|
1230
1345
|
}
|
|
@@ -1239,11 +1354,11 @@ export class StreamingResponse {
|
|
|
1239
1354
|
}
|
|
1240
1355
|
this._closed = true;
|
|
1241
1356
|
const response: RPCResponse = {
|
|
1242
|
-
|
|
1357
|
+
done: true,
|
|
1243
1358
|
id: this._id,
|
|
1244
|
-
success: true,
|
|
1245
1359
|
result: finalChunk,
|
|
1246
|
-
|
|
1360
|
+
success: true,
|
|
1361
|
+
type: "rpc"
|
|
1247
1362
|
};
|
|
1248
1363
|
this._connection.send(JSON.stringify(response));
|
|
1249
1364
|
}
|