agents 0.0.0-3471713 → 0.0.0-352d62c

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.
Files changed (51) hide show
  1. package/README.md +131 -25
  2. package/dist/ai-chat-agent.d.ts +54 -4
  3. package/dist/ai-chat-agent.js +182 -86
  4. package/dist/ai-chat-agent.js.map +1 -1
  5. package/dist/ai-react.d.ts +22 -5
  6. package/dist/ai-react.js +54 -45
  7. package/dist/ai-react.js.map +1 -1
  8. package/dist/ai-types.d.ts +31 -8
  9. package/dist/ai-types.js +6 -0
  10. package/dist/chunk-EEKLJYON.js +17 -0
  11. package/dist/chunk-EEKLJYON.js.map +1 -0
  12. package/dist/chunk-EM3J4KV7.js +598 -0
  13. package/dist/chunk-EM3J4KV7.js.map +1 -0
  14. package/dist/chunk-ID62XSAS.js +1290 -0
  15. package/dist/chunk-ID62XSAS.js.map +1 -0
  16. package/dist/chunk-PVQZBKN7.js +106 -0
  17. package/dist/chunk-PVQZBKN7.js.map +1 -0
  18. package/dist/chunk-QEVM4BVL.js +116 -0
  19. package/dist/chunk-QEVM4BVL.js.map +1 -0
  20. package/dist/client-DgyzBU_8.d.ts +4601 -0
  21. package/dist/client.d.ts +16 -2
  22. package/dist/client.js +7 -126
  23. package/dist/client.js.map +1 -1
  24. package/dist/index.d.ts +266 -26
  25. package/dist/index.js +15 -8
  26. package/dist/mcp/client.d.ts +11 -675
  27. package/dist/mcp/client.js +3 -262
  28. package/dist/mcp/client.js.map +1 -1
  29. package/dist/mcp/do-oauth-client-provider.d.ts +41 -0
  30. package/dist/mcp/do-oauth-client-provider.js +7 -0
  31. package/dist/mcp/index.d.ts +73 -6
  32. package/dist/mcp/index.js +792 -179
  33. package/dist/mcp/index.js.map +1 -1
  34. package/dist/observability/index.d.ts +46 -0
  35. package/dist/observability/index.js +11 -0
  36. package/dist/observability/index.js.map +1 -0
  37. package/dist/react.d.ts +89 -5
  38. package/dist/react.js +40 -26
  39. package/dist/react.js.map +1 -1
  40. package/dist/schedule.d.ts +6 -6
  41. package/dist/schedule.js +4 -6
  42. package/dist/schedule.js.map +1 -1
  43. package/dist/serializable.d.ts +32 -0
  44. package/dist/serializable.js +1 -0
  45. package/dist/serializable.js.map +1 -0
  46. package/package.json +84 -51
  47. package/src/index.ts +1151 -149
  48. package/dist/chunk-HMLY7DHA.js +0 -16
  49. package/dist/chunk-YMUU7QHV.js +0 -595
  50. package/dist/chunk-YMUU7QHV.js.map +0 -1
  51. /package/dist/{chunk-HMLY7DHA.js.map → mcp/do-oauth-client-provider.js.map} +0 -0
@@ -1,19 +1,17 @@
1
1
  import {
2
2
  Agent
3
- } from "./chunk-YMUU7QHV.js";
4
- import {
5
- __privateAdd,
6
- __privateMethod
7
- } from "./chunk-HMLY7DHA.js";
3
+ } from "./chunk-ID62XSAS.js";
4
+ import "./chunk-EM3J4KV7.js";
5
+ import "./chunk-PVQZBKN7.js";
6
+ import "./chunk-QEVM4BVL.js";
7
+ import "./chunk-EEKLJYON.js";
8
8
 
9
9
  // src/ai-chat-agent.ts
10
10
  import { appendResponseMessages } from "ai";
11
11
  var decoder = new TextDecoder();
12
- var _AIChatAgent_instances, broadcastChatMessage_fn, tryCatch_fn, persistMessages_fn, reply_fn;
13
12
  var AIChatAgent = class extends Agent {
14
13
  constructor(ctx, env) {
15
14
  super(ctx, env);
16
- __privateAdd(this, _AIChatAgent_instances);
17
15
  this.sql`create table if not exists cf_ai_chat_agent_messages (
18
16
  id text primary key,
19
17
  message text not null,
@@ -22,64 +20,111 @@ var AIChatAgent = class extends Agent {
22
20
  this.messages = (this.sql`select * from cf_ai_chat_agent_messages` || []).map((row) => {
23
21
  return JSON.parse(row.message);
24
22
  });
23
+ this._chatMessageAbortControllers = /* @__PURE__ */ new Map();
24
+ }
25
+ _broadcastChatMessage(message, exclude) {
26
+ this.broadcast(JSON.stringify(message), exclude);
25
27
  }
26
28
  async onMessage(connection, message) {
27
29
  if (typeof message === "string") {
28
30
  let data;
29
31
  try {
30
32
  data = JSON.parse(message);
31
- } catch (error) {
33
+ } catch (_error) {
32
34
  return;
33
35
  }
34
- if (data.type === "cf_agent_use_chat_request" && data.init.method === "POST") {
36
+ if (data.type === "cf_agent_use_chat_request" /* CF_AGENT_USE_CHAT_REQUEST */ && data.init.method === "POST") {
35
37
  const {
36
- method,
37
- keepalive,
38
- headers,
39
- body,
38
+ // method,
39
+ // keepalive,
40
+ // headers,
41
+ body
40
42
  // we're reading this
41
- redirect,
42
- integrity,
43
- credentials,
44
- mode,
45
- referrer,
46
- referrerPolicy,
47
- window
43
+ //
44
+ // // these might not exist?
48
45
  // dispatcher,
49
46
  // duplex
50
47
  } = data.init;
51
48
  const { messages } = JSON.parse(body);
52
- __privateMethod(this, _AIChatAgent_instances, broadcastChatMessage_fn).call(this, {
53
- type: "cf_agent_chat_messages",
54
- messages
55
- }, [connection.id]);
56
- await __privateMethod(this, _AIChatAgent_instances, persistMessages_fn).call(this, messages, [connection.id]);
57
- return __privateMethod(this, _AIChatAgent_instances, tryCatch_fn).call(this, async () => {
58
- const response = await this.onChatMessage(async ({ response: response2 }) => {
59
- const finalMessages = appendResponseMessages({
60
- messages,
61
- responseMessages: response2.messages
62
- });
63
- await __privateMethod(this, _AIChatAgent_instances, persistMessages_fn).call(this, finalMessages, [connection.id]);
64
- });
49
+ this._broadcastChatMessage(
50
+ {
51
+ messages,
52
+ type: "cf_agent_chat_messages" /* CF_AGENT_CHAT_MESSAGES */
53
+ },
54
+ [connection.id]
55
+ );
56
+ await this.persistMessages(messages, [connection.id]);
57
+ this.observability?.emit(
58
+ {
59
+ displayMessage: "Chat message request",
60
+ id: data.id,
61
+ payload: {},
62
+ timestamp: Date.now(),
63
+ type: "message:request"
64
+ },
65
+ this.ctx
66
+ );
67
+ const chatMessageId = data.id;
68
+ const abortSignal = this._getAbortSignal(chatMessageId);
69
+ return this._tryCatchChat(async () => {
70
+ const response = await this.onChatMessage(
71
+ async ({ response: response2 }) => {
72
+ const finalMessages = appendResponseMessages({
73
+ messages,
74
+ responseMessages: response2.messages
75
+ });
76
+ await this.persistMessages(finalMessages, [connection.id]);
77
+ this._removeAbortController(chatMessageId);
78
+ this.observability?.emit(
79
+ {
80
+ displayMessage: "Chat message response",
81
+ id: data.id,
82
+ payload: {},
83
+ timestamp: Date.now(),
84
+ type: "message:response"
85
+ },
86
+ this.ctx
87
+ );
88
+ },
89
+ abortSignal ? { abortSignal } : void 0
90
+ );
65
91
  if (response) {
66
- await __privateMethod(this, _AIChatAgent_instances, reply_fn).call(this, data.id, response);
92
+ await this._reply(data.id, response);
93
+ } else {
94
+ console.warn(
95
+ `[AIChatAgent] onChatMessage returned no response for chatMessageId: ${chatMessageId}`
96
+ );
97
+ this._broadcastChatMessage(
98
+ {
99
+ body: "No response was generated by the agent.",
100
+ done: true,
101
+ id: data.id,
102
+ type: "cf_agent_use_chat_response" /* CF_AGENT_USE_CHAT_RESPONSE */
103
+ },
104
+ [connection.id]
105
+ );
67
106
  }
68
107
  });
69
108
  }
70
- if (data.type === "cf_agent_chat_clear") {
109
+ if (data.type === "cf_agent_chat_clear" /* CF_AGENT_CHAT_CLEAR */) {
110
+ this._destroyAbortControllers();
71
111
  this.sql`delete from cf_ai_chat_agent_messages`;
72
112
  this.messages = [];
73
- __privateMethod(this, _AIChatAgent_instances, broadcastChatMessage_fn).call(this, {
74
- type: "cf_agent_chat_clear"
75
- }, [connection.id]);
76
- } else if (data.type === "cf_agent_chat_messages") {
77
- await __privateMethod(this, _AIChatAgent_instances, persistMessages_fn).call(this, data.messages, [connection.id]);
113
+ this._broadcastChatMessage(
114
+ {
115
+ type: "cf_agent_chat_clear" /* CF_AGENT_CHAT_CLEAR */
116
+ },
117
+ [connection.id]
118
+ );
119
+ } else if (data.type === "cf_agent_chat_messages" /* CF_AGENT_CHAT_MESSAGES */) {
120
+ await this.persistMessages(data.messages, [connection.id]);
121
+ } else if (data.type === "cf_agent_chat_request_cancel" /* CF_AGENT_CHAT_REQUEST_CANCEL */) {
122
+ this._cancelChatRequest(data.id);
78
123
  }
79
124
  }
80
125
  }
81
126
  async onRequest(request) {
82
- return __privateMethod(this, _AIChatAgent_instances, tryCatch_fn).call(this, () => {
127
+ return this._tryCatchChat(() => {
83
128
  const url = new URL(request.url);
84
129
  if (url.pathname.endsWith("/get-messages")) {
85
130
  const messages = (this.sql`select * from cf_ai_chat_agent_messages` || []).map((row) => {
@@ -90,12 +135,32 @@ var AIChatAgent = class extends Agent {
90
135
  return super.onRequest(request);
91
136
  });
92
137
  }
138
+ async _tryCatchChat(fn) {
139
+ try {
140
+ return await fn();
141
+ } catch (e) {
142
+ throw this.onError(e);
143
+ }
144
+ }
145
+ async _drainStream(stream) {
146
+ const reader = stream.getReader();
147
+ try {
148
+ while (true) {
149
+ const { done, value } = await reader.read();
150
+ if (done) break;
151
+ decoder.decode(value);
152
+ }
153
+ } finally {
154
+ reader.releaseLock();
155
+ }
156
+ }
93
157
  /**
94
158
  * Handle incoming chat messages and generate a response
95
159
  * @param onFinish Callback to be called when the response is finished
160
+ * @param options.signal A signal to pass to any child requests which can be used to cancel them
96
161
  * @returns Response to send to the client or undefined
97
162
  */
98
- async onChatMessage(onFinish) {
163
+ async onChatMessage(onFinish, options) {
99
164
  throw new Error(
100
165
  "recieved a chat message, override onChatMessage and return a Response to send to the client"
101
166
  );
@@ -105,62 +170,93 @@ var AIChatAgent = class extends Agent {
105
170
  * @param messages Chat messages to save
106
171
  */
107
172
  async saveMessages(messages) {
108
- await __privateMethod(this, _AIChatAgent_instances, persistMessages_fn).call(this, messages);
173
+ await this.persistMessages(messages);
109
174
  const response = await this.onChatMessage(async ({ response: response2 }) => {
110
175
  const finalMessages = appendResponseMessages({
111
176
  messages,
112
177
  responseMessages: response2.messages
113
178
  });
114
- await __privateMethod(this, _AIChatAgent_instances, persistMessages_fn).call(this, finalMessages, []);
179
+ await this.persistMessages(finalMessages, []);
115
180
  });
116
- if (response) {
117
- for await (const chunk of response.body) {
118
- decoder.decode(chunk);
119
- }
120
- response.body?.cancel();
181
+ if (response?.body) {
182
+ await this._drainStream(response.body);
183
+ response.body.cancel();
121
184
  }
122
185
  }
123
- };
124
- _AIChatAgent_instances = new WeakSet();
125
- broadcastChatMessage_fn = function(message, exclude) {
126
- this.broadcast(JSON.stringify(message), exclude);
127
- };
128
- tryCatch_fn = async function(fn) {
129
- try {
130
- return await fn();
131
- } catch (e) {
132
- throw this.onError(e);
133
- }
134
- };
135
- persistMessages_fn = async function(messages, excludeBroadcastIds = []) {
136
- this.sql`delete from cf_ai_chat_agent_messages`;
137
- for (const message of messages) {
138
- this.sql`insert into cf_ai_chat_agent_messages (id, message) values (${message.id},${JSON.stringify(message)})`;
186
+ async persistMessages(messages, excludeBroadcastIds = []) {
187
+ this.sql`delete from cf_ai_chat_agent_messages`;
188
+ for (const message of messages) {
189
+ this.sql`insert into cf_ai_chat_agent_messages (id, message) values (${message.id},${JSON.stringify(message)})`;
190
+ }
191
+ this.messages = messages;
192
+ this._broadcastChatMessage(
193
+ {
194
+ messages,
195
+ type: "cf_agent_chat_messages" /* CF_AGENT_CHAT_MESSAGES */
196
+ },
197
+ excludeBroadcastIds
198
+ );
139
199
  }
140
- this.messages = messages;
141
- __privateMethod(this, _AIChatAgent_instances, broadcastChatMessage_fn).call(this, {
142
- type: "cf_agent_chat_messages",
143
- messages
144
- }, excludeBroadcastIds);
145
- };
146
- reply_fn = async function(id, response) {
147
- return __privateMethod(this, _AIChatAgent_instances, tryCatch_fn).call(this, async () => {
148
- for await (const chunk of response.body) {
149
- const body = decoder.decode(chunk);
150
- __privateMethod(this, _AIChatAgent_instances, broadcastChatMessage_fn).call(this, {
200
+ async _reply(id, response) {
201
+ return this._tryCatchChat(async () => {
202
+ if (response.body) {
203
+ await this._drainStream(response.body);
204
+ response.body.cancel();
205
+ }
206
+ this._broadcastChatMessage({
207
+ body: "",
208
+ done: true,
151
209
  id,
152
- type: "cf_agent_use_chat_response",
153
- body,
154
- done: false
210
+ type: "cf_agent_use_chat_response" /* CF_AGENT_USE_CHAT_RESPONSE */
155
211
  });
156
- }
157
- __privateMethod(this, _AIChatAgent_instances, broadcastChatMessage_fn).call(this, {
158
- id,
159
- type: "cf_agent_use_chat_response",
160
- body: "",
161
- done: true
162
212
  });
163
- });
213
+ }
214
+ /**
215
+ * For the given message id, look up its associated AbortController
216
+ * If the AbortController does not exist, create and store one in memory
217
+ *
218
+ * returns the AbortSignal associated with the AbortController
219
+ */
220
+ _getAbortSignal(id) {
221
+ if (typeof id !== "string") {
222
+ return void 0;
223
+ }
224
+ if (!this._chatMessageAbortControllers.has(id)) {
225
+ this._chatMessageAbortControllers.set(id, new AbortController());
226
+ }
227
+ return this._chatMessageAbortControllers.get(id)?.signal;
228
+ }
229
+ /**
230
+ * Remove an abort controller from the cache of pending message responses
231
+ */
232
+ _removeAbortController(id) {
233
+ this._chatMessageAbortControllers.delete(id);
234
+ }
235
+ /**
236
+ * Propagate an abort signal for any requests associated with the given message id
237
+ */
238
+ _cancelChatRequest(id) {
239
+ if (this._chatMessageAbortControllers.has(id)) {
240
+ const abortController = this._chatMessageAbortControllers.get(id);
241
+ abortController?.abort();
242
+ }
243
+ }
244
+ /**
245
+ * Abort all pending requests and clear the cache of AbortControllers
246
+ */
247
+ _destroyAbortControllers() {
248
+ for (const controller of this._chatMessageAbortControllers.values()) {
249
+ controller?.abort();
250
+ }
251
+ this._chatMessageAbortControllers.clear();
252
+ }
253
+ /**
254
+ * When the DO is destroyed, cancel all pending requests
255
+ */
256
+ async destroy() {
257
+ this._destroyAbortControllers();
258
+ await super.destroy();
259
+ }
164
260
  };
165
261
  export {
166
262
  AIChatAgent
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/ai-chat-agent.ts"],"sourcesContent":["import { Agent, type AgentContext, type Connection, type WSMessage } from \"./\";\nimport type {\n Message as ChatMessage,\n StreamTextOnFinishCallback,\n ToolSet,\n} from \"ai\";\nimport { appendResponseMessages } from \"ai\";\nimport type { OutgoingMessage, IncomingMessage } from \"./ai-types\";\nconst decoder = new TextDecoder();\n\n/**\n * Extension of Agent with built-in chat capabilities\n * @template Env Environment type containing bindings\n */\nexport class AIChatAgent<Env = unknown, State = unknown> extends Agent<\n Env,\n State\n> {\n /** Array of chat messages for the current conversation */\n messages: ChatMessage[];\n constructor(ctx: AgentContext, env: Env) {\n super(ctx, env);\n this.sql`create table if not exists cf_ai_chat_agent_messages (\n id text primary key,\n message text not null,\n created_at datetime default current_timestamp\n )`;\n this.messages = (\n this.sql`select * from cf_ai_chat_agent_messages` || []\n ).map((row) => {\n return JSON.parse(row.message as string);\n });\n }\n\n #broadcastChatMessage(message: OutgoingMessage, exclude?: string[]) {\n this.broadcast(JSON.stringify(message), exclude);\n }\n\n override async onMessage(connection: Connection, message: WSMessage) {\n if (typeof message === \"string\") {\n let data: IncomingMessage;\n try {\n data = JSON.parse(message) as IncomingMessage;\n } catch (error) {\n // silently ignore invalid messages for now\n // TODO: log errors with log levels\n return;\n }\n if (\n data.type === \"cf_agent_use_chat_request\" &&\n data.init.method === \"POST\"\n ) {\n const {\n method,\n keepalive,\n headers,\n body, // we're reading this\n redirect,\n integrity,\n credentials,\n mode,\n referrer,\n referrerPolicy,\n window,\n // dispatcher,\n // duplex\n } = data.init;\n const { messages } = JSON.parse(body as string);\n this.#broadcastChatMessage(\n {\n type: \"cf_agent_chat_messages\",\n messages,\n },\n [connection.id]\n );\n await this.#persistMessages(messages, [connection.id]);\n return this.#tryCatch(async () => {\n const response = await this.onChatMessage(async ({ response }) => {\n const finalMessages = appendResponseMessages({\n messages,\n responseMessages: response.messages,\n });\n\n await this.#persistMessages(finalMessages, [connection.id]);\n });\n if (response) {\n await this.#reply(data.id, response);\n }\n });\n }\n if (data.type === \"cf_agent_chat_clear\") {\n this.sql`delete from cf_ai_chat_agent_messages`;\n this.messages = [];\n this.#broadcastChatMessage(\n {\n type: \"cf_agent_chat_clear\",\n },\n [connection.id]\n );\n } else if (data.type === \"cf_agent_chat_messages\") {\n // replace the messages with the new ones\n await this.#persistMessages(data.messages, [connection.id]);\n }\n }\n }\n\n override async onRequest(request: Request): Promise<Response> {\n return this.#tryCatch(() => {\n const url = new URL(request.url);\n if (url.pathname.endsWith(\"/get-messages\")) {\n const messages = (\n this.sql`select * from cf_ai_chat_agent_messages` || []\n ).map((row) => {\n return JSON.parse(row.message as string);\n });\n return Response.json(messages);\n }\n return super.onRequest(request);\n });\n }\n\n async #tryCatch<T>(fn: () => T | Promise<T>) {\n try {\n return await fn();\n } catch (e) {\n throw this.onError(e);\n }\n }\n\n /**\n * Handle incoming chat messages and generate a response\n * @param onFinish Callback to be called when the response is finished\n * @returns Response to send to the client or undefined\n */\n async onChatMessage(\n onFinish: StreamTextOnFinishCallback<ToolSet>\n ): Promise<Response | undefined> {\n throw new Error(\n \"recieved a chat message, override onChatMessage and return a Response to send to the client\"\n );\n }\n\n /**\n * Save messages on the server side and trigger AI response\n * @param messages Chat messages to save\n */\n async saveMessages(messages: ChatMessage[]) {\n await this.#persistMessages(messages);\n const response = await this.onChatMessage(async ({ response }) => {\n const finalMessages = appendResponseMessages({\n messages,\n responseMessages: response.messages,\n });\n\n await this.#persistMessages(finalMessages, []);\n });\n if (response) {\n // we're just going to drain the body\n // @ts-ignore TODO: fix this type error\n for await (const chunk of response.body!) {\n decoder.decode(chunk);\n }\n response.body?.cancel();\n }\n }\n\n async #persistMessages(\n messages: ChatMessage[],\n excludeBroadcastIds: string[] = []\n ) {\n this.sql`delete from cf_ai_chat_agent_messages`;\n for (const message of messages) {\n this.sql`insert into cf_ai_chat_agent_messages (id, message) values (${\n message.id\n },${JSON.stringify(message)})`;\n }\n this.messages = messages;\n this.#broadcastChatMessage(\n {\n type: \"cf_agent_chat_messages\",\n messages: messages,\n },\n excludeBroadcastIds\n );\n }\n\n async #reply(id: string, response: Response) {\n // now take chunks out from dataStreamResponse and send them to the client\n return this.#tryCatch(async () => {\n // @ts-expect-error TODO: fix this type error\n for await (const chunk of response.body!) {\n const body = decoder.decode(chunk);\n\n this.#broadcastChatMessage({\n id,\n type: \"cf_agent_use_chat_response\",\n body,\n done: false,\n });\n }\n\n this.#broadcastChatMessage({\n id,\n type: \"cf_agent_use_chat_response\",\n body: \"\",\n done: true,\n });\n });\n }\n}\n"],"mappings":";;;;;;;;;AAMA,SAAS,8BAA8B;AAEvC,IAAM,UAAU,IAAI,YAAY;AARhC;AAcO,IAAM,cAAN,cAA0D,MAG/D;AAAA,EAGA,YAAY,KAAmB,KAAU;AACvC,UAAM,KAAK,GAAG;AAPX;AAQH,SAAK;AAAA;AAAA;AAAA;AAAA;AAKL,SAAK,YACH,KAAK,gDAAgD,CAAC,GACtD,IAAI,CAAC,QAAQ;AACb,aAAO,KAAK,MAAM,IAAI,OAAiB;AAAA,IACzC,CAAC;AAAA,EACH;AAAA,EAMA,MAAe,UAAU,YAAwB,SAAoB;AACnE,QAAI,OAAO,YAAY,UAAU;AAC/B,UAAI;AACJ,UAAI;AACF,eAAO,KAAK,MAAM,OAAO;AAAA,MAC3B,SAAS,OAAO;AAGd;AAAA,MACF;AACA,UACE,KAAK,SAAS,+BACd,KAAK,KAAK,WAAW,QACrB;AACA,cAAM;AAAA,UACJ;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA;AAAA;AAAA,QAGF,IAAI,KAAK;AACT,cAAM,EAAE,SAAS,IAAI,KAAK,MAAM,IAAc;AAC9C,8BAAK,iDAAL,WACE;AAAA,UACE,MAAM;AAAA,UACN;AAAA,QACF,GACA,CAAC,WAAW,EAAE;AAEhB,cAAM,sBAAK,4CAAL,WAAsB,UAAU,CAAC,WAAW,EAAE;AACpD,eAAO,sBAAK,qCAAL,WAAe,YAAY;AAChC,gBAAM,WAAW,MAAM,KAAK,cAAc,OAAO,EAAE,UAAAA,UAAS,MAAM;AAChE,kBAAM,gBAAgB,uBAAuB;AAAA,cAC3C;AAAA,cACA,kBAAkBA,UAAS;AAAA,YAC7B,CAAC;AAED,kBAAM,sBAAK,4CAAL,WAAsB,eAAe,CAAC,WAAW,EAAE;AAAA,UAC3D,CAAC;AACD,cAAI,UAAU;AACZ,kBAAM,sBAAK,kCAAL,WAAY,KAAK,IAAI;AAAA,UAC7B;AAAA,QACF;AAAA,MACF;AACA,UAAI,KAAK,SAAS,uBAAuB;AACvC,aAAK;AACL,aAAK,WAAW,CAAC;AACjB,8BAAK,iDAAL,WACE;AAAA,UACE,MAAM;AAAA,QACR,GACA,CAAC,WAAW,EAAE;AAAA,MAElB,WAAW,KAAK,SAAS,0BAA0B;AAEjD,cAAM,sBAAK,4CAAL,WAAsB,KAAK,UAAU,CAAC,WAAW,EAAE;AAAA,MAC3D;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAe,UAAU,SAAqC;AAC5D,WAAO,sBAAK,qCAAL,WAAe,MAAM;AAC1B,YAAM,MAAM,IAAI,IAAI,QAAQ,GAAG;AAC/B,UAAI,IAAI,SAAS,SAAS,eAAe,GAAG;AAC1C,cAAM,YACJ,KAAK,gDAAgD,CAAC,GACtD,IAAI,CAAC,QAAQ;AACb,iBAAO,KAAK,MAAM,IAAI,OAAiB;AAAA,QACzC,CAAC;AACD,eAAO,SAAS,KAAK,QAAQ;AAAA,MAC/B;AACA,aAAO,MAAM,UAAU,OAAO;AAAA,IAChC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAeA,MAAM,cACJ,UAC+B;AAC/B,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,aAAa,UAAyB;AAC1C,UAAM,sBAAK,4CAAL,WAAsB;AAC5B,UAAM,WAAW,MAAM,KAAK,cAAc,OAAO,EAAE,UAAAA,UAAS,MAAM;AAChE,YAAM,gBAAgB,uBAAuB;AAAA,QAC3C;AAAA,QACA,kBAAkBA,UAAS;AAAA,MAC7B,CAAC;AAED,YAAM,sBAAK,4CAAL,WAAsB,eAAe,CAAC;AAAA,IAC9C,CAAC;AACD,QAAI,UAAU;AAGZ,uBAAiB,SAAS,SAAS,MAAO;AACxC,gBAAQ,OAAO,KAAK;AAAA,MACtB;AACA,eAAS,MAAM,OAAO;AAAA,IACxB;AAAA,EACF;AA6CF;AAnMO;AAoBL,0BAAqB,SAAC,SAA0B,SAAoB;AAClE,OAAK,UAAU,KAAK,UAAU,OAAO,GAAG,OAAO;AACjD;AAqFM,cAAY,eAAC,IAA0B;AAC3C,MAAI;AACF,WAAO,MAAM,GAAG;AAAA,EAClB,SAAS,GAAG;AACV,UAAM,KAAK,QAAQ,CAAC;AAAA,EACtB;AACF;AAuCM,qBAAgB,eACpB,UACA,sBAAgC,CAAC,GACjC;AACA,OAAK;AACL,aAAW,WAAW,UAAU;AAC9B,SAAK,kEACH,QAAQ,EACV,IAAI,KAAK,UAAU,OAAO,CAAC;AAAA,EAC7B;AACA,OAAK,WAAW;AAChB,wBAAK,iDAAL,WACE;AAAA,IACE,MAAM;AAAA,IACN;AAAA,EACF,GACA;AAEJ;AAEM,WAAM,eAAC,IAAY,UAAoB;AAE3C,SAAO,sBAAK,qCAAL,WAAe,YAAY;AAEhC,qBAAiB,SAAS,SAAS,MAAO;AACxC,YAAM,OAAO,QAAQ,OAAO,KAAK;AAEjC,4BAAK,iDAAL,WAA2B;AAAA,QACzB;AAAA,QACA,MAAM;AAAA,QACN;AAAA,QACA,MAAM;AAAA,MACR;AAAA,IACF;AAEA,0BAAK,iDAAL,WAA2B;AAAA,MACzB;AAAA,MACA,MAAM;AAAA,MACN,MAAM;AAAA,MACN,MAAM;AAAA,IACR;AAAA,EACF;AACF;","names":["response"]}
1
+ {"version":3,"sources":["../src/ai-chat-agent.ts"],"sourcesContent":["import type {\n Message as ChatMessage,\n StreamTextOnFinishCallback,\n ToolSet\n} from \"ai\";\nimport { appendResponseMessages } from \"ai\";\nimport { Agent, type AgentContext, type Connection, type WSMessage } from \"./\";\nimport {\n MessageType,\n type IncomingMessage,\n type OutgoingMessage\n} from \"./ai-types\";\n\nconst decoder = new TextDecoder();\n\n/**\n * Extension of Agent with built-in chat capabilities\n * @template Env Environment type containing bindings\n */\nexport class AIChatAgent<Env = unknown, State = unknown> extends Agent<\n Env,\n State\n> {\n /**\n * Map of message `id`s to `AbortController`s\n * useful to propagate request cancellation signals for any external calls made by the agent\n */\n private _chatMessageAbortControllers: Map<string, AbortController>;\n /** Array of chat messages for the current conversation */\n messages: ChatMessage[];\n constructor(ctx: AgentContext, env: Env) {\n super(ctx, env);\n this.sql`create table if not exists cf_ai_chat_agent_messages (\n id text primary key,\n message text not null,\n created_at datetime default current_timestamp\n )`;\n this.messages = (\n this.sql`select * from cf_ai_chat_agent_messages` || []\n ).map((row) => {\n return JSON.parse(row.message as string);\n });\n\n this._chatMessageAbortControllers = new Map();\n }\n\n private _broadcastChatMessage(message: OutgoingMessage, exclude?: string[]) {\n this.broadcast(JSON.stringify(message), exclude);\n }\n\n override async onMessage(connection: Connection, message: WSMessage) {\n if (typeof message === \"string\") {\n let data: IncomingMessage;\n try {\n data = JSON.parse(message) as IncomingMessage;\n } catch (_error) {\n // silently ignore invalid messages for now\n // TODO: log errors with log levels\n return;\n }\n if (\n data.type === MessageType.CF_AGENT_USE_CHAT_REQUEST &&\n data.init.method === \"POST\"\n ) {\n const {\n // method,\n // keepalive,\n // headers,\n body // we're reading this\n //\n // // these might not exist?\n // dispatcher,\n // duplex\n } = data.init;\n const { messages } = JSON.parse(body as string);\n this._broadcastChatMessage(\n {\n messages,\n type: MessageType.CF_AGENT_CHAT_MESSAGES\n },\n [connection.id]\n );\n\n await this.persistMessages(messages, [connection.id]);\n\n this.observability?.emit(\n {\n displayMessage: \"Chat message request\",\n id: data.id,\n payload: {},\n timestamp: Date.now(),\n type: \"message:request\"\n },\n this.ctx\n );\n\n const chatMessageId = data.id;\n const abortSignal = this._getAbortSignal(chatMessageId);\n\n return this._tryCatchChat(async () => {\n const response = await this.onChatMessage(\n async ({ response }) => {\n const finalMessages = appendResponseMessages({\n messages,\n responseMessages: response.messages\n });\n\n await this.persistMessages(finalMessages, [connection.id]);\n this._removeAbortController(chatMessageId);\n\n this.observability?.emit(\n {\n displayMessage: \"Chat message response\",\n id: data.id,\n payload: {},\n timestamp: Date.now(),\n type: \"message:response\"\n },\n this.ctx\n );\n },\n abortSignal ? { abortSignal } : undefined\n );\n\n if (response) {\n await this._reply(data.id, response);\n } else {\n // Log a warning for observability\n console.warn(\n `[AIChatAgent] onChatMessage returned no response for chatMessageId: ${chatMessageId}`\n );\n // Send a fallback message to the client\n this._broadcastChatMessage(\n {\n body: \"No response was generated by the agent.\",\n done: true,\n id: data.id,\n type: MessageType.CF_AGENT_USE_CHAT_RESPONSE\n },\n [connection.id]\n );\n }\n });\n }\n if (data.type === MessageType.CF_AGENT_CHAT_CLEAR) {\n this._destroyAbortControllers();\n this.sql`delete from cf_ai_chat_agent_messages`;\n this.messages = [];\n this._broadcastChatMessage(\n {\n type: MessageType.CF_AGENT_CHAT_CLEAR\n },\n [connection.id]\n );\n } else if (data.type === MessageType.CF_AGENT_CHAT_MESSAGES) {\n // replace the messages with the new ones\n await this.persistMessages(data.messages, [connection.id]);\n } else if (data.type === MessageType.CF_AGENT_CHAT_REQUEST_CANCEL) {\n // propagate an abort signal for the associated request\n this._cancelChatRequest(data.id);\n }\n }\n }\n\n override async onRequest(request: Request): Promise<Response> {\n return this._tryCatchChat(() => {\n const url = new URL(request.url);\n if (url.pathname.endsWith(\"/get-messages\")) {\n const messages = (\n this.sql`select * from cf_ai_chat_agent_messages` || []\n ).map((row) => {\n return JSON.parse(row.message as string);\n });\n return Response.json(messages);\n }\n return super.onRequest(request);\n });\n }\n\n private async _tryCatchChat<T>(fn: () => T | Promise<T>) {\n try {\n return await fn();\n } catch (e) {\n throw this.onError(e);\n }\n }\n\n private async _drainStream(stream: ReadableStream<Uint8Array>) {\n const reader = stream.getReader();\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n decoder.decode(value);\n }\n } finally {\n reader.releaseLock();\n }\n }\n\n /**\n * Handle incoming chat messages and generate a response\n * @param onFinish Callback to be called when the response is finished\n * @param options.signal A signal to pass to any child requests which can be used to cancel them\n * @returns Response to send to the client or undefined\n */\n async onChatMessage(\n // biome-ignore lint/correctness/noUnusedFunctionParameters: overridden later\n onFinish: StreamTextOnFinishCallback<ToolSet>,\n // biome-ignore lint/correctness/noUnusedFunctionParameters: overridden later\n options?: { abortSignal: AbortSignal | undefined }\n ): Promise<Response | undefined> {\n throw new Error(\n \"recieved a chat message, override onChatMessage and return a Response to send to the client\"\n );\n }\n\n /**\n * Save messages on the server side and trigger AI response\n * @param messages Chat messages to save\n */\n async saveMessages(messages: ChatMessage[]) {\n await this.persistMessages(messages);\n const response = await this.onChatMessage(async ({ response }) => {\n const finalMessages = appendResponseMessages({\n messages,\n responseMessages: response.messages\n });\n\n await this.persistMessages(finalMessages, []);\n });\n if (response?.body) {\n // we're just going to drain the body\n await this._drainStream(response.body!);\n response.body.cancel();\n }\n }\n\n async persistMessages(\n messages: ChatMessage[],\n excludeBroadcastIds: string[] = []\n ) {\n this.sql`delete from cf_ai_chat_agent_messages`;\n for (const message of messages) {\n this.sql`insert into cf_ai_chat_agent_messages (id, message) values (${\n message.id\n },${JSON.stringify(message)})`;\n }\n this.messages = messages;\n this._broadcastChatMessage(\n {\n messages: messages,\n type: MessageType.CF_AGENT_CHAT_MESSAGES\n },\n excludeBroadcastIds\n );\n }\n\n private async _reply(id: string, response: Response) {\n // now take chunks out from dataStreamResponse and send them to the client\n return this._tryCatchChat(async () => {\n if (response.body) {\n await this._drainStream(response.body);\n response.body.cancel();\n }\n\n this._broadcastChatMessage({\n body: \"\",\n done: true,\n id,\n type: MessageType.CF_AGENT_USE_CHAT_RESPONSE\n });\n });\n }\n\n /**\n * For the given message id, look up its associated AbortController\n * If the AbortController does not exist, create and store one in memory\n *\n * returns the AbortSignal associated with the AbortController\n */\n private _getAbortSignal(id: string): AbortSignal | undefined {\n // Defensive check, since we're coercing message types at the moment\n if (typeof id !== \"string\") {\n return undefined;\n }\n\n if (!this._chatMessageAbortControllers.has(id)) {\n this._chatMessageAbortControllers.set(id, new AbortController());\n }\n\n return this._chatMessageAbortControllers.get(id)?.signal;\n }\n\n /**\n * Remove an abort controller from the cache of pending message responses\n */\n private _removeAbortController(id: string) {\n this._chatMessageAbortControllers.delete(id);\n }\n\n /**\n * Propagate an abort signal for any requests associated with the given message id\n */\n private _cancelChatRequest(id: string) {\n if (this._chatMessageAbortControllers.has(id)) {\n const abortController = this._chatMessageAbortControllers.get(id);\n abortController?.abort();\n }\n }\n\n /**\n * Abort all pending requests and clear the cache of AbortControllers\n */\n private _destroyAbortControllers() {\n for (const controller of this._chatMessageAbortControllers.values()) {\n controller?.abort();\n }\n this._chatMessageAbortControllers.clear();\n }\n\n /**\n * When the DO is destroyed, cancel all pending requests\n */\n async destroy() {\n this._destroyAbortControllers();\n await super.destroy();\n }\n}\n"],"mappings":";;;;;;;;;AAKA,SAAS,8BAA8B;AAQvC,IAAM,UAAU,IAAI,YAAY;AAMzB,IAAM,cAAN,cAA0D,MAG/D;AAAA,EAQA,YAAY,KAAmB,KAAU;AACvC,UAAM,KAAK,GAAG;AACd,SAAK;AAAA;AAAA;AAAA;AAAA;AAKL,SAAK,YACH,KAAK,gDAAgD,CAAC,GACtD,IAAI,CAAC,QAAQ;AACb,aAAO,KAAK,MAAM,IAAI,OAAiB;AAAA,IACzC,CAAC;AAED,SAAK,+BAA+B,oBAAI,IAAI;AAAA,EAC9C;AAAA,EAEQ,sBAAsB,SAA0B,SAAoB;AAC1E,SAAK,UAAU,KAAK,UAAU,OAAO,GAAG,OAAO;AAAA,EACjD;AAAA,EAEA,MAAe,UAAU,YAAwB,SAAoB;AACnE,QAAI,OAAO,YAAY,UAAU;AAC/B,UAAI;AACJ,UAAI;AACF,eAAO,KAAK,MAAM,OAAO;AAAA,MAC3B,SAAS,QAAQ;AAGf;AAAA,MACF;AACA,UACE,KAAK,wEACL,KAAK,KAAK,WAAW,QACrB;AACA,cAAM;AAAA;AAAA;AAAA;AAAA,UAIJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAKF,IAAI,KAAK;AACT,cAAM,EAAE,SAAS,IAAI,KAAK,MAAM,IAAc;AAC9C,aAAK;AAAA,UACH;AAAA,YACE;AAAA,YACA;AAAA,UACF;AAAA,UACA,CAAC,WAAW,EAAE;AAAA,QAChB;AAEA,cAAM,KAAK,gBAAgB,UAAU,CAAC,WAAW,EAAE,CAAC;AAEpD,aAAK,eAAe;AAAA,UAClB;AAAA,YACE,gBAAgB;AAAA,YAChB,IAAI,KAAK;AAAA,YACT,SAAS,CAAC;AAAA,YACV,WAAW,KAAK,IAAI;AAAA,YACpB,MAAM;AAAA,UACR;AAAA,UACA,KAAK;AAAA,QACP;AAEA,cAAM,gBAAgB,KAAK;AAC3B,cAAM,cAAc,KAAK,gBAAgB,aAAa;AAEtD,eAAO,KAAK,cAAc,YAAY;AACpC,gBAAM,WAAW,MAAM,KAAK;AAAA,YAC1B,OAAO,EAAE,UAAAA,UAAS,MAAM;AACtB,oBAAM,gBAAgB,uBAAuB;AAAA,gBAC3C;AAAA,gBACA,kBAAkBA,UAAS;AAAA,cAC7B,CAAC;AAED,oBAAM,KAAK,gBAAgB,eAAe,CAAC,WAAW,EAAE,CAAC;AACzD,mBAAK,uBAAuB,aAAa;AAEzC,mBAAK,eAAe;AAAA,gBAClB;AAAA,kBACE,gBAAgB;AAAA,kBAChB,IAAI,KAAK;AAAA,kBACT,SAAS,CAAC;AAAA,kBACV,WAAW,KAAK,IAAI;AAAA,kBACpB,MAAM;AAAA,gBACR;AAAA,gBACA,KAAK;AAAA,cACP;AAAA,YACF;AAAA,YACA,cAAc,EAAE,YAAY,IAAI;AAAA,UAClC;AAEA,cAAI,UAAU;AACZ,kBAAM,KAAK,OAAO,KAAK,IAAI,QAAQ;AAAA,UACrC,OAAO;AAEL,oBAAQ;AAAA,cACN,uEAAuE,aAAa;AAAA,YACtF;AAEA,iBAAK;AAAA,cACH;AAAA,gBACE,MAAM;AAAA,gBACN,MAAM;AAAA,gBACN,IAAI,KAAK;AAAA,gBACT;AAAA,cACF;AAAA,cACA,CAAC,WAAW,EAAE;AAAA,YAChB;AAAA,UACF;AAAA,QACF,CAAC;AAAA,MACH;AACA,UAAI,KAAK,0DAA0C;AACjD,aAAK,yBAAyB;AAC9B,aAAK;AACL,aAAK,WAAW,CAAC;AACjB,aAAK;AAAA,UACH;AAAA,YACE;AAAA,UACF;AAAA,UACA,CAAC,WAAW,EAAE;AAAA,QAChB;AAAA,MACF,WAAW,KAAK,gEAA6C;AAE3D,cAAM,KAAK,gBAAgB,KAAK,UAAU,CAAC,WAAW,EAAE,CAAC;AAAA,MAC3D,WAAW,KAAK,4EAAmD;AAEjE,aAAK,mBAAmB,KAAK,EAAE;AAAA,MACjC;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAe,UAAU,SAAqC;AAC5D,WAAO,KAAK,cAAc,MAAM;AAC9B,YAAM,MAAM,IAAI,IAAI,QAAQ,GAAG;AAC/B,UAAI,IAAI,SAAS,SAAS,eAAe,GAAG;AAC1C,cAAM,YACJ,KAAK,gDAAgD,CAAC,GACtD,IAAI,CAAC,QAAQ;AACb,iBAAO,KAAK,MAAM,IAAI,OAAiB;AAAA,QACzC,CAAC;AACD,eAAO,SAAS,KAAK,QAAQ;AAAA,MAC/B;AACA,aAAO,MAAM,UAAU,OAAO;AAAA,IAChC,CAAC;AAAA,EACH;AAAA,EAEA,MAAc,cAAiB,IAA0B;AACvD,QAAI;AACF,aAAO,MAAM,GAAG;AAAA,IAClB,SAAS,GAAG;AACV,YAAM,KAAK,QAAQ,CAAC;AAAA,IACtB;AAAA,EACF;AAAA,EAEA,MAAc,aAAa,QAAoC;AAC7D,UAAM,SAAS,OAAO,UAAU;AAChC,QAAI;AACF,aAAO,MAAM;AACX,cAAM,EAAE,MAAM,MAAM,IAAI,MAAM,OAAO,KAAK;AAC1C,YAAI,KAAM;AACV,gBAAQ,OAAO,KAAK;AAAA,MACtB;AAAA,IACF,UAAE;AACA,aAAO,YAAY;AAAA,IACrB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,cAEJ,UAEA,SAC+B;AAC/B,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,aAAa,UAAyB;AAC1C,UAAM,KAAK,gBAAgB,QAAQ;AACnC,UAAM,WAAW,MAAM,KAAK,cAAc,OAAO,EAAE,UAAAA,UAAS,MAAM;AAChE,YAAM,gBAAgB,uBAAuB;AAAA,QAC3C;AAAA,QACA,kBAAkBA,UAAS;AAAA,MAC7B,CAAC;AAED,YAAM,KAAK,gBAAgB,eAAe,CAAC,CAAC;AAAA,IAC9C,CAAC;AACD,QAAI,UAAU,MAAM;AAElB,YAAM,KAAK,aAAa,SAAS,IAAK;AACtC,eAAS,KAAK,OAAO;AAAA,IACvB;AAAA,EACF;AAAA,EAEA,MAAM,gBACJ,UACA,sBAAgC,CAAC,GACjC;AACA,SAAK;AACL,eAAW,WAAW,UAAU;AAC9B,WAAK,kEACH,QAAQ,EACV,IAAI,KAAK,UAAU,OAAO,CAAC;AAAA,IAC7B;AACA,SAAK,WAAW;AAChB,SAAK;AAAA,MACH;AAAA,QACE;AAAA,QACA;AAAA,MACF;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAc,OAAO,IAAY,UAAoB;AAEnD,WAAO,KAAK,cAAc,YAAY;AACpC,UAAI,SAAS,MAAM;AACjB,cAAM,KAAK,aAAa,SAAS,IAAI;AACrC,iBAAS,KAAK,OAAO;AAAA,MACvB;AAEA,WAAK,sBAAsB;AAAA,QACzB,MAAM;AAAA,QACN,MAAM;AAAA,QACN;AAAA,QACA;AAAA,MACF,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQQ,gBAAgB,IAAqC;AAE3D,QAAI,OAAO,OAAO,UAAU;AAC1B,aAAO;AAAA,IACT;AAEA,QAAI,CAAC,KAAK,6BAA6B,IAAI,EAAE,GAAG;AAC9C,WAAK,6BAA6B,IAAI,IAAI,IAAI,gBAAgB,CAAC;AAAA,IACjE;AAEA,WAAO,KAAK,6BAA6B,IAAI,EAAE,GAAG;AAAA,EACpD;AAAA;AAAA;AAAA;AAAA,EAKQ,uBAAuB,IAAY;AACzC,SAAK,6BAA6B,OAAO,EAAE;AAAA,EAC7C;AAAA;AAAA;AAAA;AAAA,EAKQ,mBAAmB,IAAY;AACrC,QAAI,KAAK,6BAA6B,IAAI,EAAE,GAAG;AAC7C,YAAM,kBAAkB,KAAK,6BAA6B,IAAI,EAAE;AAChE,uBAAiB,MAAM;AAAA,IACzB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,2BAA2B;AACjC,eAAW,cAAc,KAAK,6BAA6B,OAAO,GAAG;AACnE,kBAAY,MAAM;AAAA,IACpB;AACA,SAAK,6BAA6B,MAAM;AAAA,EAC1C;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,UAAU;AACd,SAAK,yBAAyB;AAC9B,UAAM,MAAM,QAAQ;AAAA,EACtB;AACF;","names":["response"]}
@@ -4,7 +4,23 @@ import { useChat } from "@ai-sdk/react";
4
4
  import { useAgent } from "./react.js";
5
5
  import "partysocket";
6
6
  import "partysocket/react";
7
+ import "./index.js";
8
+ import "cloudflare:workers";
9
+ import "@modelcontextprotocol/sdk/client/index.js";
10
+ import "@modelcontextprotocol/sdk/types.js";
11
+ import "partyserver";
12
+ import "./client-DgyzBU_8.js";
13
+ import "zod";
14
+ import "@modelcontextprotocol/sdk/shared/protocol.js";
15
+ import "@modelcontextprotocol/sdk/client/sse.js";
16
+ import "@modelcontextprotocol/sdk/client/streamableHttp.js";
17
+ import "./mcp/do-oauth-client-provider.js";
18
+ import "@modelcontextprotocol/sdk/client/auth.js";
19
+ import "@modelcontextprotocol/sdk/shared/auth.js";
20
+ import "./observability/index.js";
21
+ import "./ai-types.js";
7
22
  import "./client.js";
23
+ import "./serializable.js";
8
24
 
9
25
  type GetInitialMessagesOptions = {
10
26
  agent: string;
@@ -33,15 +49,15 @@ type UseAgentChatOptions<State> = Omit<
33
49
  declare function useAgentChat<State = unknown>(
34
50
  options: UseAgentChatOptions<State>
35
51
  ): {
52
+ /**
53
+ * Clear chat history on both client and Agent
54
+ */
55
+ clearHistory: () => void;
36
56
  /**
37
57
  * Set the chat messages and synchronize with the Agent
38
58
  * @param messages New messages to set
39
59
  */
40
60
  setMessages: (messages: Message[]) => void;
41
- /**
42
- * Clear chat history on both client and Agent
43
- */
44
- clearHistory: () => void;
45
61
  messages: ai.UIMessage[];
46
62
  error: undefined | Error;
47
63
  append: (
@@ -52,6 +68,7 @@ declare function useAgentChat<State = unknown>(
52
68
  chatRequestOptions?: ai.ChatRequestOptions
53
69
  ) => Promise<string | null | undefined>;
54
70
  stop: () => void;
71
+ experimental_resume: () => void;
55
72
  input: string;
56
73
  setInput: React.Dispatch<React.SetStateAction<string>>;
57
74
  handleInputChange: (
@@ -78,7 +95,7 @@ declare function useAgentChat<State = unknown>(
78
95
  id: string;
79
96
  addToolResult: ({
80
97
  toolCallId,
81
- result,
98
+ result
82
99
  }: {
83
100
  toolCallId: string;
84
101
  result: any;
package/dist/ai-react.js CHANGED
@@ -1,14 +1,15 @@
1
- import "./chunk-HMLY7DHA.js";
1
+ import "./chunk-EEKLJYON.js";
2
2
 
3
3
  // src/ai-react.tsx
4
4
  import { useChat } from "@ai-sdk/react";
5
- import { useEffect, use } from "react";
5
+ import { nanoid } from "nanoid";
6
+ import { use, useEffect } from "react";
6
7
  var requestCache = /* @__PURE__ */ new Map();
7
8
  function useAgentChat(options) {
8
9
  const { agent, getInitialMessages, ...rest } = options;
9
10
  const agentUrl = new URL(
10
11
  `${// @ts-expect-error we're using a protected _url property that includes query params
11
- agent._url.replace("ws://", "http://").replace("wss://", "https://")}`
12
+ (agent._url || agent._pkurl)?.replace("ws://", "http://").replace("wss://", "https://")}`
12
13
  );
13
14
  agentUrl.searchParams.delete("_pk");
14
15
  const agentUrlString = agentUrl.toString();
@@ -18,8 +19,8 @@ function useAgentChat(options) {
18
19
  const getMessagesUrl = new URL(url);
19
20
  getMessagesUrl.pathname += "/get-messages";
20
21
  const response = await fetch(getMessagesUrl.toString(), {
21
- headers: options.headers,
22
- credentials: options.credentials
22
+ credentials: options.credentials,
23
+ headers: options.headers
23
24
  });
24
25
  return response.json();
25
26
  }
@@ -32,18 +33,23 @@ function useAgentChat(options) {
32
33
  requestCache.set(agentUrlString, promise);
33
34
  return promise;
34
35
  }
35
- const initialMessages = getInitialMessages !== null ? use(
36
- doGetInitialMessages({
37
- agent: agent.agent,
38
- name: agent.name,
39
- url: agentUrlString
40
- })
41
- ) : rest.initialMessages;
36
+ const initialMessagesPromise = getInitialMessages === null ? null : doGetInitialMessages({
37
+ agent: agent.agent,
38
+ name: agent.name,
39
+ url: agentUrlString
40
+ });
41
+ const initialMessages = initialMessagesPromise ? use(initialMessagesPromise) : rest.initialMessages ?? [];
42
42
  useEffect(() => {
43
+ if (!initialMessagesPromise) {
44
+ return;
45
+ }
46
+ requestCache.set(agentUrlString, initialMessagesPromise);
43
47
  return () => {
44
- requestCache.delete(agentUrlString);
48
+ if (requestCache.get(agentUrlString) === initialMessagesPromise) {
49
+ requestCache.delete(agentUrlString);
50
+ }
45
51
  };
46
- }, [agentUrlString]);
52
+ }, [agentUrlString, initialMessagesPromise]);
47
53
  async function aiFetch(request, options2 = {}) {
48
54
  const {
49
55
  method,
@@ -60,10 +66,17 @@ function useAgentChat(options) {
60
66
  window
61
67
  // dispatcher, duplex
62
68
  } = options2;
63
- const id = crypto.randomUUID();
69
+ const id = nanoid(8);
64
70
  const abortController = new AbortController();
65
71
  signal?.addEventListener("abort", () => {
72
+ agent.send(
73
+ JSON.stringify({
74
+ id,
75
+ type: "cf_agent_chat_request_cancel" /* CF_AGENT_CHAT_REQUEST_CANCEL */
76
+ })
77
+ );
66
78
  abortController.abort();
79
+ controller.close();
67
80
  });
68
81
  agent.addEventListener(
69
82
  "message",
@@ -71,10 +84,10 @@ function useAgentChat(options) {
71
84
  let data;
72
85
  try {
73
86
  data = JSON.parse(event.data);
74
- } catch (error) {
87
+ } catch (_error) {
75
88
  return;
76
89
  }
77
- if (data.type === "cf_agent_use_chat_response") {
90
+ if (data.type === "cf_agent_use_chat_response" /* CF_AGENT_USE_CHAT_RESPONSE */) {
78
91
  if (data.id === id) {
79
92
  controller.enqueue(new TextEncoder().encode(data.body));
80
93
  if (data.done) {
@@ -94,32 +107,32 @@ function useAgentChat(options) {
94
107
  });
95
108
  agent.send(
96
109
  JSON.stringify({
97
- type: "cf_agent_use_chat_request",
98
110
  id,
99
- url: request.toString(),
100
111
  init: {
101
- method,
102
- keepalive,
103
- headers,
104
112
  body,
105
- redirect,
106
- integrity,
107
113
  credentials,
114
+ headers,
115
+ integrity,
116
+ keepalive,
117
+ method,
108
118
  mode,
119
+ redirect,
109
120
  referrer,
110
121
  referrerPolicy,
111
122
  window
112
123
  // dispatcher,
113
124
  // duplex
114
- }
125
+ },
126
+ type: "cf_agent_use_chat_request" /* CF_AGENT_USE_CHAT_REQUEST */,
127
+ url: request.toString()
115
128
  })
116
129
  );
117
130
  return new Response(stream);
118
131
  }
119
132
  const useChatHelpers = useChat({
133
+ fetch: aiFetch,
120
134
  initialMessages,
121
135
  sendExtraMessageFields: true,
122
- fetch: aiFetch,
123
136
  ...rest
124
137
  });
125
138
  useEffect(() => {
@@ -130,10 +143,10 @@ function useAgentChat(options) {
130
143
  let data;
131
144
  try {
132
145
  data = JSON.parse(event.data);
133
- } catch (error) {
146
+ } catch (_error) {
134
147
  return;
135
148
  }
136
- if (data.type === "cf_agent_chat_clear") {
149
+ if (data.type === "cf_agent_chat_clear" /* CF_AGENT_CHAT_CLEAR */) {
137
150
  useChatHelpers.setMessages([]);
138
151
  }
139
152
  }
@@ -144,10 +157,10 @@ function useAgentChat(options) {
144
157
  let data;
145
158
  try {
146
159
  data = JSON.parse(event.data);
147
- } catch (error) {
160
+ } catch (_error) {
148
161
  return;
149
162
  }
150
- if (data.type === "cf_agent_chat_messages") {
163
+ if (data.type === "cf_agent_chat_messages" /* CF_AGENT_CHAT_MESSAGES */) {
151
164
  useChatHelpers.setMessages(data.messages);
152
165
  }
153
166
  }
@@ -157,34 +170,30 @@ function useAgentChat(options) {
157
170
  agent.removeEventListener("message", onClearHistory);
158
171
  agent.removeEventListener("message", onMessages);
159
172
  };
160
- }, [
161
- agent.addEventListener,
162
- agent.removeEventListener,
163
- useChatHelpers.setMessages
164
- ]);
173
+ }, [agent, useChatHelpers.setMessages]);
165
174
  return {
166
175
  ...useChatHelpers,
167
176
  /**
168
- * Set the chat messages and synchronize with the Agent
169
- * @param messages New messages to set
177
+ * Clear chat history on both client and Agent
170
178
  */
171
- setMessages: (messages) => {
172
- useChatHelpers.setMessages(messages);
179
+ clearHistory: () => {
180
+ useChatHelpers.setMessages([]);
173
181
  agent.send(
174
182
  JSON.stringify({
175
- type: "cf_agent_chat_messages",
176
- messages
183
+ type: "cf_agent_chat_clear" /* CF_AGENT_CHAT_CLEAR */
177
184
  })
178
185
  );
179
186
  },
180
187
  /**
181
- * Clear chat history on both client and Agent
188
+ * Set the chat messages and synchronize with the Agent
189
+ * @param messages New messages to set
182
190
  */
183
- clearHistory: () => {
184
- useChatHelpers.setMessages([]);
191
+ setMessages: (messages) => {
192
+ useChatHelpers.setMessages(messages);
185
193
  agent.send(
186
194
  JSON.stringify({
187
- type: "cf_agent_chat_clear"
195
+ messages,
196
+ type: "cf_agent_chat_messages" /* CF_AGENT_CHAT_MESSAGES */
188
197
  })
189
198
  );
190
199
  }