agents 0.0.0-7f84d28 → 0.0.0-8157d08
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/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 +9 -8
- package/dist/ai-react.js +27 -27
- package/dist/ai-react.js.map +1 -1
- package/dist/{chunk-BZXOAZUX.js → chunk-767EASBA.js} +5 -5
- package/dist/{chunk-BZXOAZUX.js.map → chunk-767EASBA.js.map} +1 -1
- package/dist/{chunk-Y67CHZBI.js → chunk-E3LCYPCB.js} +23 -18
- package/dist/chunk-E3LCYPCB.js.map +1 -0
- package/dist/{chunk-RIYR6FR6.js → chunk-JFRK72K3.js} +212 -79
- package/dist/chunk-JFRK72K3.js.map +1 -0
- package/dist/{chunk-QSGN3REV.js → chunk-NKZZ66QY.js} +8 -15
- package/dist/chunk-NKZZ66QY.js.map +1 -0
- package/dist/client.d.ts +6 -0
- package/dist/client.js +1 -1
- package/dist/index-CITGJflw.d.ts +486 -0
- package/dist/index.d.ts +25 -394
- 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 +6 -6
- 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 +76 -10
- 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 -71
- package/src/index.ts +215 -93
- package/dist/chunk-QSGN3REV.js.map +0 -1
- package/dist/chunk-RIYR6FR6.js.map +0 -1
- package/dist/chunk-Y67CHZBI.js.map +0 -1
package/src/index.ts
CHANGED
|
@@ -1,34 +1,31 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2
|
+
import type { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
3
|
+
import type { SSEClientTransportOptions } from "@modelcontextprotocol/sdk/client/sse.js";
|
|
4
|
+
|
|
5
|
+
import type {
|
|
6
|
+
Prompt,
|
|
7
|
+
Resource,
|
|
8
|
+
ServerCapabilities,
|
|
9
|
+
Tool,
|
|
10
|
+
} from "@modelcontextprotocol/sdk/types.js";
|
|
11
|
+
import { parseCronExpression } from "cron-schedule";
|
|
12
|
+
import { nanoid } from "nanoid";
|
|
1
13
|
import {
|
|
2
|
-
Server,
|
|
3
|
-
routePartykitRequest,
|
|
4
|
-
type PartyServerOptions,
|
|
5
|
-
getServerByName,
|
|
6
14
|
type Connection,
|
|
7
15
|
type ConnectionContext,
|
|
16
|
+
getServerByName,
|
|
17
|
+
type PartyServerOptions,
|
|
18
|
+
routePartykitRequest,
|
|
19
|
+
Server,
|
|
8
20
|
type WSMessage,
|
|
9
21
|
} from "partyserver";
|
|
10
|
-
|
|
11
|
-
import { parseCronExpression } from "cron-schedule";
|
|
12
|
-
import { nanoid } from "nanoid";
|
|
13
|
-
|
|
14
|
-
import { AsyncLocalStorage } from "node:async_hooks";
|
|
15
|
-
import { MCPClientManager } from "./mcp/client";
|
|
16
|
-
import {
|
|
17
|
-
DurableObjectOAuthClientProvider,
|
|
18
|
-
type AgentsOAuthProvider,
|
|
19
|
-
} from "./mcp/do-oauth-client-provider";
|
|
20
|
-
import type {
|
|
21
|
-
Tool,
|
|
22
|
-
Resource,
|
|
23
|
-
Prompt,
|
|
24
|
-
} from "@modelcontextprotocol/sdk/types.js";
|
|
25
|
-
|
|
26
|
-
import type { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
27
|
-
import type { SSEClientTransportOptions } from "@modelcontextprotocol/sdk/client/sse.js";
|
|
28
|
-
|
|
29
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";
|
|
30
27
|
|
|
31
|
-
export type { Connection,
|
|
28
|
+
export type { Connection, ConnectionContext, WSMessage } from "partyserver";
|
|
32
29
|
|
|
33
30
|
/**
|
|
34
31
|
* RPC request message from client
|
|
@@ -112,7 +109,6 @@ export type CallableMetadata = {
|
|
|
112
109
|
streaming?: boolean;
|
|
113
110
|
};
|
|
114
111
|
|
|
115
|
-
// biome-ignore lint/complexity/noBannedTypes: <explanation>
|
|
116
112
|
const callableMetadata = new Map<Function, CallableMetadata>();
|
|
117
113
|
|
|
118
114
|
/**
|
|
@@ -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,7 +191,12 @@ 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
|
+
instructions: string | null;
|
|
199
|
+
capabilities: ServerCapabilities | null;
|
|
198
200
|
};
|
|
199
201
|
|
|
200
202
|
/**
|
|
@@ -315,6 +317,11 @@ export class Agent<Env, State = unknown> extends Server<Env> {
|
|
|
315
317
|
hibernate: true, // default to hibernate
|
|
316
318
|
};
|
|
317
319
|
|
|
320
|
+
/**
|
|
321
|
+
* The observability implementation to use for the Agent
|
|
322
|
+
*/
|
|
323
|
+
observability?: Observability = genericObservability;
|
|
324
|
+
|
|
318
325
|
/**
|
|
319
326
|
* Execute SQL queries against the Agent's database
|
|
320
327
|
* @template T Type of the returned rows
|
|
@@ -395,15 +402,15 @@ export class Agent<Env, State = unknown> extends Server<Env> {
|
|
|
395
402
|
// after the MCP connection handshake, we can send updated mcp state
|
|
396
403
|
this.broadcast(
|
|
397
404
|
JSON.stringify({
|
|
405
|
+
mcp: this.getMcpServers(),
|
|
398
406
|
type: "cf_agent_mcp_servers",
|
|
399
|
-
mcp: this._getMcpServerStateInternal(),
|
|
400
407
|
})
|
|
401
408
|
);
|
|
402
409
|
|
|
403
410
|
// We probably should let the user configure this response/redirect, but this is fine for now.
|
|
404
411
|
return new Response("<script>window.close();</script>", {
|
|
405
|
-
status: 200,
|
|
406
412
|
headers: { "content-type": "text/html" },
|
|
413
|
+
status: 200,
|
|
407
414
|
});
|
|
408
415
|
}
|
|
409
416
|
|
|
@@ -424,7 +431,7 @@ export class Agent<Env, State = unknown> extends Server<Env> {
|
|
|
424
431
|
let parsed: unknown;
|
|
425
432
|
try {
|
|
426
433
|
parsed = JSON.parse(message);
|
|
427
|
-
} catch (
|
|
434
|
+
} catch (_e) {
|
|
428
435
|
// silently fail and let the onMessage handler handle it
|
|
429
436
|
return this._tryCatch(() => _onMessage(connection, message));
|
|
430
437
|
}
|
|
@@ -448,7 +455,6 @@ export class Agent<Env, State = unknown> extends Server<Env> {
|
|
|
448
455
|
throw new Error(`Method ${method} is not callable`);
|
|
449
456
|
}
|
|
450
457
|
|
|
451
|
-
// biome-ignore lint/complexity/noBannedTypes: <explanation>
|
|
452
458
|
const metadata = callableMetadata.get(methodFn as Function);
|
|
453
459
|
|
|
454
460
|
// For streaming methods, pass a StreamingResponse object
|
|
@@ -460,22 +466,39 @@ export class Agent<Env, State = unknown> extends Server<Env> {
|
|
|
460
466
|
|
|
461
467
|
// For regular methods, execute and send response
|
|
462
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
|
+
|
|
463
486
|
const response: RPCResponse = {
|
|
464
|
-
|
|
487
|
+
done: true,
|
|
465
488
|
id,
|
|
466
|
-
success: true,
|
|
467
489
|
result,
|
|
468
|
-
|
|
490
|
+
success: true,
|
|
491
|
+
type: "rpc",
|
|
469
492
|
};
|
|
470
493
|
connection.send(JSON.stringify(response));
|
|
471
494
|
} catch (e) {
|
|
472
495
|
// Send error response
|
|
473
496
|
const response: RPCResponse = {
|
|
474
|
-
type: "rpc",
|
|
475
|
-
id: parsed.id,
|
|
476
|
-
success: false,
|
|
477
497
|
error:
|
|
478
498
|
e instanceof Error ? e.message : "Unknown error occurred",
|
|
499
|
+
id: parsed.id,
|
|
500
|
+
success: false,
|
|
501
|
+
type: "rpc",
|
|
479
502
|
};
|
|
480
503
|
connection.send(JSON.stringify(response));
|
|
481
504
|
console.error("RPC error:", e);
|
|
@@ -499,19 +522,31 @@ export class Agent<Env, State = unknown> extends Server<Env> {
|
|
|
499
522
|
if (this.state) {
|
|
500
523
|
connection.send(
|
|
501
524
|
JSON.stringify({
|
|
502
|
-
type: "cf_agent_state",
|
|
503
525
|
state: this.state,
|
|
526
|
+
type: "cf_agent_state",
|
|
504
527
|
})
|
|
505
528
|
);
|
|
506
529
|
}
|
|
507
530
|
|
|
508
531
|
connection.send(
|
|
509
532
|
JSON.stringify({
|
|
533
|
+
mcp: this.getMcpServers(),
|
|
510
534
|
type: "cf_agent_mcp_servers",
|
|
511
|
-
mcp: this._getMcpServerStateInternal(),
|
|
512
535
|
})
|
|
513
536
|
);
|
|
514
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
|
+
);
|
|
515
550
|
return this._tryCatch(() => _onConnect(connection, ctx));
|
|
516
551
|
}, 20);
|
|
517
552
|
}
|
|
@@ -527,8 +562,8 @@ export class Agent<Env, State = unknown> extends Server<Env> {
|
|
|
527
562
|
SELECT id, name, server_url, client_id, auth_url, callback_url, server_options FROM cf_agents_mcp_servers;
|
|
528
563
|
`;
|
|
529
564
|
|
|
530
|
-
// from DO storage, reconnect to all servers using our saved auth information
|
|
531
|
-
|
|
565
|
+
// from DO storage, reconnect to all servers not currently in the oauth flow using our saved auth information
|
|
566
|
+
Promise.allSettled(
|
|
532
567
|
servers.map((server) => {
|
|
533
568
|
return this._connectToMcpServerInternal(
|
|
534
569
|
server.name,
|
|
@@ -543,15 +578,14 @@ export class Agent<Env, State = unknown> extends Server<Env> {
|
|
|
543
578
|
}
|
|
544
579
|
);
|
|
545
580
|
})
|
|
546
|
-
)
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
);
|
|
554
|
-
|
|
581
|
+
).then((_results) => {
|
|
582
|
+
this.broadcast(
|
|
583
|
+
JSON.stringify({
|
|
584
|
+
mcp: this.getMcpServers(),
|
|
585
|
+
type: "cf_agent_mcp_servers",
|
|
586
|
+
})
|
|
587
|
+
);
|
|
588
|
+
});
|
|
555
589
|
await this._tryCatch(() => _onStart());
|
|
556
590
|
}
|
|
557
591
|
);
|
|
@@ -562,6 +596,7 @@ export class Agent<Env, State = unknown> extends Server<Env> {
|
|
|
562
596
|
state: State,
|
|
563
597
|
source: Connection | "server" = "server"
|
|
564
598
|
) {
|
|
599
|
+
const previousState = this._state;
|
|
565
600
|
this._state = state;
|
|
566
601
|
this.sql`
|
|
567
602
|
INSERT OR REPLACE INTO cf_agents_state (id, state)
|
|
@@ -573,8 +608,8 @@ export class Agent<Env, State = unknown> extends Server<Env> {
|
|
|
573
608
|
`;
|
|
574
609
|
this.broadcast(
|
|
575
610
|
JSON.stringify({
|
|
576
|
-
type: "cf_agent_state",
|
|
577
611
|
state: state,
|
|
612
|
+
type: "cf_agent_state",
|
|
578
613
|
}),
|
|
579
614
|
source !== "server" ? [source.id] : []
|
|
580
615
|
);
|
|
@@ -583,6 +618,19 @@ export class Agent<Env, State = unknown> extends Server<Env> {
|
|
|
583
618
|
return agentContext.run(
|
|
584
619
|
{ agent: this, connection, request },
|
|
585
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
|
+
);
|
|
586
634
|
return this.onStateUpdate(state, source);
|
|
587
635
|
}
|
|
588
636
|
);
|
|
@@ -602,6 +650,7 @@ export class Agent<Env, State = unknown> extends Server<Env> {
|
|
|
602
650
|
* @param state Updated state
|
|
603
651
|
* @param source Source of the state update ("server" or a client connection)
|
|
604
652
|
*/
|
|
653
|
+
// biome-ignore lint/correctness/noUnusedFunctionParameters: overridden later
|
|
605
654
|
onStateUpdate(state: State | undefined, source: Connection | "server") {
|
|
606
655
|
// override this to handle state updates
|
|
607
656
|
}
|
|
@@ -610,6 +659,7 @@ export class Agent<Env, State = unknown> extends Server<Env> {
|
|
|
610
659
|
* Called when the Agent receives an email
|
|
611
660
|
* @param email Email message to process
|
|
612
661
|
*/
|
|
662
|
+
// biome-ignore lint/correctness/noUnusedFunctionParameters: overridden later
|
|
613
663
|
onEmail(email: ForwardableEmailMessage) {
|
|
614
664
|
return agentContext.run(
|
|
615
665
|
{ agent: this, connection: undefined, request: undefined },
|
|
@@ -676,6 +726,18 @@ export class Agent<Env, State = unknown> extends Server<Env> {
|
|
|
676
726
|
): Promise<Schedule<T>> {
|
|
677
727
|
const id = nanoid(9);
|
|
678
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
|
+
|
|
679
741
|
if (typeof callback !== "string") {
|
|
680
742
|
throw new Error("Callback must be a string");
|
|
681
743
|
}
|
|
@@ -695,13 +757,17 @@ export class Agent<Env, State = unknown> extends Server<Env> {
|
|
|
695
757
|
|
|
696
758
|
await this._scheduleNextAlarm();
|
|
697
759
|
|
|
698
|
-
|
|
699
|
-
id,
|
|
760
|
+
const schedule: Schedule<T> = {
|
|
700
761
|
callback: callback,
|
|
762
|
+
id,
|
|
701
763
|
payload: payload as T,
|
|
702
764
|
time: timestamp,
|
|
703
765
|
type: "scheduled",
|
|
704
766
|
};
|
|
767
|
+
|
|
768
|
+
emitScheduleCreate(schedule);
|
|
769
|
+
|
|
770
|
+
return schedule;
|
|
705
771
|
}
|
|
706
772
|
if (typeof when === "number") {
|
|
707
773
|
const time = new Date(Date.now() + when * 1000);
|
|
@@ -716,14 +782,18 @@ export class Agent<Env, State = unknown> extends Server<Env> {
|
|
|
716
782
|
|
|
717
783
|
await this._scheduleNextAlarm();
|
|
718
784
|
|
|
719
|
-
|
|
720
|
-
id,
|
|
785
|
+
const schedule: Schedule<T> = {
|
|
721
786
|
callback: callback,
|
|
722
|
-
payload: payload as T,
|
|
723
787
|
delayInSeconds: when,
|
|
788
|
+
id,
|
|
789
|
+
payload: payload as T,
|
|
724
790
|
time: timestamp,
|
|
725
791
|
type: "delayed",
|
|
726
792
|
};
|
|
793
|
+
|
|
794
|
+
emitScheduleCreate(schedule);
|
|
795
|
+
|
|
796
|
+
return schedule;
|
|
727
797
|
}
|
|
728
798
|
if (typeof when === "string") {
|
|
729
799
|
const nextExecutionTime = getNextCronTime(when);
|
|
@@ -738,14 +808,18 @@ export class Agent<Env, State = unknown> extends Server<Env> {
|
|
|
738
808
|
|
|
739
809
|
await this._scheduleNextAlarm();
|
|
740
810
|
|
|
741
|
-
|
|
742
|
-
id,
|
|
811
|
+
const schedule: Schedule<T> = {
|
|
743
812
|
callback: callback,
|
|
744
|
-
payload: payload as T,
|
|
745
813
|
cron: when,
|
|
814
|
+
id,
|
|
815
|
+
payload: payload as T,
|
|
746
816
|
time: timestamp,
|
|
747
817
|
type: "cron",
|
|
748
818
|
};
|
|
819
|
+
|
|
820
|
+
emitScheduleCreate(schedule);
|
|
821
|
+
|
|
822
|
+
return schedule;
|
|
749
823
|
}
|
|
750
824
|
throw new Error("Invalid schedule type");
|
|
751
825
|
}
|
|
@@ -821,6 +895,19 @@ export class Agent<Env, State = unknown> extends Server<Env> {
|
|
|
821
895
|
* @returns true if the task was cancelled, false otherwise
|
|
822
896
|
*/
|
|
823
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
|
+
}
|
|
824
911
|
this.sql`DELETE FROM cf_agents_schedules WHERE id = ${id}`;
|
|
825
912
|
|
|
826
913
|
await this._scheduleNextAlarm();
|
|
@@ -869,6 +956,17 @@ export class Agent<Env, State = unknown> extends Server<Env> {
|
|
|
869
956
|
{ agent: this, connection: undefined, request: undefined },
|
|
870
957
|
async () => {
|
|
871
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
|
+
|
|
872
970
|
await (
|
|
873
971
|
callback as (
|
|
874
972
|
payload: unknown,
|
|
@@ -912,10 +1010,25 @@ export class Agent<Env, State = unknown> extends Server<Env> {
|
|
|
912
1010
|
// delete all alarms
|
|
913
1011
|
await this.ctx.storage.deleteAlarm();
|
|
914
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
|
+
);
|
|
915
1025
|
}
|
|
916
1026
|
|
|
1027
|
+
/**
|
|
1028
|
+
* Get all methods marked as callable on this Agent
|
|
1029
|
+
* @returns A map of method names to their metadata
|
|
1030
|
+
*/
|
|
917
1031
|
private _isCallable(method: string): boolean {
|
|
918
|
-
// biome-ignore lint/complexity/noBannedTypes: <explanation>
|
|
919
1032
|
return callableMetadata.has(this[method as keyof this] as Function);
|
|
920
1033
|
}
|
|
921
1034
|
|
|
@@ -948,11 +1061,24 @@ export class Agent<Env, State = unknown> extends Server<Env> {
|
|
|
948
1061
|
callbackUrl,
|
|
949
1062
|
options
|
|
950
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
|
+
`;
|
|
951
1077
|
|
|
952
1078
|
this.broadcast(
|
|
953
1079
|
JSON.stringify({
|
|
1080
|
+
mcp: this.getMcpServers(),
|
|
954
1081
|
type: "cf_agent_mcp_servers",
|
|
955
|
-
mcp: this._getMcpServerStateInternal(),
|
|
956
1082
|
})
|
|
957
1083
|
);
|
|
958
1084
|
|
|
@@ -960,7 +1086,7 @@ export class Agent<Env, State = unknown> extends Server<Env> {
|
|
|
960
1086
|
}
|
|
961
1087
|
|
|
962
1088
|
async _connectToMcpServerInternal(
|
|
963
|
-
|
|
1089
|
+
_serverName: string,
|
|
964
1090
|
url: string,
|
|
965
1091
|
callbackUrl: string,
|
|
966
1092
|
// it's important that any options here are serializable because we put them into our sqlite DB for reconnection purposes
|
|
@@ -981,7 +1107,11 @@ export class Agent<Env, State = unknown> extends Server<Env> {
|
|
|
981
1107
|
id: string;
|
|
982
1108
|
oauthClientId?: string;
|
|
983
1109
|
}
|
|
984
|
-
): Promise<{
|
|
1110
|
+
): Promise<{
|
|
1111
|
+
id: string;
|
|
1112
|
+
authUrl: string | undefined;
|
|
1113
|
+
clientId: string | undefined;
|
|
1114
|
+
}> {
|
|
985
1115
|
const authProvider = new DurableObjectOAuthClientProvider(
|
|
986
1116
|
this.ctx.storage,
|
|
987
1117
|
this.name,
|
|
@@ -1014,30 +1144,18 @@ export class Agent<Env, State = unknown> extends Server<Env> {
|
|
|
1014
1144
|
}
|
|
1015
1145
|
|
|
1016
1146
|
const { id, authUrl, clientId } = await this.mcp.connect(url, {
|
|
1147
|
+
client: options?.client,
|
|
1017
1148
|
reconnect,
|
|
1018
1149
|
transport: {
|
|
1019
1150
|
...headerTransportOpts,
|
|
1020
1151
|
authProvider,
|
|
1021
1152
|
},
|
|
1022
|
-
client: options?.client,
|
|
1023
1153
|
});
|
|
1024
1154
|
|
|
1025
|
-
this.sql`
|
|
1026
|
-
INSERT OR REPLACE INTO cf_agents_mcp_servers (id, name, server_url, client_id, auth_url, callback_url, server_options)
|
|
1027
|
-
VALUES (
|
|
1028
|
-
${id},
|
|
1029
|
-
${serverName},
|
|
1030
|
-
${url},
|
|
1031
|
-
${clientId ?? null},
|
|
1032
|
-
${authUrl ?? null},
|
|
1033
|
-
${callbackUrl},
|
|
1034
|
-
${options ? JSON.stringify(options) : null}
|
|
1035
|
-
);
|
|
1036
|
-
`;
|
|
1037
|
-
|
|
1038
1155
|
return {
|
|
1039
|
-
id,
|
|
1040
1156
|
authUrl,
|
|
1157
|
+
clientId,
|
|
1158
|
+
id,
|
|
1041
1159
|
};
|
|
1042
1160
|
}
|
|
1043
1161
|
|
|
@@ -1048,18 +1166,18 @@ export class Agent<Env, State = unknown> extends Server<Env> {
|
|
|
1048
1166
|
`;
|
|
1049
1167
|
this.broadcast(
|
|
1050
1168
|
JSON.stringify({
|
|
1169
|
+
mcp: this.getMcpServers(),
|
|
1051
1170
|
type: "cf_agent_mcp_servers",
|
|
1052
|
-
mcp: this._getMcpServerStateInternal(),
|
|
1053
1171
|
})
|
|
1054
1172
|
);
|
|
1055
1173
|
}
|
|
1056
1174
|
|
|
1057
|
-
|
|
1175
|
+
getMcpServers(): MCPServersState {
|
|
1058
1176
|
const mcpState: MCPServersState = {
|
|
1059
|
-
servers: {},
|
|
1060
|
-
tools: this.mcp.listTools(),
|
|
1061
1177
|
prompts: this.mcp.listPrompts(),
|
|
1062
1178
|
resources: this.mcp.listResources(),
|
|
1179
|
+
servers: {},
|
|
1180
|
+
tools: this.mcp.listTools(),
|
|
1063
1181
|
};
|
|
1064
1182
|
|
|
1065
1183
|
const servers = this.sql<MCPServerRow>`
|
|
@@ -1067,11 +1185,15 @@ export class Agent<Env, State = unknown> extends Server<Env> {
|
|
|
1067
1185
|
`;
|
|
1068
1186
|
|
|
1069
1187
|
for (const server of servers) {
|
|
1188
|
+
const serverConn = this.mcp.mcpConnections[server.id];
|
|
1070
1189
|
mcpState.servers[server.id] = {
|
|
1190
|
+
auth_url: server.auth_url,
|
|
1191
|
+
capabilities: serverConn?.serverCapabilities ?? null,
|
|
1192
|
+
instructions: serverConn?.instructions ?? null,
|
|
1071
1193
|
name: server.name,
|
|
1072
1194
|
server_url: server.server_url,
|
|
1073
|
-
|
|
1074
|
-
state:
|
|
1195
|
+
// mark as "authenticating" because the server isn't automatically connected, so it's pending authenticating
|
|
1196
|
+
state: serverConn?.connectionState ?? "authenticating",
|
|
1075
1197
|
};
|
|
1076
1198
|
}
|
|
1077
1199
|
|
|
@@ -1116,9 +1238,9 @@ export async function routeAgentRequest<Env>(
|
|
|
1116
1238
|
const corsHeaders =
|
|
1117
1239
|
options?.cors === true
|
|
1118
1240
|
? {
|
|
1119
|
-
"Access-Control-Allow-Origin": "*",
|
|
1120
|
-
"Access-Control-Allow-Methods": "GET, POST, HEAD, OPTIONS",
|
|
1121
1241
|
"Access-Control-Allow-Credentials": "true",
|
|
1242
|
+
"Access-Control-Allow-Methods": "GET, POST, HEAD, OPTIONS",
|
|
1243
|
+
"Access-Control-Allow-Origin": "*",
|
|
1122
1244
|
"Access-Control-Max-Age": "86400",
|
|
1123
1245
|
}
|
|
1124
1246
|
: options?.cors;
|
|
@@ -1166,9 +1288,9 @@ export async function routeAgentRequest<Env>(
|
|
|
1166
1288
|
* @param options Routing options
|
|
1167
1289
|
*/
|
|
1168
1290
|
export async function routeAgentEmail<Env>(
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1291
|
+
_email: ForwardableEmailMessage,
|
|
1292
|
+
_env: Env,
|
|
1293
|
+
_options?: AgentOptions<Env>
|
|
1172
1294
|
): Promise<void> {}
|
|
1173
1295
|
|
|
1174
1296
|
/**
|
|
@@ -1213,11 +1335,11 @@ export class StreamingResponse {
|
|
|
1213
1335
|
throw new Error("StreamingResponse is already closed");
|
|
1214
1336
|
}
|
|
1215
1337
|
const response: RPCResponse = {
|
|
1216
|
-
|
|
1338
|
+
done: false,
|
|
1217
1339
|
id: this._id,
|
|
1218
|
-
success: true,
|
|
1219
1340
|
result: chunk,
|
|
1220
|
-
|
|
1341
|
+
success: true,
|
|
1342
|
+
type: "rpc",
|
|
1221
1343
|
};
|
|
1222
1344
|
this._connection.send(JSON.stringify(response));
|
|
1223
1345
|
}
|
|
@@ -1232,11 +1354,11 @@ export class StreamingResponse {
|
|
|
1232
1354
|
}
|
|
1233
1355
|
this._closed = true;
|
|
1234
1356
|
const response: RPCResponse = {
|
|
1235
|
-
|
|
1357
|
+
done: true,
|
|
1236
1358
|
id: this._id,
|
|
1237
|
-
success: true,
|
|
1238
1359
|
result: finalChunk,
|
|
1239
|
-
|
|
1360
|
+
success: true,
|
|
1361
|
+
type: "rpc",
|
|
1240
1362
|
};
|
|
1241
1363
|
this._connection.send(JSON.stringify(response));
|
|
1242
1364
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/client.ts"],"sourcesContent":["import {\n PartySocket,\n type PartySocketOptions,\n type PartyFetchOptions,\n} from \"partysocket\";\nimport type { RPCRequest, RPCResponse } from \"./\";\n\n/**\n * Options for creating an AgentClient\n */\nexport type AgentClientOptions<State = unknown> = Omit<\n PartySocketOptions,\n \"party\" | \"room\"\n> & {\n /** Name of the agent to connect to */\n agent: string;\n /** Name of the specific Agent instance */\n name?: string;\n /** Called when the Agent's state is updated */\n onStateUpdate?: (state: State, source: \"server\" | \"client\") => void;\n};\n\n/**\n * Options for streaming RPC calls\n */\nexport type StreamOptions = {\n /** Called when a chunk of data is received */\n onChunk?: (chunk: unknown) => void;\n /** Called when the stream ends */\n onDone?: (finalChunk: unknown) => void;\n /** Called when an error occurs */\n onError?: (error: string) => void;\n};\n\n/**\n * Options for the agentFetch function\n */\nexport type AgentClientFetchOptions = Omit<\n PartyFetchOptions,\n \"party\" | \"room\"\n> & {\n /** Name of the agent to connect to */\n agent: string;\n /** Name of the specific Agent instance */\n name?: string;\n};\n\n/**\n * Convert a camelCase string to a kebab-case string\n * @param str The string to convert\n * @returns The kebab-case string\n */\nexport function camelCaseToKebabCase(str: string): string {\n // If string is all uppercase, convert to lowercase\n if (str === str.toUpperCase() && str !== str.toLowerCase()) {\n return str.toLowerCase().replace(/_/g, \"-\");\n }\n\n // Otherwise handle camelCase to kebab-case\n let kebabified = str.replace(\n /[A-Z]/g,\n (letter) => `-${letter.toLowerCase()}`\n );\n kebabified = kebabified.startsWith(\"-\") ? kebabified.slice(1) : kebabified;\n // Convert any remaining underscores to hyphens and remove trailing -'s\n return kebabified.replace(/_/g, \"-\").replace(/-$/, \"\");\n}\n\n/**\n * WebSocket client for connecting to an Agent\n */\nexport class AgentClient<State = unknown> extends PartySocket {\n /**\n * @deprecated Use agentFetch instead\n */\n static fetch(_opts: PartyFetchOptions): Promise<Response> {\n throw new Error(\n \"AgentClient.fetch is not implemented, use agentFetch instead\"\n );\n }\n agent: string;\n name: string;\n private options: AgentClientOptions<State>;\n private _pendingCalls = new Map<\n string,\n {\n resolve: (value: unknown) => void;\n reject: (error: Error) => void;\n stream?: StreamOptions;\n type?: unknown;\n }\n >();\n\n constructor(options: AgentClientOptions<State>) {\n const agentNamespace = camelCaseToKebabCase(options.agent);\n super({\n prefix: \"agents\",\n party: agentNamespace,\n room: options.name || \"default\",\n ...options,\n });\n this.agent = agentNamespace;\n this.name = options.name || \"default\";\n this.options = options;\n\n this.addEventListener(\"message\", (event) => {\n if (typeof event.data === \"string\") {\n let parsedMessage: Record<string, unknown>;\n try {\n parsedMessage = JSON.parse(event.data);\n } catch (error) {\n // silently ignore invalid messages for now\n // TODO: log errors with log levels\n return;\n }\n if (parsedMessage.type === \"cf_agent_state\") {\n this.options.onStateUpdate?.(parsedMessage.state as State, \"server\");\n return;\n }\n if (parsedMessage.type === \"rpc\") {\n const response = parsedMessage as RPCResponse;\n const pending = this._pendingCalls.get(response.id);\n if (!pending) return;\n\n if (!response.success) {\n pending.reject(new Error(response.error));\n this._pendingCalls.delete(response.id);\n pending.stream?.onError?.(response.error);\n return;\n }\n\n // Handle streaming responses\n if (\"done\" in response) {\n if (response.done) {\n pending.resolve(response.result);\n this._pendingCalls.delete(response.id);\n pending.stream?.onDone?.(response.result);\n } else {\n pending.stream?.onChunk?.(response.result);\n }\n } else {\n // Non-streaming response\n pending.resolve(response.result);\n this._pendingCalls.delete(response.id);\n }\n }\n }\n });\n }\n\n setState(state: State) {\n this.send(JSON.stringify({ type: \"cf_agent_state\", state }));\n this.options.onStateUpdate?.(state, \"client\");\n }\n\n /**\n * Call a method on the Agent\n * @param method Name of the method to call\n * @param args Arguments to pass to the method\n * @param streamOptions Options for handling streaming responses\n * @returns Promise that resolves with the method's return value\n */\n async call<T = unknown>(\n method: string,\n args: unknown[] = [],\n streamOptions?: StreamOptions\n ): Promise<T> {\n return new Promise<T>((resolve, reject) => {\n const id = Math.random().toString(36).slice(2);\n this._pendingCalls.set(id, {\n resolve: (value: unknown) => resolve(value as T),\n reject,\n stream: streamOptions,\n type: null as T,\n });\n\n const request: RPCRequest = {\n type: \"rpc\",\n id,\n method,\n args,\n };\n\n this.send(JSON.stringify(request));\n });\n }\n}\n\n/**\n * Make an HTTP request to an Agent\n * @param opts Connection options\n * @param init Request initialization options\n * @returns Promise resolving to a Response\n */\nexport function agentFetch(opts: AgentClientFetchOptions, init?: RequestInit) {\n const agentNamespace = camelCaseToKebabCase(opts.agent);\n\n return PartySocket.fetch(\n {\n prefix: \"agents\",\n party: agentNamespace,\n room: opts.name || \"default\",\n ...opts,\n },\n init\n );\n}\n"],"mappings":";AAAA;AAAA,EACE;AAAA,OAGK;AAgDA,SAAS,qBAAqB,KAAqB;AAExD,MAAI,QAAQ,IAAI,YAAY,KAAK,QAAQ,IAAI,YAAY,GAAG;AAC1D,WAAO,IAAI,YAAY,EAAE,QAAQ,MAAM,GAAG;AAAA,EAC5C;AAGA,MAAI,aAAa,IAAI;AAAA,IACnB;AAAA,IACA,CAAC,WAAW,IAAI,OAAO,YAAY,CAAC;AAAA,EACtC;AACA,eAAa,WAAW,WAAW,GAAG,IAAI,WAAW,MAAM,CAAC,IAAI;AAEhE,SAAO,WAAW,QAAQ,MAAM,GAAG,EAAE,QAAQ,MAAM,EAAE;AACvD;AAKO,IAAM,cAAN,cAA2C,YAAY;AAAA,EAsB5D,YAAY,SAAoC;AAC9C,UAAM,iBAAiB,qBAAqB,QAAQ,KAAK;AACzD,UAAM;AAAA,MACJ,QAAQ;AAAA,MACR,OAAO;AAAA,MACP,MAAM,QAAQ,QAAQ;AAAA,MACtB,GAAG;AAAA,IACL,CAAC;AAjBH,SAAQ,gBAAgB,oBAAI,IAQ1B;AAUA,SAAK,QAAQ;AACb,SAAK,OAAO,QAAQ,QAAQ;AAC5B,SAAK,UAAU;AAEf,SAAK,iBAAiB,WAAW,CAAC,UAAU;AAC1C,UAAI,OAAO,MAAM,SAAS,UAAU;AAClC,YAAI;AACJ,YAAI;AACF,0BAAgB,KAAK,MAAM,MAAM,IAAI;AAAA,QACvC,SAAS,OAAO;AAGd;AAAA,QACF;AACA,YAAI,cAAc,SAAS,kBAAkB;AAC3C,eAAK,QAAQ,gBAAgB,cAAc,OAAgB,QAAQ;AACnE;AAAA,QACF;AACA,YAAI,cAAc,SAAS,OAAO;AAChC,gBAAM,WAAW;AACjB,gBAAM,UAAU,KAAK,cAAc,IAAI,SAAS,EAAE;AAClD,cAAI,CAAC,QAAS;AAEd,cAAI,CAAC,SAAS,SAAS;AACrB,oBAAQ,OAAO,IAAI,MAAM,SAAS,KAAK,CAAC;AACxC,iBAAK,cAAc,OAAO,SAAS,EAAE;AACrC,oBAAQ,QAAQ,UAAU,SAAS,KAAK;AACxC;AAAA,UACF;AAGA,cAAI,UAAU,UAAU;AACtB,gBAAI,SAAS,MAAM;AACjB,sBAAQ,QAAQ,SAAS,MAAM;AAC/B,mBAAK,cAAc,OAAO,SAAS,EAAE;AACrC,sBAAQ,QAAQ,SAAS,SAAS,MAAM;AAAA,YAC1C,OAAO;AACL,sBAAQ,QAAQ,UAAU,SAAS,MAAM;AAAA,YAC3C;AAAA,UACF,OAAO;AAEL,oBAAQ,QAAQ,SAAS,MAAM;AAC/B,iBAAK,cAAc,OAAO,SAAS,EAAE;AAAA,UACvC;AAAA,QACF;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAzEA,OAAO,MAAM,OAA6C;AACxD,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAAA,EAuEA,SAAS,OAAc;AACrB,SAAK,KAAK,KAAK,UAAU,EAAE,MAAM,kBAAkB,MAAM,CAAC,CAAC;AAC3D,SAAK,QAAQ,gBAAgB,OAAO,QAAQ;AAAA,EAC9C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,KACJ,QACA,OAAkB,CAAC,GACnB,eACY;AACZ,WAAO,IAAI,QAAW,CAAC,SAAS,WAAW;AACzC,YAAM,KAAK,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,CAAC;AAC7C,WAAK,cAAc,IAAI,IAAI;AAAA,QACzB,SAAS,CAAC,UAAmB,QAAQ,KAAU;AAAA,QAC/C;AAAA,QACA,QAAQ;AAAA,QACR,MAAM;AAAA,MACR,CAAC;AAED,YAAM,UAAsB;AAAA,QAC1B,MAAM;AAAA,QACN;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAEA,WAAK,KAAK,KAAK,UAAU,OAAO,CAAC;AAAA,IACnC,CAAC;AAAA,EACH;AACF;AAQO,SAAS,WAAW,MAA+B,MAAoB;AAC5E,QAAM,iBAAiB,qBAAqB,KAAK,KAAK;AAEtD,SAAO,YAAY;AAAA,IACjB;AAAA,MACE,QAAQ;AAAA,MACR,OAAO;AAAA,MACP,MAAM,KAAK,QAAQ;AAAA,MACnB,GAAG;AAAA,IACL;AAAA,IACA;AAAA,EACF;AACF;","names":[]}
|