agents 0.0.0-74a8c74 → 0.0.0-7972da4
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 +49 -4
- package/dist/ai-chat-agent.js +88 -29
- package/dist/ai-chat-agent.js.map +1 -1
- package/dist/ai-react.d.ts +13 -0
- package/dist/ai-react.js +38 -22
- package/dist/ai-react.js.map +1 -1
- package/dist/ai-types.d.ts +5 -0
- package/dist/chunk-BZXOAZUX.js +106 -0
- package/dist/chunk-BZXOAZUX.js.map +1 -0
- package/dist/{chunk-SZEXGW6W.js → chunk-CFTLYEEK.js} +345 -142
- package/dist/chunk-CFTLYEEK.js.map +1 -0
- package/dist/chunk-IFXSRTKF.js +465 -0
- package/dist/chunk-IFXSRTKF.js.map +1 -0
- package/dist/chunk-VCSB47AK.js +116 -0
- package/dist/chunk-VCSB47AK.js.map +1 -0
- package/dist/client.d.ts +15 -1
- package/dist/client.js +6 -126
- package/dist/client.js.map +1 -1
- package/dist/index.d.ts +120 -17
- package/dist/index.js +8 -7
- package/dist/mcp/client.d.ts +142 -34
- package/dist/mcp/client.js +3 -780
- package/dist/mcp/client.js.map +1 -1
- package/dist/mcp/do-oauth-client-provider.d.ts +41 -0
- package/dist/mcp/do-oauth-client-provider.js +7 -0
- package/dist/mcp/do-oauth-client-provider.js.map +1 -0
- package/dist/mcp/index.d.ts +50 -7
- package/dist/mcp/index.js +718 -71
- package/dist/mcp/index.js.map +1 -1
- package/dist/react.d.ts +85 -5
- package/dist/react.js +48 -27
- package/dist/react.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 +28 -5
- package/src/index.ts +389 -58
- package/dist/chunk-EZ76ZGDB.js +0 -1721
- package/dist/chunk-EZ76ZGDB.js.map +0 -1
- package/dist/chunk-SZEXGW6W.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/mcp/do-oauth-client-provider.ts"],"sourcesContent":["import type { OAuthClientProvider } from \"@modelcontextprotocol/sdk/client/auth.js\";\nimport type {\n OAuthTokens,\n OAuthClientMetadata,\n OAuthClientInformation,\n OAuthClientInformationFull,\n} from \"@modelcontextprotocol/sdk/shared/auth.js\";\n\n// A slight extension to the standard OAuthClientProvider interface because `redirectToAuthorization` doesn't give us the interface we need\n// This allows us to track authentication for a specific server and associated dynamic client registration\nexport interface AgentsOAuthProvider extends OAuthClientProvider {\n authUrl: string | undefined;\n clientId: string | undefined;\n serverId: string | undefined;\n}\n\nexport class DurableObjectOAuthClientProvider implements AgentsOAuthProvider {\n private _authUrl_: string | undefined;\n private _serverId_: string | undefined;\n private _clientId_: string | undefined;\n\n constructor(\n public storage: DurableObjectStorage,\n public clientName: string,\n public baseRedirectUrl: string\n ) {}\n\n get clientMetadata(): OAuthClientMetadata {\n return {\n redirect_uris: [this.redirectUrl],\n token_endpoint_auth_method: \"none\",\n grant_types: [\"authorization_code\", \"refresh_token\"],\n response_types: [\"code\"],\n client_name: this.clientName,\n client_uri: \"example.com\",\n };\n }\n\n get redirectUrl() {\n return `${this.baseRedirectUrl}/${this.serverId}`;\n }\n\n get clientId() {\n if (!this._clientId_) {\n throw new Error(\"Trying to access clientId before it was set\");\n }\n return this._clientId_;\n }\n\n set clientId(clientId_: string) {\n this._clientId_ = clientId_;\n }\n\n get serverId() {\n if (!this._serverId_) {\n throw new Error(\"Trying to access serverId before it was set\");\n }\n return this._serverId_;\n }\n\n set serverId(serverId_: string) {\n this._serverId_ = serverId_;\n }\n\n keyPrefix(clientId: string) {\n return `/${this.clientName}/${this.serverId}/${clientId}`;\n }\n\n clientInfoKey(clientId: string) {\n return `${this.keyPrefix(clientId)}/client_info/`;\n }\n\n async clientInformation(): Promise<OAuthClientInformation | undefined> {\n if (!this._clientId_) {\n return undefined;\n }\n return (\n (await this.storage.get<OAuthClientInformation>(\n this.clientInfoKey(this.clientId)\n )) ?? undefined\n );\n }\n\n async saveClientInformation(\n clientInformation: OAuthClientInformationFull\n ): Promise<void> {\n await this.storage.put(\n this.clientInfoKey(clientInformation.client_id),\n clientInformation\n );\n this.clientId = clientInformation.client_id;\n }\n\n tokenKey(clientId: string) {\n return `${this.keyPrefix(clientId)}/token`;\n }\n\n async tokens(): Promise<OAuthTokens | undefined> {\n if (!this._clientId_) {\n return undefined;\n }\n return (\n (await this.storage.get<OAuthTokens>(this.tokenKey(this.clientId))) ??\n undefined\n );\n }\n\n async saveTokens(tokens: OAuthTokens): Promise<void> {\n await this.storage.put(this.tokenKey(this.clientId), tokens);\n }\n\n get authUrl() {\n return this._authUrl_;\n }\n\n /**\n * Because this operates on the server side (but we need browser auth), we send this url back to the user\n * and require user interact to initiate the redirect flow\n */\n async redirectToAuthorization(authUrl: URL): Promise<void> {\n // We want to track the client ID in state here because the typescript SSE client sometimes does\n // a dynamic client registration AFTER generating this redirect URL.\n const client_id = authUrl.searchParams.get(\"client_id\");\n if (client_id) {\n authUrl.searchParams.append(\"state\", client_id);\n }\n this._authUrl_ = authUrl.toString();\n }\n\n codeVerifierKey(clientId: string) {\n return `${this.keyPrefix(clientId)}/code_verifier`;\n }\n\n async saveCodeVerifier(verifier: string): Promise<void> {\n await this.storage.put(this.codeVerifierKey(this.clientId), verifier);\n }\n\n async codeVerifier(): Promise<string> {\n const codeVerifier = await this.storage.get<string>(\n this.codeVerifierKey(this.clientId)\n );\n if (!codeVerifier) {\n throw new Error(\"No code verifier found\");\n }\n return codeVerifier;\n }\n}\n"],"mappings":";AAgBO,IAAM,mCAAN,MAAsE;AAAA,EAK3E,YACS,SACA,YACA,iBACP;AAHO;AACA;AACA;AAAA,EACN;AAAA,EAEH,IAAI,iBAAsC;AACxC,WAAO;AAAA,MACL,eAAe,CAAC,KAAK,WAAW;AAAA,MAChC,4BAA4B;AAAA,MAC5B,aAAa,CAAC,sBAAsB,eAAe;AAAA,MACnD,gBAAgB,CAAC,MAAM;AAAA,MACvB,aAAa,KAAK;AAAA,MAClB,YAAY;AAAA,IACd;AAAA,EACF;AAAA,EAEA,IAAI,cAAc;AAChB,WAAO,GAAG,KAAK,eAAe,IAAI,KAAK,QAAQ;AAAA,EACjD;AAAA,EAEA,IAAI,WAAW;AACb,QAAI,CAAC,KAAK,YAAY;AACpB,YAAM,IAAI,MAAM,6CAA6C;AAAA,IAC/D;AACA,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,IAAI,SAAS,WAAmB;AAC9B,SAAK,aAAa;AAAA,EACpB;AAAA,EAEA,IAAI,WAAW;AACb,QAAI,CAAC,KAAK,YAAY;AACpB,YAAM,IAAI,MAAM,6CAA6C;AAAA,IAC/D;AACA,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,IAAI,SAAS,WAAmB;AAC9B,SAAK,aAAa;AAAA,EACpB;AAAA,EAEA,UAAU,UAAkB;AAC1B,WAAO,IAAI,KAAK,UAAU,IAAI,KAAK,QAAQ,IAAI,QAAQ;AAAA,EACzD;AAAA,EAEA,cAAc,UAAkB;AAC9B,WAAO,GAAG,KAAK,UAAU,QAAQ,CAAC;AAAA,EACpC;AAAA,EAEA,MAAM,oBAAiE;AACrE,QAAI,CAAC,KAAK,YAAY;AACpB,aAAO;AAAA,IACT;AACA,WACG,MAAM,KAAK,QAAQ;AAAA,MAClB,KAAK,cAAc,KAAK,QAAQ;AAAA,IAClC,KAAM;AAAA,EAEV;AAAA,EAEA,MAAM,sBACJ,mBACe;AACf,UAAM,KAAK,QAAQ;AAAA,MACjB,KAAK,cAAc,kBAAkB,SAAS;AAAA,MAC9C;AAAA,IACF;AACA,SAAK,WAAW,kBAAkB;AAAA,EACpC;AAAA,EAEA,SAAS,UAAkB;AACzB,WAAO,GAAG,KAAK,UAAU,QAAQ,CAAC;AAAA,EACpC;AAAA,EAEA,MAAM,SAA2C;AAC/C,QAAI,CAAC,KAAK,YAAY;AACpB,aAAO;AAAA,IACT;AACA,WACG,MAAM,KAAK,QAAQ,IAAiB,KAAK,SAAS,KAAK,QAAQ,CAAC,KACjE;AAAA,EAEJ;AAAA,EAEA,MAAM,WAAW,QAAoC;AACnD,UAAM,KAAK,QAAQ,IAAI,KAAK,SAAS,KAAK,QAAQ,GAAG,MAAM;AAAA,EAC7D;AAAA,EAEA,IAAI,UAAU;AACZ,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,wBAAwB,SAA6B;AAGzD,UAAM,YAAY,QAAQ,aAAa,IAAI,WAAW;AACtD,QAAI,WAAW;AACb,cAAQ,aAAa,OAAO,SAAS,SAAS;AAAA,IAChD;AACA,SAAK,YAAY,QAAQ,SAAS;AAAA,EACpC;AAAA,EAEA,gBAAgB,UAAkB;AAChC,WAAO,GAAG,KAAK,UAAU,QAAQ,CAAC;AAAA,EACpC;AAAA,EAEA,MAAM,iBAAiB,UAAiC;AACtD,UAAM,KAAK,QAAQ,IAAI,KAAK,gBAAgB,KAAK,QAAQ,GAAG,QAAQ;AAAA,EACtE;AAAA,EAEA,MAAM,eAAgC;AACpC,UAAM,eAAe,MAAM,KAAK,QAAQ;AAAA,MACtC,KAAK,gBAAgB,KAAK,QAAQ;AAAA,IACpC;AACA,QAAI,CAAC,cAAc;AACjB,YAAM,IAAI,MAAM,wBAAwB;AAAA,IAC1C;AACA,WAAO;AAAA,EACT;AACF;","names":[]}
|
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
import {
|
|
2
|
+
MCPClientManager
|
|
3
|
+
} from "./chunk-IFXSRTKF.js";
|
|
4
|
+
import {
|
|
5
|
+
DurableObjectOAuthClientProvider
|
|
6
|
+
} from "./chunk-BZXOAZUX.js";
|
|
7
|
+
import {
|
|
8
|
+
camelCaseToKebabCase
|
|
9
|
+
} from "./chunk-VCSB47AK.js";
|
|
10
|
+
|
|
1
11
|
// src/index.ts
|
|
2
12
|
import {
|
|
3
13
|
Server,
|
|
@@ -6,8 +16,7 @@ import {
|
|
|
6
16
|
} from "partyserver";
|
|
7
17
|
import { parseCronExpression } from "cron-schedule";
|
|
8
18
|
import { nanoid } from "nanoid";
|
|
9
|
-
import { AsyncLocalStorage } from "
|
|
10
|
-
import { WorkflowEntrypoint as CFWorkflowEntrypoint } from "cloudflare:workers";
|
|
19
|
+
import { AsyncLocalStorage } from "async_hooks";
|
|
11
20
|
function isRPCRequest(msg) {
|
|
12
21
|
return typeof msg === "object" && msg !== null && "type" in msg && msg.type === "rpc" && "id" in msg && typeof msg.id === "string" && "method" in msg && typeof msg.method === "string" && "args" in msg && Array.isArray(msg.args);
|
|
13
22
|
}
|
|
@@ -23,8 +32,6 @@ function unstable_callable(metadata = {}) {
|
|
|
23
32
|
return target;
|
|
24
33
|
};
|
|
25
34
|
}
|
|
26
|
-
var WorkflowEntrypoint = class extends CFWorkflowEntrypoint {
|
|
27
|
-
};
|
|
28
35
|
function getNextCronTime(cron) {
|
|
29
36
|
const interval = parseCronExpression(cron);
|
|
30
37
|
return interval.getNextDate();
|
|
@@ -32,69 +39,72 @@ function getNextCronTime(cron) {
|
|
|
32
39
|
var STATE_ROW_ID = "cf_state_row_id";
|
|
33
40
|
var STATE_WAS_CHANGED = "cf_state_was_changed";
|
|
34
41
|
var DEFAULT_STATE = {};
|
|
35
|
-
var
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
* Current state of the Agent
|
|
45
|
-
*/
|
|
46
|
-
get state() {
|
|
47
|
-
if (this.#state !== DEFAULT_STATE) {
|
|
48
|
-
return this.#state;
|
|
49
|
-
}
|
|
50
|
-
const wasChanged = this.sql`
|
|
51
|
-
SELECT state FROM cf_agents_state WHERE id = ${STATE_WAS_CHANGED}
|
|
52
|
-
`;
|
|
53
|
-
const result = this.sql`
|
|
54
|
-
SELECT state FROM cf_agents_state WHERE id = ${STATE_ROW_ID}
|
|
55
|
-
`;
|
|
56
|
-
if (wasChanged[0]?.state === "true" || // we do this check for people who updated their code before we shipped wasChanged
|
|
57
|
-
result[0]?.state) {
|
|
58
|
-
const state = result[0]?.state;
|
|
59
|
-
this.#state = JSON.parse(state);
|
|
60
|
-
return this.#state;
|
|
61
|
-
}
|
|
62
|
-
if (this.initialState === DEFAULT_STATE) {
|
|
63
|
-
return void 0;
|
|
64
|
-
}
|
|
65
|
-
this.setState(this.initialState);
|
|
66
|
-
return this.initialState;
|
|
67
|
-
}
|
|
68
|
-
/**
|
|
69
|
-
* Agent configuration options
|
|
70
|
-
*/
|
|
71
|
-
static options = {
|
|
72
|
-
/** Whether the Agent should hibernate when inactive */
|
|
73
|
-
hibernate: true
|
|
74
|
-
// default to hibernate
|
|
75
|
-
};
|
|
76
|
-
/**
|
|
77
|
-
* Execute SQL queries against the Agent's database
|
|
78
|
-
* @template T Type of the returned rows
|
|
79
|
-
* @param strings SQL query template strings
|
|
80
|
-
* @param values Values to be inserted into the query
|
|
81
|
-
* @returns Array of query results
|
|
82
|
-
*/
|
|
83
|
-
sql(strings, ...values) {
|
|
84
|
-
let query = "";
|
|
85
|
-
try {
|
|
86
|
-
query = strings.reduce(
|
|
87
|
-
(acc, str, i) => acc + str + (i < values.length ? "?" : ""),
|
|
88
|
-
""
|
|
89
|
-
);
|
|
90
|
-
return [...this.ctx.storage.sql.exec(query, ...values)];
|
|
91
|
-
} catch (e) {
|
|
92
|
-
console.error(`failed to execute sql query: ${query}`, e);
|
|
93
|
-
throw this.onError(e);
|
|
94
|
-
}
|
|
42
|
+
var agentContext = new AsyncLocalStorage();
|
|
43
|
+
function getCurrentAgent() {
|
|
44
|
+
const store = agentContext.getStore();
|
|
45
|
+
if (!store) {
|
|
46
|
+
return {
|
|
47
|
+
agent: void 0,
|
|
48
|
+
connection: void 0,
|
|
49
|
+
request: void 0
|
|
50
|
+
};
|
|
95
51
|
}
|
|
52
|
+
return store;
|
|
53
|
+
}
|
|
54
|
+
var Agent = class extends Server {
|
|
96
55
|
constructor(ctx, env) {
|
|
97
56
|
super(ctx, env);
|
|
57
|
+
this._state = DEFAULT_STATE;
|
|
58
|
+
this._ParentClass = Object.getPrototypeOf(this).constructor;
|
|
59
|
+
this.mcp = new MCPClientManager(this._ParentClass.name, "0.0.1");
|
|
60
|
+
/**
|
|
61
|
+
* Initial state for the Agent
|
|
62
|
+
* Override to provide default state values
|
|
63
|
+
*/
|
|
64
|
+
this.initialState = DEFAULT_STATE;
|
|
65
|
+
/**
|
|
66
|
+
* Method called when an alarm fires.
|
|
67
|
+
* Executes any scheduled tasks that are due.
|
|
68
|
+
*
|
|
69
|
+
* @remarks
|
|
70
|
+
* To schedule a task, please use the `this.schedule` method instead.
|
|
71
|
+
* See {@link https://developers.cloudflare.com/agents/api-reference/schedule-tasks/}
|
|
72
|
+
*/
|
|
73
|
+
this.alarm = async () => {
|
|
74
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
75
|
+
const result = this.sql`
|
|
76
|
+
SELECT * FROM cf_agents_schedules WHERE time <= ${now}
|
|
77
|
+
`;
|
|
78
|
+
for (const row of result || []) {
|
|
79
|
+
const callback = this[row.callback];
|
|
80
|
+
if (!callback) {
|
|
81
|
+
console.error(`callback ${row.callback} not found`);
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
await agentContext.run(
|
|
85
|
+
{ agent: this, connection: void 0, request: void 0 },
|
|
86
|
+
async () => {
|
|
87
|
+
try {
|
|
88
|
+
await callback.bind(this)(JSON.parse(row.payload), row);
|
|
89
|
+
} catch (e) {
|
|
90
|
+
console.error(`error executing callback "${row.callback}"`, e);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
);
|
|
94
|
+
if (row.type === "cron") {
|
|
95
|
+
const nextExecutionTime = getNextCronTime(row.cron);
|
|
96
|
+
const nextTimestamp = Math.floor(nextExecutionTime.getTime() / 1e3);
|
|
97
|
+
this.sql`
|
|
98
|
+
UPDATE cf_agents_schedules SET time = ${nextTimestamp} WHERE id = ${row.id}
|
|
99
|
+
`;
|
|
100
|
+
} else {
|
|
101
|
+
this.sql`
|
|
102
|
+
DELETE FROM cf_agents_schedules WHERE id = ${row.id}
|
|
103
|
+
`;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
await this._scheduleNextAlarm();
|
|
107
|
+
};
|
|
98
108
|
this.sql`
|
|
99
109
|
CREATE TABLE IF NOT EXISTS cf_agents_state (
|
|
100
110
|
id TEXT PRIMARY KEY NOT NULL,
|
|
@@ -102,7 +112,7 @@ var Agent = class extends Server {
|
|
|
102
112
|
)
|
|
103
113
|
`;
|
|
104
114
|
void this.ctx.blockConcurrencyWhile(async () => {
|
|
105
|
-
return this
|
|
115
|
+
return this._tryCatch(async () => {
|
|
106
116
|
this.sql`
|
|
107
117
|
CREATE TABLE IF NOT EXISTS cf_agents_schedules (
|
|
108
118
|
id TEXT PRIMARY KEY NOT NULL DEFAULT (randomblob(9)),
|
|
@@ -118,22 +128,55 @@ var Agent = class extends Server {
|
|
|
118
128
|
await this.alarm();
|
|
119
129
|
});
|
|
120
130
|
});
|
|
131
|
+
this.sql`
|
|
132
|
+
CREATE TABLE IF NOT EXISTS cf_agents_mcp_servers (
|
|
133
|
+
id TEXT PRIMARY KEY NOT NULL,
|
|
134
|
+
name TEXT NOT NULL,
|
|
135
|
+
server_url TEXT NOT NULL,
|
|
136
|
+
callback_url TEXT NOT NULL,
|
|
137
|
+
client_id TEXT,
|
|
138
|
+
auth_url TEXT,
|
|
139
|
+
server_options TEXT
|
|
140
|
+
)
|
|
141
|
+
`;
|
|
142
|
+
const _onRequest = this.onRequest.bind(this);
|
|
143
|
+
this.onRequest = (request) => {
|
|
144
|
+
return agentContext.run(
|
|
145
|
+
{ agent: this, connection: void 0, request },
|
|
146
|
+
async () => {
|
|
147
|
+
if (this.mcp.isCallbackRequest(request)) {
|
|
148
|
+
await this.mcp.handleCallbackRequest(request);
|
|
149
|
+
this.broadcast(
|
|
150
|
+
JSON.stringify({
|
|
151
|
+
type: "cf_agent_mcp_servers",
|
|
152
|
+
mcp: this.getMcpServers()
|
|
153
|
+
})
|
|
154
|
+
);
|
|
155
|
+
return new Response("<script>window.close();</script>", {
|
|
156
|
+
status: 200,
|
|
157
|
+
headers: { "content-type": "text/html" }
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
return this._tryCatch(() => _onRequest(request));
|
|
161
|
+
}
|
|
162
|
+
);
|
|
163
|
+
};
|
|
121
164
|
const _onMessage = this.onMessage.bind(this);
|
|
122
165
|
this.onMessage = async (connection, message) => {
|
|
123
|
-
return
|
|
166
|
+
return agentContext.run(
|
|
124
167
|
{ agent: this, connection, request: void 0 },
|
|
125
168
|
async () => {
|
|
126
169
|
if (typeof message !== "string") {
|
|
127
|
-
return this
|
|
170
|
+
return this._tryCatch(() => _onMessage(connection, message));
|
|
128
171
|
}
|
|
129
172
|
let parsed;
|
|
130
173
|
try {
|
|
131
174
|
parsed = JSON.parse(message);
|
|
132
175
|
} catch (e) {
|
|
133
|
-
return this
|
|
176
|
+
return this._tryCatch(() => _onMessage(connection, message));
|
|
134
177
|
}
|
|
135
178
|
if (isStateUpdateMessage(parsed)) {
|
|
136
|
-
this
|
|
179
|
+
this._setStateInternal(parsed.state, connection);
|
|
137
180
|
return;
|
|
138
181
|
}
|
|
139
182
|
if (isRPCRequest(parsed)) {
|
|
@@ -143,7 +186,7 @@ var Agent = class extends Server {
|
|
|
143
186
|
if (typeof methodFn !== "function") {
|
|
144
187
|
throw new Error(`Method ${method} does not exist`);
|
|
145
188
|
}
|
|
146
|
-
if (!this
|
|
189
|
+
if (!this._isCallable(method)) {
|
|
147
190
|
throw new Error(`Method ${method} is not callable`);
|
|
148
191
|
}
|
|
149
192
|
const metadata = callableMetadata.get(methodFn);
|
|
@@ -173,13 +216,13 @@ var Agent = class extends Server {
|
|
|
173
216
|
}
|
|
174
217
|
return;
|
|
175
218
|
}
|
|
176
|
-
return this
|
|
219
|
+
return this._tryCatch(() => _onMessage(connection, message));
|
|
177
220
|
}
|
|
178
221
|
);
|
|
179
222
|
};
|
|
180
223
|
const _onConnect = this.onConnect.bind(this);
|
|
181
224
|
this.onConnect = (connection, ctx2) => {
|
|
182
|
-
return
|
|
225
|
+
return agentContext.run(
|
|
183
226
|
{ agent: this, connection, request: ctx2.request },
|
|
184
227
|
async () => {
|
|
185
228
|
setTimeout(() => {
|
|
@@ -191,14 +234,97 @@ var Agent = class extends Server {
|
|
|
191
234
|
})
|
|
192
235
|
);
|
|
193
236
|
}
|
|
194
|
-
|
|
237
|
+
connection.send(
|
|
238
|
+
JSON.stringify({
|
|
239
|
+
type: "cf_agent_mcp_servers",
|
|
240
|
+
mcp: this.getMcpServers()
|
|
241
|
+
})
|
|
242
|
+
);
|
|
243
|
+
return this._tryCatch(() => _onConnect(connection, ctx2));
|
|
195
244
|
}, 20);
|
|
196
245
|
}
|
|
197
246
|
);
|
|
198
247
|
};
|
|
248
|
+
const _onStart = this.onStart.bind(this);
|
|
249
|
+
this.onStart = async () => {
|
|
250
|
+
return agentContext.run(
|
|
251
|
+
{ agent: this, connection: void 0, request: void 0 },
|
|
252
|
+
async () => {
|
|
253
|
+
const servers = this.sql`
|
|
254
|
+
SELECT id, name, server_url, client_id, auth_url, callback_url, server_options FROM cf_agents_mcp_servers;
|
|
255
|
+
`;
|
|
256
|
+
await Promise.allSettled(
|
|
257
|
+
servers.map((server) => {
|
|
258
|
+
return this._connectToMcpServerInternal(
|
|
259
|
+
server.name,
|
|
260
|
+
server.server_url,
|
|
261
|
+
server.callback_url,
|
|
262
|
+
server.server_options ? JSON.parse(server.server_options) : void 0,
|
|
263
|
+
{
|
|
264
|
+
id: server.id,
|
|
265
|
+
oauthClientId: server.client_id ?? void 0
|
|
266
|
+
}
|
|
267
|
+
);
|
|
268
|
+
})
|
|
269
|
+
);
|
|
270
|
+
this.broadcast(
|
|
271
|
+
JSON.stringify({
|
|
272
|
+
type: "cf_agent_mcp_servers",
|
|
273
|
+
mcp: this.getMcpServers()
|
|
274
|
+
})
|
|
275
|
+
);
|
|
276
|
+
await this._tryCatch(() => _onStart());
|
|
277
|
+
}
|
|
278
|
+
);
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* Current state of the Agent
|
|
283
|
+
*/
|
|
284
|
+
get state() {
|
|
285
|
+
if (this._state !== DEFAULT_STATE) {
|
|
286
|
+
return this._state;
|
|
287
|
+
}
|
|
288
|
+
const wasChanged = this.sql`
|
|
289
|
+
SELECT state FROM cf_agents_state WHERE id = ${STATE_WAS_CHANGED}
|
|
290
|
+
`;
|
|
291
|
+
const result = this.sql`
|
|
292
|
+
SELECT state FROM cf_agents_state WHERE id = ${STATE_ROW_ID}
|
|
293
|
+
`;
|
|
294
|
+
if (wasChanged[0]?.state === "true" || // we do this check for people who updated their code before we shipped wasChanged
|
|
295
|
+
result[0]?.state) {
|
|
296
|
+
const state = result[0]?.state;
|
|
297
|
+
this._state = JSON.parse(state);
|
|
298
|
+
return this._state;
|
|
299
|
+
}
|
|
300
|
+
if (this.initialState === DEFAULT_STATE) {
|
|
301
|
+
return void 0;
|
|
302
|
+
}
|
|
303
|
+
this.setState(this.initialState);
|
|
304
|
+
return this.initialState;
|
|
199
305
|
}
|
|
200
|
-
|
|
201
|
-
|
|
306
|
+
/**
|
|
307
|
+
* Execute SQL queries against the Agent's database
|
|
308
|
+
* @template T Type of the returned rows
|
|
309
|
+
* @param strings SQL query template strings
|
|
310
|
+
* @param values Values to be inserted into the query
|
|
311
|
+
* @returns Array of query results
|
|
312
|
+
*/
|
|
313
|
+
sql(strings, ...values) {
|
|
314
|
+
let query = "";
|
|
315
|
+
try {
|
|
316
|
+
query = strings.reduce(
|
|
317
|
+
(acc, str, i) => acc + str + (i < values.length ? "?" : ""),
|
|
318
|
+
""
|
|
319
|
+
);
|
|
320
|
+
return [...this.ctx.storage.sql.exec(query, ...values)];
|
|
321
|
+
} catch (e) {
|
|
322
|
+
console.error(`failed to execute sql query: ${query}`, e);
|
|
323
|
+
throw this.onError(e);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
_setStateInternal(state, source = "server") {
|
|
327
|
+
this._state = state;
|
|
202
328
|
this.sql`
|
|
203
329
|
INSERT OR REPLACE INTO cf_agents_state (id, state)
|
|
204
330
|
VALUES (${STATE_ROW_ID}, ${JSON.stringify(state)})
|
|
@@ -214,9 +340,9 @@ var Agent = class extends Server {
|
|
|
214
340
|
}),
|
|
215
341
|
source !== "server" ? [source.id] : []
|
|
216
342
|
);
|
|
217
|
-
return this
|
|
218
|
-
const { connection, request } =
|
|
219
|
-
return
|
|
343
|
+
return this._tryCatch(() => {
|
|
344
|
+
const { connection, request } = agentContext.getStore() || {};
|
|
345
|
+
return agentContext.run(
|
|
220
346
|
{ agent: this, connection, request },
|
|
221
347
|
async () => {
|
|
222
348
|
return this.onStateUpdate(state, source);
|
|
@@ -229,7 +355,7 @@ var Agent = class extends Server {
|
|
|
229
355
|
* @param state New state to set
|
|
230
356
|
*/
|
|
231
357
|
setState(state) {
|
|
232
|
-
this
|
|
358
|
+
this._setStateInternal(state, "server");
|
|
233
359
|
}
|
|
234
360
|
/**
|
|
235
361
|
* Called when the Agent's state is updated
|
|
@@ -243,14 +369,14 @@ var Agent = class extends Server {
|
|
|
243
369
|
* @param email Email message to process
|
|
244
370
|
*/
|
|
245
371
|
onEmail(email) {
|
|
246
|
-
return
|
|
372
|
+
return agentContext.run(
|
|
247
373
|
{ agent: this, connection: void 0, request: void 0 },
|
|
248
374
|
async () => {
|
|
249
375
|
console.error("onEmail not implemented");
|
|
250
376
|
}
|
|
251
377
|
);
|
|
252
378
|
}
|
|
253
|
-
async
|
|
379
|
+
async _tryCatch(fn) {
|
|
254
380
|
try {
|
|
255
381
|
return await fn();
|
|
256
382
|
} catch (e) {
|
|
@@ -306,7 +432,7 @@ var Agent = class extends Server {
|
|
|
306
432
|
payload
|
|
307
433
|
)}, 'scheduled', ${timestamp})
|
|
308
434
|
`;
|
|
309
|
-
await this
|
|
435
|
+
await this._scheduleNextAlarm();
|
|
310
436
|
return {
|
|
311
437
|
id,
|
|
312
438
|
callback,
|
|
@@ -324,7 +450,7 @@ var Agent = class extends Server {
|
|
|
324
450
|
payload
|
|
325
451
|
)}, 'delayed', ${when}, ${timestamp})
|
|
326
452
|
`;
|
|
327
|
-
await this
|
|
453
|
+
await this._scheduleNextAlarm();
|
|
328
454
|
return {
|
|
329
455
|
id,
|
|
330
456
|
callback,
|
|
@@ -343,7 +469,7 @@ var Agent = class extends Server {
|
|
|
343
469
|
payload
|
|
344
470
|
)}, 'cron', ${when}, ${timestamp})
|
|
345
471
|
`;
|
|
346
|
-
await this
|
|
472
|
+
await this._scheduleNextAlarm();
|
|
347
473
|
return {
|
|
348
474
|
id,
|
|
349
475
|
callback,
|
|
@@ -410,10 +536,10 @@ var Agent = class extends Server {
|
|
|
410
536
|
*/
|
|
411
537
|
async cancelSchedule(id) {
|
|
412
538
|
this.sql`DELETE FROM cf_agents_schedules WHERE id = ${id}`;
|
|
413
|
-
await this
|
|
539
|
+
await this._scheduleNextAlarm();
|
|
414
540
|
return true;
|
|
415
541
|
}
|
|
416
|
-
async
|
|
542
|
+
async _scheduleNextAlarm() {
|
|
417
543
|
const result = this.sql`
|
|
418
544
|
SELECT time FROM cf_agents_schedules
|
|
419
545
|
WHERE time > ${Math.floor(Date.now() / 1e3)}
|
|
@@ -426,51 +552,13 @@ var Agent = class extends Server {
|
|
|
426
552
|
await this.ctx.storage.setAlarm(nextTime);
|
|
427
553
|
}
|
|
428
554
|
}
|
|
429
|
-
/**
|
|
430
|
-
* Method called when an alarm fires
|
|
431
|
-
* Executes any scheduled tasks that are due
|
|
432
|
-
*/
|
|
433
|
-
async alarm() {
|
|
434
|
-
const now = Math.floor(Date.now() / 1e3);
|
|
435
|
-
const result = this.sql`
|
|
436
|
-
SELECT * FROM cf_agents_schedules WHERE time <= ${now}
|
|
437
|
-
`;
|
|
438
|
-
for (const row of result || []) {
|
|
439
|
-
const callback = this[row.callback];
|
|
440
|
-
if (!callback) {
|
|
441
|
-
console.error(`callback ${row.callback} not found`);
|
|
442
|
-
continue;
|
|
443
|
-
}
|
|
444
|
-
await unstable_context.run(
|
|
445
|
-
{ agent: this, connection: void 0, request: void 0 },
|
|
446
|
-
async () => {
|
|
447
|
-
try {
|
|
448
|
-
await callback.bind(this)(JSON.parse(row.payload), row);
|
|
449
|
-
} catch (e) {
|
|
450
|
-
console.error(`error executing callback "${row.callback}"`, e);
|
|
451
|
-
}
|
|
452
|
-
}
|
|
453
|
-
);
|
|
454
|
-
if (row.type === "cron") {
|
|
455
|
-
const nextExecutionTime = getNextCronTime(row.cron);
|
|
456
|
-
const nextTimestamp = Math.floor(nextExecutionTime.getTime() / 1e3);
|
|
457
|
-
this.sql`
|
|
458
|
-
UPDATE cf_agents_schedules SET time = ${nextTimestamp} WHERE id = ${row.id}
|
|
459
|
-
`;
|
|
460
|
-
} else {
|
|
461
|
-
this.sql`
|
|
462
|
-
DELETE FROM cf_agents_schedules WHERE id = ${row.id}
|
|
463
|
-
`;
|
|
464
|
-
}
|
|
465
|
-
}
|
|
466
|
-
await this.#scheduleNextAlarm();
|
|
467
|
-
}
|
|
468
555
|
/**
|
|
469
556
|
* Destroy the Agent, removing all state and scheduled tasks
|
|
470
557
|
*/
|
|
471
558
|
async destroy() {
|
|
472
559
|
this.sql`DROP TABLE IF EXISTS cf_agents_state`;
|
|
473
560
|
this.sql`DROP TABLE IF EXISTS cf_agents_schedules`;
|
|
561
|
+
this.sql`DROP TABLE IF EXISTS cf_agents_mcp_servers`;
|
|
474
562
|
await this.ctx.storage.deleteAlarm();
|
|
475
563
|
await this.ctx.storage.deleteAll();
|
|
476
564
|
}
|
|
@@ -478,9 +566,127 @@ var Agent = class extends Server {
|
|
|
478
566
|
* Get all methods marked as callable on this Agent
|
|
479
567
|
* @returns A map of method names to their metadata
|
|
480
568
|
*/
|
|
481
|
-
|
|
569
|
+
_isCallable(method) {
|
|
482
570
|
return callableMetadata.has(this[method]);
|
|
483
571
|
}
|
|
572
|
+
/**
|
|
573
|
+
* Connect to a new MCP Server
|
|
574
|
+
*
|
|
575
|
+
* @param url MCP Server SSE URL
|
|
576
|
+
* @param callbackHost Base host for the agent, used for the redirect URI.
|
|
577
|
+
* @param agentsPrefix agents routing prefix if not using `agents`
|
|
578
|
+
* @param options MCP client and transport (header) options
|
|
579
|
+
* @returns authUrl
|
|
580
|
+
*/
|
|
581
|
+
async addMcpServer(serverName, url, callbackHost, agentsPrefix = "agents", options) {
|
|
582
|
+
const callbackUrl = `${callbackHost}/${agentsPrefix}/${camelCaseToKebabCase(this._ParentClass.name)}/${this.name}/callback`;
|
|
583
|
+
const result = await this._connectToMcpServerInternal(
|
|
584
|
+
serverName,
|
|
585
|
+
url,
|
|
586
|
+
callbackUrl,
|
|
587
|
+
options
|
|
588
|
+
);
|
|
589
|
+
this.broadcast(
|
|
590
|
+
JSON.stringify({
|
|
591
|
+
type: "cf_agent_mcp_servers",
|
|
592
|
+
mcp: this.getMcpServers()
|
|
593
|
+
})
|
|
594
|
+
);
|
|
595
|
+
return result;
|
|
596
|
+
}
|
|
597
|
+
async _connectToMcpServerInternal(serverName, url, callbackUrl, options, reconnect) {
|
|
598
|
+
const authProvider = new DurableObjectOAuthClientProvider(
|
|
599
|
+
this.ctx.storage,
|
|
600
|
+
this.name,
|
|
601
|
+
callbackUrl
|
|
602
|
+
);
|
|
603
|
+
if (reconnect) {
|
|
604
|
+
authProvider.serverId = reconnect.id;
|
|
605
|
+
if (reconnect.oauthClientId) {
|
|
606
|
+
authProvider.clientId = reconnect.oauthClientId;
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
let headerTransportOpts = {};
|
|
610
|
+
if (options?.transport?.headers) {
|
|
611
|
+
headerTransportOpts = {
|
|
612
|
+
eventSourceInit: {
|
|
613
|
+
fetch: (url2, init) => fetch(url2, {
|
|
614
|
+
...init,
|
|
615
|
+
headers: options?.transport?.headers
|
|
616
|
+
})
|
|
617
|
+
},
|
|
618
|
+
requestInit: {
|
|
619
|
+
headers: options?.transport?.headers
|
|
620
|
+
}
|
|
621
|
+
};
|
|
622
|
+
}
|
|
623
|
+
const { id, authUrl, clientId } = await this.mcp.connect(url, {
|
|
624
|
+
reconnect,
|
|
625
|
+
transport: {
|
|
626
|
+
...headerTransportOpts,
|
|
627
|
+
authProvider
|
|
628
|
+
},
|
|
629
|
+
client: options?.client
|
|
630
|
+
});
|
|
631
|
+
this.sql`
|
|
632
|
+
INSERT OR REPLACE INTO cf_agents_mcp_servers (id, name, server_url, client_id, auth_url, callback_url, server_options)
|
|
633
|
+
VALUES (
|
|
634
|
+
${id},
|
|
635
|
+
${serverName},
|
|
636
|
+
${url},
|
|
637
|
+
${clientId ?? null},
|
|
638
|
+
${authUrl ?? null},
|
|
639
|
+
${callbackUrl},
|
|
640
|
+
${options ? JSON.stringify(options) : null}
|
|
641
|
+
);
|
|
642
|
+
`;
|
|
643
|
+
return {
|
|
644
|
+
id,
|
|
645
|
+
authUrl
|
|
646
|
+
};
|
|
647
|
+
}
|
|
648
|
+
async removeMcpServer(id) {
|
|
649
|
+
this.mcp.closeConnection(id);
|
|
650
|
+
this.sql`
|
|
651
|
+
DELETE FROM cf_agents_mcp_servers WHERE id = ${id};
|
|
652
|
+
`;
|
|
653
|
+
this.broadcast(
|
|
654
|
+
JSON.stringify({
|
|
655
|
+
type: "cf_agent_mcp_servers",
|
|
656
|
+
mcp: this.getMcpServers()
|
|
657
|
+
})
|
|
658
|
+
);
|
|
659
|
+
}
|
|
660
|
+
getMcpServers() {
|
|
661
|
+
const mcpState = {
|
|
662
|
+
servers: {},
|
|
663
|
+
tools: this.mcp.listTools(),
|
|
664
|
+
prompts: this.mcp.listPrompts(),
|
|
665
|
+
resources: this.mcp.listResources()
|
|
666
|
+
};
|
|
667
|
+
const servers = this.sql`
|
|
668
|
+
SELECT id, name, server_url, client_id, auth_url, callback_url, server_options FROM cf_agents_mcp_servers;
|
|
669
|
+
`;
|
|
670
|
+
for (const server of servers) {
|
|
671
|
+
mcpState.servers[server.id] = {
|
|
672
|
+
name: server.name,
|
|
673
|
+
server_url: server.server_url,
|
|
674
|
+
auth_url: server.auth_url,
|
|
675
|
+
state: this.mcp.mcpConnections[server.id].connectionState,
|
|
676
|
+
instructions: this.mcp.mcpConnections[server.id].instructions ?? null,
|
|
677
|
+
capabilities: this.mcp.mcpConnections[server.id].serverCapabilities ?? null
|
|
678
|
+
};
|
|
679
|
+
}
|
|
680
|
+
return mcpState;
|
|
681
|
+
}
|
|
682
|
+
};
|
|
683
|
+
/**
|
|
684
|
+
* Agent configuration options
|
|
685
|
+
*/
|
|
686
|
+
Agent.options = {
|
|
687
|
+
/** Whether the Agent should hibernate when inactive */
|
|
688
|
+
hibernate: true
|
|
689
|
+
// default to hibernate
|
|
484
690
|
};
|
|
485
691
|
async function routeAgentRequest(request, env, options) {
|
|
486
692
|
const corsHeaders = options?.cors === true ? {
|
|
@@ -519,62 +725,59 @@ async function routeAgentRequest(request, env, options) {
|
|
|
519
725
|
}
|
|
520
726
|
async function routeAgentEmail(email, env, options) {
|
|
521
727
|
}
|
|
522
|
-
function getAgentByName(namespace, name, options) {
|
|
728
|
+
async function getAgentByName(namespace, name, options) {
|
|
523
729
|
return getServerByName(namespace, name, options);
|
|
524
730
|
}
|
|
525
731
|
var StreamingResponse = class {
|
|
526
|
-
#connection;
|
|
527
|
-
#id;
|
|
528
|
-
#closed = false;
|
|
529
732
|
constructor(connection, id) {
|
|
530
|
-
this
|
|
531
|
-
this
|
|
733
|
+
this._closed = false;
|
|
734
|
+
this._connection = connection;
|
|
735
|
+
this._id = id;
|
|
532
736
|
}
|
|
533
737
|
/**
|
|
534
738
|
* Send a chunk of data to the client
|
|
535
739
|
* @param chunk The data to send
|
|
536
740
|
*/
|
|
537
741
|
send(chunk) {
|
|
538
|
-
if (this
|
|
742
|
+
if (this._closed) {
|
|
539
743
|
throw new Error("StreamingResponse is already closed");
|
|
540
744
|
}
|
|
541
745
|
const response = {
|
|
542
746
|
type: "rpc",
|
|
543
|
-
id: this
|
|
747
|
+
id: this._id,
|
|
544
748
|
success: true,
|
|
545
749
|
result: chunk,
|
|
546
750
|
done: false
|
|
547
751
|
};
|
|
548
|
-
this
|
|
752
|
+
this._connection.send(JSON.stringify(response));
|
|
549
753
|
}
|
|
550
754
|
/**
|
|
551
755
|
* End the stream and send the final chunk (if any)
|
|
552
756
|
* @param finalChunk Optional final chunk of data to send
|
|
553
757
|
*/
|
|
554
758
|
end(finalChunk) {
|
|
555
|
-
if (this
|
|
759
|
+
if (this._closed) {
|
|
556
760
|
throw new Error("StreamingResponse is already closed");
|
|
557
761
|
}
|
|
558
|
-
this
|
|
762
|
+
this._closed = true;
|
|
559
763
|
const response = {
|
|
560
764
|
type: "rpc",
|
|
561
|
-
id: this
|
|
765
|
+
id: this._id,
|
|
562
766
|
success: true,
|
|
563
767
|
result: finalChunk,
|
|
564
768
|
done: true
|
|
565
769
|
};
|
|
566
|
-
this
|
|
770
|
+
this._connection.send(JSON.stringify(response));
|
|
567
771
|
}
|
|
568
772
|
};
|
|
569
773
|
|
|
570
774
|
export {
|
|
571
775
|
unstable_callable,
|
|
572
|
-
|
|
573
|
-
unstable_context,
|
|
776
|
+
getCurrentAgent,
|
|
574
777
|
Agent,
|
|
575
778
|
routeAgentRequest,
|
|
576
779
|
routeAgentEmail,
|
|
577
780
|
getAgentByName,
|
|
578
781
|
StreamingResponse
|
|
579
782
|
};
|
|
580
|
-
//# sourceMappingURL=chunk-
|
|
783
|
+
//# sourceMappingURL=chunk-CFTLYEEK.js.map
|