agents 0.0.0-f6c26e4 → 0.0.0-f7bd395

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 (50) hide show
  1. package/README.md +136 -6
  2. package/dist/ai-chat-agent.d.ts +12 -9
  3. package/dist/ai-chat-agent.js +142 -59
  4. package/dist/ai-chat-agent.js.map +1 -1
  5. package/dist/ai-chat-v5-migration.d.ts +152 -0
  6. package/dist/ai-chat-v5-migration.js +19 -0
  7. package/dist/ai-chat-v5-migration.js.map +1 -0
  8. package/dist/ai-react.d.ts +62 -71
  9. package/dist/ai-react.js +144 -37
  10. package/dist/ai-react.js.map +1 -1
  11. package/dist/ai-types.d.ts +36 -19
  12. package/dist/ai-types.js +6 -0
  13. package/dist/chunk-AVYJQSLW.js +17 -0
  14. package/dist/chunk-AVYJQSLW.js.map +1 -0
  15. package/dist/{chunk-5YIRLLUX.js → chunk-IJPBZOSS.js} +137 -105
  16. package/dist/chunk-IJPBZOSS.js.map +1 -0
  17. package/dist/{chunk-PVQZBKN7.js → chunk-LL2AFX7V.js} +5 -2
  18. package/dist/chunk-LL2AFX7V.js.map +1 -0
  19. package/dist/{chunk-KUH345EY.js → chunk-QEVM4BVL.js} +5 -5
  20. package/dist/chunk-QEVM4BVL.js.map +1 -0
  21. package/dist/chunk-UJVEAURM.js +150 -0
  22. package/dist/chunk-UJVEAURM.js.map +1 -0
  23. package/dist/{chunk-MW5BQ2FW.js → chunk-VYENMKFS.js} +163 -20
  24. package/dist/chunk-VYENMKFS.js.map +1 -0
  25. package/dist/client-CcIORE73.d.ts +4607 -0
  26. package/dist/client.js +2 -1
  27. package/dist/index.d.ts +557 -32
  28. package/dist/index.js +7 -4
  29. package/dist/mcp/client.d.ts +9 -1053
  30. package/dist/mcp/client.js +1 -1
  31. package/dist/mcp/do-oauth-client-provider.d.ts +1 -0
  32. package/dist/mcp/do-oauth-client-provider.js +1 -1
  33. package/dist/mcp/index.d.ts +66 -53
  34. package/dist/mcp/index.js +850 -604
  35. package/dist/mcp/index.js.map +1 -1
  36. package/dist/observability/index.d.ts +46 -12
  37. package/dist/observability/index.js +5 -4
  38. package/dist/react.d.ts +7 -3
  39. package/dist/react.js +7 -5
  40. package/dist/react.js.map +1 -1
  41. package/dist/schedule.d.ts +83 -9
  42. package/dist/schedule.js +15 -2
  43. package/dist/schedule.js.map +1 -1
  44. package/package.json +19 -8
  45. package/src/index.ts +192 -123
  46. package/dist/chunk-5YIRLLUX.js.map +0 -1
  47. package/dist/chunk-KUH345EY.js.map +0 -1
  48. package/dist/chunk-MW5BQ2FW.js.map +0 -1
  49. package/dist/chunk-PVQZBKN7.js.map +0 -1
  50. package/dist/index-BIJvkfYt.d.ts +0 -614
package/src/index.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import type { env } from "cloudflare:workers";
1
2
  import { AsyncLocalStorage } from "node:async_hooks";
2
3
  import type { Client } from "@modelcontextprotocol/sdk/client/index.js";
3
4
  import type { SSEClientTransportOptions } from "@modelcontextprotocol/sdk/client/sse.js";
@@ -25,6 +26,7 @@ import { MCPClientManager } from "./mcp/client";
25
26
  // import type { MCPClientConnection } from "./mcp/client-connection";
26
27
  import { DurableObjectOAuthClientProvider } from "./mcp/do-oauth-client-provider";
27
28
  import { genericObservability, type Observability } from "./observability";
29
+ import { MessageType } from "./ai-types";
28
30
 
29
31
  export type { Connection, ConnectionContext, WSMessage } from "partyserver";
30
32
 
@@ -42,7 +44,7 @@ export type RPCRequest = {
42
44
  * State update message from client
43
45
  */
44
46
  export type StateUpdateMessage = {
45
- type: "cf_agent_state";
47
+ type: MessageType.CF_AGENT_STATE;
46
48
  state: unknown;
47
49
  };
48
50
 
@@ -50,7 +52,7 @@ export type StateUpdateMessage = {
50
52
  * RPC response message to client
51
53
  */
52
54
  export type RPCResponse = {
53
- type: "rpc";
55
+ type: MessageType.RPC;
54
56
  id: string;
55
57
  } & (
56
58
  | {
@@ -77,7 +79,7 @@ function isRPCRequest(msg: unknown): msg is RPCRequest {
77
79
  typeof msg === "object" &&
78
80
  msg !== null &&
79
81
  "type" in msg &&
80
- msg.type === "rpc" &&
82
+ msg.type === MessageType.RPC &&
81
83
  "id" in msg &&
82
84
  typeof msg.id === "string" &&
83
85
  "method" in msg &&
@@ -95,7 +97,7 @@ function isStateUpdateMessage(msg: unknown): msg is StateUpdateMessage {
95
97
  typeof msg === "object" &&
96
98
  msg !== null &&
97
99
  "type" in msg &&
98
- msg.type === "cf_agent_state" &&
100
+ msg.type === MessageType.CF_AGENT_STATE &&
99
101
  "state" in msg
100
102
  );
101
103
  }
@@ -116,7 +118,7 @@ const callableMetadata = new Map<Function, CallableMetadata>();
116
118
  * Decorator that marks a method as callable by clients
117
119
  * @param metadata Optional metadata about the callable method
118
120
  */
119
- export function unstable_callable(metadata: CallableMetadata = {}) {
121
+ export function callable(metadata: CallableMetadata = {}) {
120
122
  return function callableDecorator<This, Args extends unknown[], Return>(
121
123
  target: (this: This, ...args: Args) => Return,
122
124
  // biome-ignore lint/correctness/noUnusedFunctionParameters: later
@@ -130,6 +132,23 @@ export function unstable_callable(metadata: CallableMetadata = {}) {
130
132
  };
131
133
  }
132
134
 
135
+ let didWarnAboutUnstableCallable = false;
136
+
137
+ /**
138
+ * Decorator that marks a method as callable by clients
139
+ * @deprecated this has been renamed to callable, and unstable_callable will be removed in the next major version
140
+ * @param metadata Optional metadata about the callable method
141
+ */
142
+ export const unstable_callable = (metadata: CallableMetadata = {}) => {
143
+ if (!didWarnAboutUnstableCallable) {
144
+ didWarnAboutUnstableCallable = true;
145
+ console.warn(
146
+ "unstable_callable is deprecated, use callable instead. unstable_callable will be removed in the next major version."
147
+ );
148
+ }
149
+ callable(metadata);
150
+ };
151
+
133
152
  export type QueueItem<T = string> = {
134
153
  id: string;
135
154
  payload: T;
@@ -182,7 +201,7 @@ function getNextCronTime(cron: string) {
182
201
  * MCP Server state update message from server -> Client
183
202
  */
184
203
  export type MCPServerMessage = {
185
- type: "cf_agent_mcp_servers";
204
+ type: MessageType.CF_AGENT_MCP_SERVERS;
186
205
  mcp: MCPServersState;
187
206
  };
188
207
 
@@ -271,7 +290,13 @@ function withAgentContext<T extends (...args: any[]) => any>(
271
290
  method: T
272
291
  ): (this: Agent<unknown, unknown>, ...args: Parameters<T>) => ReturnType<T> {
273
292
  return function (...args: Parameters<T>): ReturnType<T> {
274
- const { connection, request, email } = getCurrentAgent();
293
+ const { connection, request, email, agent } = getCurrentAgent();
294
+
295
+ if (agent === this) {
296
+ // already wrapped, so we can just call the method
297
+ return method.apply(this, args);
298
+ }
299
+ // not wrapped, so we need to wrap it
275
300
  return agentContext.run({ agent: this, connection, request, email }, () => {
276
301
  return method.apply(this, args);
277
302
  });
@@ -283,7 +308,11 @@ function withAgentContext<T extends (...args: any[]) => any>(
283
308
  * @template Env Environment type containing bindings
284
309
  * @template State State type to store within the Agent
285
310
  */
286
- export class Agent<Env, State = unknown> extends Server<Env> {
311
+ export class Agent<
312
+ Env = typeof env,
313
+ State = unknown,
314
+ Props extends Record<string, unknown> = Record<string, unknown>
315
+ > extends Server<Env, Props> {
287
316
  private _state = DEFAULT_STATE as State;
288
317
 
289
318
  private _ParentClass: typeof Agent<Env, State> =
@@ -446,7 +475,7 @@ export class Agent<Env, State = unknown> extends Server<Env> {
446
475
  this.broadcast(
447
476
  JSON.stringify({
448
477
  mcp: this.getMcpServers(),
449
- type: "cf_agent_mcp_servers"
478
+ type: MessageType.CF_AGENT_MCP_SERVERS
450
479
  })
451
480
  );
452
481
 
@@ -515,10 +544,8 @@ export class Agent<Env, State = unknown> extends Server<Env> {
515
544
  displayMessage: `RPC call to ${method}`,
516
545
  id: nanoid(),
517
546
  payload: {
518
- args,
519
547
  method,
520
- streaming: metadata?.streaming,
521
- success: true
548
+ streaming: metadata?.streaming
522
549
  },
523
550
  timestamp: Date.now(),
524
551
  type: "rpc"
@@ -531,7 +558,7 @@ export class Agent<Env, State = unknown> extends Server<Env> {
531
558
  id,
532
559
  result,
533
560
  success: true,
534
- type: "rpc"
561
+ type: MessageType.RPC
535
562
  };
536
563
  connection.send(JSON.stringify(response));
537
564
  } catch (e) {
@@ -541,7 +568,7 @@ export class Agent<Env, State = unknown> extends Server<Env> {
541
568
  e instanceof Error ? e.message : "Unknown error occurred",
542
569
  id: parsed.id,
543
570
  success: false,
544
- type: "rpc"
571
+ type: MessageType.RPC
545
572
  };
546
573
  connection.send(JSON.stringify(response));
547
574
  console.error("RPC error:", e);
@@ -560,44 +587,42 @@ export class Agent<Env, State = unknown> extends Server<Env> {
560
587
  // must fix this
561
588
  return agentContext.run(
562
589
  { agent: this, connection, request: ctx.request, email: undefined },
563
- async () => {
564
- setTimeout(() => {
565
- if (this.state) {
566
- connection.send(
567
- JSON.stringify({
568
- state: this.state,
569
- type: "cf_agent_state"
570
- })
571
- );
572
- }
573
-
590
+ () => {
591
+ if (this.state) {
574
592
  connection.send(
575
593
  JSON.stringify({
576
- mcp: this.getMcpServers(),
577
- type: "cf_agent_mcp_servers"
594
+ state: this.state,
595
+ type: MessageType.CF_AGENT_STATE
578
596
  })
579
597
  );
598
+ }
580
599
 
581
- this.observability?.emit(
582
- {
583
- displayMessage: "Connection established",
584
- id: nanoid(),
585
- payload: {
586
- connectionId: connection.id
587
- },
588
- timestamp: Date.now(),
589
- type: "connect"
600
+ connection.send(
601
+ JSON.stringify({
602
+ mcp: this.getMcpServers(),
603
+ type: MessageType.CF_AGENT_MCP_SERVERS
604
+ })
605
+ );
606
+
607
+ this.observability?.emit(
608
+ {
609
+ displayMessage: "Connection established",
610
+ id: nanoid(),
611
+ payload: {
612
+ connectionId: connection.id
590
613
  },
591
- this.ctx
592
- );
593
- return this._tryCatch(() => _onConnect(connection, ctx));
594
- }, 20);
614
+ timestamp: Date.now(),
615
+ type: "connect"
616
+ },
617
+ this.ctx
618
+ );
619
+ return this._tryCatch(() => _onConnect(connection, ctx));
595
620
  }
596
621
  );
597
622
  };
598
623
 
599
624
  const _onStart = this.onStart.bind(this);
600
- this.onStart = async () => {
625
+ this.onStart = async (props?: Props) => {
601
626
  return agentContext.run(
602
627
  {
603
628
  agent: this,
@@ -606,15 +631,22 @@ export class Agent<Env, State = unknown> extends Server<Env> {
606
631
  email: undefined
607
632
  },
608
633
  async () => {
609
- const servers = this.sql<MCPServerRow>`
634
+ await this._tryCatch(() => {
635
+ const servers = this.sql<MCPServerRow>`
610
636
  SELECT id, name, server_url, client_id, auth_url, callback_url, server_options FROM cf_agents_mcp_servers;
611
637
  `;
612
638
 
613
- // from DO storage, reconnect to all servers not currently in the oauth flow using our saved auth information
614
- if (servers && Array.isArray(servers) && servers.length > 0) {
615
- Promise.allSettled(
616
- servers.map((server) => {
617
- return this._connectToMcpServerInternal(
639
+ this.broadcast(
640
+ JSON.stringify({
641
+ mcp: this.getMcpServers(),
642
+ type: MessageType.CF_AGENT_MCP_SERVERS
643
+ })
644
+ );
645
+
646
+ // from DO storage, reconnect to all servers not currently in the oauth flow using our saved auth information
647
+ if (servers && Array.isArray(servers) && servers.length > 0) {
648
+ servers.forEach((server) => {
649
+ this._connectToMcpServerInternal(
618
650
  server.name,
619
651
  server.server_url,
620
652
  server.callback_url,
@@ -625,18 +657,33 @@ export class Agent<Env, State = unknown> extends Server<Env> {
625
657
  id: server.id,
626
658
  oauthClientId: server.client_id ?? undefined
627
659
  }
628
- );
629
- })
630
- ).then((_results) => {
631
- this.broadcast(
632
- JSON.stringify({
633
- mcp: this.getMcpServers(),
634
- type: "cf_agent_mcp_servers"
635
- })
636
- );
637
- });
638
- }
639
- await this._tryCatch(() => _onStart());
660
+ )
661
+ .then(() => {
662
+ // Broadcast updated MCP servers state after each server connects
663
+ this.broadcast(
664
+ JSON.stringify({
665
+ mcp: this.getMcpServers(),
666
+ type: MessageType.CF_AGENT_MCP_SERVERS
667
+ })
668
+ );
669
+ })
670
+ .catch((error) => {
671
+ console.error(
672
+ `Error connecting to MCP server: ${server.name} (${server.server_url})`,
673
+ error
674
+ );
675
+ // Still broadcast even if connection fails, so clients know about the failure
676
+ this.broadcast(
677
+ JSON.stringify({
678
+ mcp: this.getMcpServers(),
679
+ type: MessageType.CF_AGENT_MCP_SERVERS
680
+ })
681
+ );
682
+ });
683
+ });
684
+ }
685
+ return _onStart(props);
686
+ });
640
687
  }
641
688
  );
642
689
  };
@@ -646,7 +693,6 @@ export class Agent<Env, State = unknown> extends Server<Env> {
646
693
  state: State,
647
694
  source: Connection | "server" = "server"
648
695
  ) {
649
- const previousState = this._state;
650
696
  this._state = state;
651
697
  this.sql`
652
698
  INSERT OR REPLACE INTO cf_agents_state (id, state)
@@ -659,7 +705,7 @@ export class Agent<Env, State = unknown> extends Server<Env> {
659
705
  this.broadcast(
660
706
  JSON.stringify({
661
707
  state: state,
662
- type: "cf_agent_state"
708
+ type: MessageType.CF_AGENT_STATE
663
709
  }),
664
710
  source !== "server" ? [source.id] : []
665
711
  );
@@ -672,10 +718,7 @@ export class Agent<Env, State = unknown> extends Server<Env> {
672
718
  {
673
719
  displayMessage: "State updated",
674
720
  id: nanoid(),
675
- payload: {
676
- previousState,
677
- state
678
- },
721
+ payload: {},
679
722
  timestamp: Date.now(),
680
723
  type: "state:update"
681
724
  },
@@ -815,41 +858,37 @@ export class Agent<Env, State = unknown> extends Server<Env> {
815
858
  while (proto && proto !== Object.prototype && depth < 10) {
816
859
  const methodNames = Object.getOwnPropertyNames(proto);
817
860
  for (const methodName of methodNames) {
818
- // Skip if it's a private method or not a function
861
+ const descriptor = Object.getOwnPropertyDescriptor(proto, methodName);
862
+
863
+ // Skip if it's a private method, a base method, a getter, or not a function,
819
864
  if (
820
865
  baseMethods.has(methodName) ||
821
866
  methodName.startsWith("_") ||
822
- typeof this[methodName as keyof this] !== "function"
867
+ !descriptor ||
868
+ !!descriptor.get ||
869
+ typeof descriptor.value !== "function"
823
870
  ) {
824
871
  continue;
825
872
  }
826
- // If the method doesn't exist in base prototypes, it's a custom method
827
- if (!baseMethods.has(methodName)) {
828
- const descriptor = Object.getOwnPropertyDescriptor(proto, methodName);
829
- if (descriptor && typeof descriptor.value === "function") {
830
- // Wrap the custom method with context
831
-
832
- const wrappedFunction = withAgentContext(
833
- // biome-ignore lint/suspicious/noExplicitAny: I can't typescript
834
- this[methodName as keyof this] as (...args: any[]) => any
835
- // biome-ignore lint/suspicious/noExplicitAny: I can't typescript
836
- ) as any;
837
-
838
- // if the method is callable, copy the metadata from the original method
839
- if (this._isCallable(methodName)) {
840
- callableMetadata.set(
841
- wrappedFunction,
842
- callableMetadata.get(
843
- this[methodName as keyof this] as Function
844
- )!
845
- );
846
- }
847
873
 
848
- // set the wrapped function on the prototype
849
- this.constructor.prototype[methodName as keyof this] =
850
- wrappedFunction;
851
- }
874
+ // Now, methodName is confirmed to be a custom method/function
875
+ // Wrap the custom method with context
876
+ const wrappedFunction = withAgentContext(
877
+ // biome-ignore lint/suspicious/noExplicitAny: I can't typescript
878
+ this[methodName as keyof this] as (...args: any[]) => any
879
+ // biome-ignore lint/suspicious/noExplicitAny: I can't typescript
880
+ ) as any;
881
+
882
+ // if the method is callable, copy the metadata from the original method
883
+ if (this._isCallable(methodName)) {
884
+ callableMetadata.set(
885
+ wrappedFunction,
886
+ callableMetadata.get(this[methodName as keyof this] as Function)!
887
+ );
852
888
  }
889
+
890
+ // set the wrapped function on the prototype
891
+ this.constructor.prototype[methodName as keyof this] = wrappedFunction;
853
892
  }
854
893
 
855
894
  proto = Object.getPrototypeOf(proto);
@@ -927,7 +966,6 @@ export class Agent<Env, State = unknown> extends Server<Env> {
927
966
  }
928
967
  this._flushingQueue = true;
929
968
  while (true) {
930
- const executed: string[] = [];
931
969
  const result = this.sql<QueueItem<string>>`
932
970
  SELECT * FROM cf_agents_queues
933
971
  ORDER BY created_at ASC
@@ -959,13 +997,10 @@ export class Agent<Env, State = unknown> extends Server<Env> {
959
997
  queueItem: QueueItem<string>
960
998
  ) => Promise<void>
961
999
  ).bind(this)(JSON.parse(row.payload as string), row);
962
- executed.push(row.id);
1000
+ await this.dequeue(row.id);
963
1001
  }
964
1002
  );
965
1003
  }
966
- for (const id of executed) {
967
- await this.dequeue(id);
968
- }
969
1004
  }
970
1005
  this._flushingQueue = false;
971
1006
  }
@@ -1040,7 +1075,10 @@ export class Agent<Env, State = unknown> extends Server<Env> {
1040
1075
  {
1041
1076
  displayMessage: `Schedule ${schedule.id} created`,
1042
1077
  id: nanoid(),
1043
- payload: schedule,
1078
+ payload: {
1079
+ callback: callback as string,
1080
+ id: id
1081
+ },
1044
1082
  timestamp: Date.now(),
1045
1083
  type: "schedule:create"
1046
1084
  },
@@ -1210,7 +1248,10 @@ export class Agent<Env, State = unknown> extends Server<Env> {
1210
1248
  {
1211
1249
  displayMessage: `Schedule ${id} cancelled`,
1212
1250
  id: nanoid(),
1213
- payload: schedule,
1251
+ payload: {
1252
+ callback: schedule.callback,
1253
+ id: schedule.id
1254
+ },
1214
1255
  timestamp: Date.now(),
1215
1256
  type: "schedule:cancel"
1216
1257
  },
@@ -1226,9 +1267,9 @@ export class Agent<Env, State = unknown> extends Server<Env> {
1226
1267
  private async _scheduleNextAlarm() {
1227
1268
  // Find the next schedule that needs to be executed
1228
1269
  const result = this.sql`
1229
- SELECT time FROM cf_agents_schedules
1270
+ SELECT time FROM cf_agents_schedules
1230
1271
  WHERE time > ${Math.floor(Date.now() / 1000)}
1231
- ORDER BY time ASC
1272
+ ORDER BY time ASC
1232
1273
  LIMIT 1
1233
1274
  `;
1234
1275
  if (!result) return;
@@ -1275,7 +1316,10 @@ export class Agent<Env, State = unknown> extends Server<Env> {
1275
1316
  {
1276
1317
  displayMessage: `Schedule ${row.id} executed`,
1277
1318
  id: nanoid(),
1278
- payload: row,
1319
+ payload: {
1320
+ callback: row.callback,
1321
+ id: row.id
1322
+ },
1279
1323
  timestamp: Date.now(),
1280
1324
  type: "schedule:execute"
1281
1325
  },
@@ -1395,7 +1439,7 @@ export class Agent<Env, State = unknown> extends Server<Env> {
1395
1439
  this.broadcast(
1396
1440
  JSON.stringify({
1397
1441
  mcp: this.getMcpServers(),
1398
- type: "cf_agent_mcp_servers"
1442
+ type: MessageType.CF_AGENT_MCP_SERVERS
1399
1443
  })
1400
1444
  );
1401
1445
 
@@ -1484,7 +1528,7 @@ export class Agent<Env, State = unknown> extends Server<Env> {
1484
1528
  this.broadcast(
1485
1529
  JSON.stringify({
1486
1530
  mcp: this.getMcpServers(),
1487
- type: "cf_agent_mcp_servers"
1531
+ type: MessageType.CF_AGENT_MCP_SERVERS
1488
1532
  })
1489
1533
  );
1490
1534
  }
@@ -1696,6 +1740,13 @@ export type EmailRoutingOptions<Env> = AgentOptions<Env> & {
1696
1740
  resolver: EmailResolver<Env>;
1697
1741
  };
1698
1742
 
1743
+ // Cache the agent namespace map for email routing
1744
+ // This maps both kebab-case and original names to namespaces
1745
+ const agentMapCache = new WeakMap<
1746
+ Record<string, unknown>,
1747
+ Record<string, unknown>
1748
+ >();
1749
+
1699
1750
  /**
1700
1751
  * Route an email to the appropriate Agent
1701
1752
  * @param email The email to route
@@ -1715,28 +1766,41 @@ export async function routeAgentEmail<Env>(
1715
1766
  return;
1716
1767
  }
1717
1768
 
1718
- const namespaceBinding = env[routingInfo.agentName as keyof Env];
1719
- if (!namespaceBinding) {
1720
- throw new Error(
1721
- `Agent namespace '${routingInfo.agentName}' not found in environment`
1722
- );
1769
+ // Build a map that includes both original names and kebab-case versions
1770
+ if (!agentMapCache.has(env as Record<string, unknown>)) {
1771
+ const map: Record<string, unknown> = {};
1772
+ for (const [key, value] of Object.entries(env as Record<string, unknown>)) {
1773
+ if (
1774
+ value &&
1775
+ typeof value === "object" &&
1776
+ "idFromName" in value &&
1777
+ typeof value.idFromName === "function"
1778
+ ) {
1779
+ // Add both the original name and kebab-case version
1780
+ map[key] = value;
1781
+ map[camelCaseToKebabCase(key)] = value;
1782
+ }
1783
+ }
1784
+ agentMapCache.set(env as Record<string, unknown>, map);
1723
1785
  }
1724
1786
 
1725
- // Type guard to check if this is actually a DurableObjectNamespace (AgentNamespace)
1726
- if (
1727
- typeof namespaceBinding !== "object" ||
1728
- !("idFromName" in namespaceBinding) ||
1729
- typeof namespaceBinding.idFromName !== "function"
1730
- ) {
1787
+ const agentMap = agentMapCache.get(env as Record<string, unknown>)!;
1788
+ const namespace = agentMap[routingInfo.agentName];
1789
+
1790
+ if (!namespace) {
1791
+ // Provide helpful error message listing available agents
1792
+ const availableAgents = Object.keys(agentMap)
1793
+ .filter((key) => !key.includes("-")) // Show only original names, not kebab-case duplicates
1794
+ .join(", ");
1731
1795
  throw new Error(
1732
- `Environment binding '${routingInfo.agentName}' is not an AgentNamespace (found: ${typeof namespaceBinding})`
1796
+ `Agent namespace '${routingInfo.agentName}' not found in environment. Available agents: ${availableAgents}`
1733
1797
  );
1734
1798
  }
1735
1799
 
1736
- // Safe cast after runtime validation
1737
- const namespace = namespaceBinding as unknown as AgentNamespace<Agent<Env>>;
1738
-
1739
- const agent = await getAgentByName(namespace, routingInfo.agentId);
1800
+ const agent = await getAgentByName(
1801
+ namespace as unknown as AgentNamespace<Agent<Env>>,
1802
+ routingInfo.agentId
1803
+ );
1740
1804
 
1741
1805
  // let's make a serialisable version of the email
1742
1806
  const serialisableEmail: AgentEmail = {
@@ -1815,12 +1879,17 @@ export type EmailSendOptions = {
1815
1879
  * @param options Options for Agent creation
1816
1880
  * @returns Promise resolving to an Agent instance stub
1817
1881
  */
1818
- export async function getAgentByName<Env, T extends Agent<Env>>(
1882
+ export async function getAgentByName<
1883
+ Env,
1884
+ T extends Agent<Env>,
1885
+ Props extends Record<string, unknown> = Record<string, unknown>
1886
+ >(
1819
1887
  namespace: AgentNamespace<T>,
1820
1888
  name: string,
1821
1889
  options?: {
1822
1890
  jurisdiction?: DurableObjectJurisdiction;
1823
1891
  locationHint?: DurableObjectLocationHint;
1892
+ props?: Props;
1824
1893
  }
1825
1894
  ) {
1826
1895
  return getServerByName<Env, T>(namespace, name, options);
@@ -1852,7 +1921,7 @@ export class StreamingResponse {
1852
1921
  id: this._id,
1853
1922
  result: chunk,
1854
1923
  success: true,
1855
- type: "rpc"
1924
+ type: MessageType.RPC
1856
1925
  };
1857
1926
  this._connection.send(JSON.stringify(response));
1858
1927
  }
@@ -1871,7 +1940,7 @@ export class StreamingResponse {
1871
1940
  id: this._id,
1872
1941
  result: finalChunk,
1873
1942
  success: true,
1874
- type: "rpc"
1943
+ type: MessageType.RPC
1875
1944
  };
1876
1945
  this._connection.send(JSON.stringify(response));
1877
1946
  }