agents 0.11.3 → 0.11.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +44 -1
- package/dist/browser/ai.js +1 -1
- package/dist/browser/index.js +1 -1
- package/dist/browser/tanstack-ai.js +1 -1
- package/dist/chat/index.d.ts +73 -1
- package/dist/{classPrivateFieldGet2-BVdP0e3Z.js → classPrivateFieldGet2-DAZNVUKb.js} +5 -5
- package/dist/{client-PEDsNnfY.js → client-BYF13FDD.js} +6 -3
- package/dist/{client-PEDsNnfY.js.map → client-BYF13FDD.js.map} +1 -1
- package/dist/client.d.ts +1 -1
- package/dist/client.js +9 -9
- package/dist/client.js.map +1 -1
- package/dist/experimental/memory/session/index.js +3 -3
- package/dist/experimental/memory/session/index.js.map +1 -1
- package/dist/experimental/webmcp.d.ts +212 -0
- package/dist/experimental/webmcp.js +298 -0
- package/dist/experimental/webmcp.js.map +1 -0
- package/dist/{index-D49HdAiY.d.ts → index-DabjI66m.d.ts} +365 -20
- package/dist/index.d.ts +12 -2
- package/dist/index.js +311 -43
- package/dist/index.js.map +1 -1
- package/dist/mcp/client.d.ts +1 -1
- package/dist/mcp/client.js +1 -1
- package/dist/mcp/index.d.ts +1 -1
- package/dist/mcp/index.js +5 -5
- package/dist/mcp/index.js.map +1 -1
- package/dist/react.d.ts +53 -5
- package/dist/react.js +55 -15
- package/dist/react.js.map +1 -1
- package/dist/{retries-JlwH9mnV.d.ts → retries-fLD8cGNf.d.ts} +1 -1
- package/dist/retries.d.ts +1 -1
- package/dist/{shared-BtPEbm_U.js → shared-BovR6hRc.js} +3 -3
- package/dist/{shared-BtPEbm_U.js.map → shared-BovR6hRc.js.map} +1 -1
- package/dist/sub-routing.d.ts +14 -0
- package/dist/sub-routing.js +171 -0
- package/dist/sub-routing.js.map +1 -0
- package/dist/utils.d.ts +21 -1
- package/dist/utils.js +36 -1
- package/dist/utils.js.map +1 -1
- package/dist/workflows.d.ts +1 -1
- package/package.json +13 -19
package/dist/index.js
CHANGED
|
@@ -2,9 +2,10 @@ import { MessageType } from "./types.js";
|
|
|
2
2
|
import { camelCaseToKebabCase } from "./utils.js";
|
|
3
3
|
import { createHeaderBasedEmailResolver, signAgentHeaders } from "./email.js";
|
|
4
4
|
import { __DO_NOT_USE_WILL_BREAK__agentContext } from "./internal_context.js";
|
|
5
|
-
import { i as _classPrivateFieldInitSpec, n as _classPrivateFieldSet2, t as _classPrivateFieldGet2 } from "./classPrivateFieldGet2-
|
|
5
|
+
import { i as _classPrivateFieldInitSpec, n as _classPrivateFieldSet2, t as _classPrivateFieldGet2 } from "./classPrivateFieldGet2-DAZNVUKb.js";
|
|
6
|
+
import { SUB_PREFIX, getSubAgentByName, parseSubAgentPath, routeSubAgentRequest } from "./sub-routing.js";
|
|
6
7
|
import { isErrorRetryable, tryN, validateRetryOptions } from "./retries.js";
|
|
7
|
-
import { o as RPC_DO_PREFIX, r as MCPConnectionState, s as DisposableStore, t as MCPClientManager } from "./client-
|
|
8
|
+
import { o as RPC_DO_PREFIX, r as MCPConnectionState, s as DisposableStore, t as MCPClientManager } from "./client-BYF13FDD.js";
|
|
8
9
|
import { DurableObjectOAuthClientProvider } from "./mcp/do-oauth-client-provider.js";
|
|
9
10
|
import { genericObservability } from "./observability/index.js";
|
|
10
11
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
@@ -19,13 +20,13 @@ let _Symbol$dispose;
|
|
|
19
20
|
* Type guard for RPC request messages
|
|
20
21
|
*/
|
|
21
22
|
function isRPCRequest(msg) {
|
|
22
|
-
return typeof msg === "object" && msg !== null && "type" in msg && msg.type ===
|
|
23
|
+
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);
|
|
23
24
|
}
|
|
24
25
|
/**
|
|
25
26
|
* Type guard for state update messages
|
|
26
27
|
*/
|
|
27
28
|
function isStateUpdateMessage(msg) {
|
|
28
|
-
return typeof msg === "object" && msg !== null && "type" in msg && msg.type ===
|
|
29
|
+
return typeof msg === "object" && msg !== null && "type" in msg && msg.type === "cf_agent_state" && "state" in msg;
|
|
29
30
|
}
|
|
30
31
|
const callableMetadata = /* @__PURE__ */ new WeakMap();
|
|
31
32
|
/**
|
|
@@ -79,6 +80,14 @@ const STATE_ROW_ID = "cf_state_row_id";
|
|
|
79
80
|
const STATE_WAS_CHANGED = "cf_state_was_changed";
|
|
80
81
|
const DEFAULT_STATE = {};
|
|
81
82
|
/**
|
|
83
|
+
* Validate that a stored `parentPath` has the expected shape. Used
|
|
84
|
+
* when restoring from DO storage to guard against corrupted data.
|
|
85
|
+
*/
|
|
86
|
+
function isValidParentPath(value) {
|
|
87
|
+
if (!Array.isArray(value)) return false;
|
|
88
|
+
return value.every((entry) => entry != null && typeof entry === "object" && typeof entry.className === "string" && typeof entry.name === "string");
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
82
91
|
* Internal key used to store the readonly flag in connection state.
|
|
83
92
|
* Prefixed with _cf_ to avoid collision with user state keys.
|
|
84
93
|
*/
|
|
@@ -459,6 +468,7 @@ var Agent = class Agent extends Server {
|
|
|
459
468
|
this._rawStateAccessors = /* @__PURE__ */ new WeakMap();
|
|
460
469
|
this._persistenceHookMode = "none";
|
|
461
470
|
this._isFacet = false;
|
|
471
|
+
this._parentPath = [];
|
|
462
472
|
this._insideOnStart = false;
|
|
463
473
|
this._warnedScheduleInOnStart = /* @__PURE__ */ new Set();
|
|
464
474
|
this._keepAliveRefs = 0;
|
|
@@ -468,6 +478,7 @@ var Agent = class Agent extends Server {
|
|
|
468
478
|
this.initialState = DEFAULT_STATE;
|
|
469
479
|
this.observability = genericObservability;
|
|
470
480
|
this._flushingQueue = false;
|
|
481
|
+
this._subAgentRegistryReady = false;
|
|
471
482
|
if (!wrappedClasses.has(this.constructor)) {
|
|
472
483
|
this._autoWrapCustomMethods();
|
|
473
484
|
wrappedClasses.add(this.constructor);
|
|
@@ -535,7 +546,7 @@ var Agent = class Agent extends Server {
|
|
|
535
546
|
if (isStateUpdateMessage(parsed)) {
|
|
536
547
|
if (this.isConnectionReadonly(connection)) {
|
|
537
548
|
connection.send(JSON.stringify({
|
|
538
|
-
type:
|
|
549
|
+
type: "cf_agent_state_error",
|
|
539
550
|
error: "Connection is readonly"
|
|
540
551
|
}));
|
|
541
552
|
return;
|
|
@@ -545,7 +556,7 @@ var Agent = class Agent extends Server {
|
|
|
545
556
|
} catch (e) {
|
|
546
557
|
console.error("[Agent] State update rejected:", e);
|
|
547
558
|
connection.send(JSON.stringify({
|
|
548
|
-
type:
|
|
559
|
+
type: "cf_agent_state_error",
|
|
549
560
|
error: "State update rejected"
|
|
550
561
|
}));
|
|
551
562
|
}
|
|
@@ -586,7 +597,7 @@ var Agent = class Agent extends Server {
|
|
|
586
597
|
id,
|
|
587
598
|
result,
|
|
588
599
|
success: true,
|
|
589
|
-
type:
|
|
600
|
+
type: "rpc"
|
|
590
601
|
};
|
|
591
602
|
connection.send(JSON.stringify(response));
|
|
592
603
|
} catch (e) {
|
|
@@ -594,7 +605,7 @@ var Agent = class Agent extends Server {
|
|
|
594
605
|
error: e instanceof Error ? e.message : "Unknown error occurred",
|
|
595
606
|
id: parsed.id,
|
|
596
607
|
success: false,
|
|
597
|
-
type:
|
|
608
|
+
type: "rpc"
|
|
598
609
|
};
|
|
599
610
|
connection.send(JSON.stringify(response));
|
|
600
611
|
console.error("RPC error:", e);
|
|
@@ -621,7 +632,7 @@ var Agent = class Agent extends Server {
|
|
|
621
632
|
if (this.shouldSendProtocolMessages(connection, ctx)) {
|
|
622
633
|
if (this._resolvedOptions.sendIdentityOnConnect) {
|
|
623
634
|
const ctor = this.constructor;
|
|
624
|
-
if (ctor.options?.sendIdentityOnConnect === void 0 && !_sendIdentityWarnedClasses.has(ctor)) {
|
|
635
|
+
if (ctor.options?.sendIdentityOnConnect === void 0 && !_sendIdentityWarnedClasses.has(ctor) && !this._isFacet) {
|
|
625
636
|
if (!new URL(ctx.request.url).pathname.includes(this.name)) {
|
|
626
637
|
_sendIdentityWarnedClasses.add(ctor);
|
|
627
638
|
console.warn(`[Agent] ${ctor.name}: sending instance name "${this.name}" to clients via sendIdentityOnConnect (the name is not visible in the URL with custom routing). If this name is sensitive, add \`static options = { sendIdentityOnConnect: false }\` to opt out. Set it to true to silence this message.`);
|
|
@@ -630,16 +641,16 @@ var Agent = class Agent extends Server {
|
|
|
630
641
|
connection.send(JSON.stringify({
|
|
631
642
|
name: this.name,
|
|
632
643
|
agent: camelCaseToKebabCase(this._ParentClass.name),
|
|
633
|
-
type:
|
|
644
|
+
type: "cf_agent_identity"
|
|
634
645
|
}));
|
|
635
646
|
}
|
|
636
647
|
if (this.state) connection.send(JSON.stringify({
|
|
637
648
|
state: this.state,
|
|
638
|
-
type:
|
|
649
|
+
type: "cf_agent_state"
|
|
639
650
|
}));
|
|
640
651
|
connection.send(JSON.stringify({
|
|
641
652
|
mcp: this.getMcpServers(),
|
|
642
|
-
type:
|
|
653
|
+
type: "cf_agent_mcp_servers"
|
|
643
654
|
}));
|
|
644
655
|
} else this._setConnectionNoProtocol(connection);
|
|
645
656
|
this._emit("connect", { connectionId: connection.id });
|
|
@@ -671,6 +682,8 @@ var Agent = class Agent extends Server {
|
|
|
671
682
|
email: void 0
|
|
672
683
|
}, async () => {
|
|
673
684
|
if (await this.ctx.storage.get("cf_agents_is_facet")) this._isFacet = true;
|
|
685
|
+
const storedParentPath = await this.ctx.storage.get("cf_agents_parent_path");
|
|
686
|
+
if (isValidParentPath(storedParentPath)) this._parentPath = storedParentPath;
|
|
674
687
|
await this._tryCatch(async () => {
|
|
675
688
|
await this.mcp.restoreConnectionsFromStorage(this.name);
|
|
676
689
|
await this._restoreRpcMcpServers();
|
|
@@ -718,23 +731,10 @@ var Agent = class Agent extends Server {
|
|
|
718
731
|
* @param excludeIds Additional connection IDs to exclude (e.g. the source)
|
|
719
732
|
*/
|
|
720
733
|
_broadcastProtocol(msg, excludeIds = []) {
|
|
721
|
-
if (this._isFacet) return;
|
|
722
734
|
const exclude = [...excludeIds];
|
|
723
735
|
for (const conn of this.getConnections()) if (!this.isConnectionProtocolEnabled(conn)) exclude.push(conn.id);
|
|
724
736
|
this.broadcast(msg, exclude);
|
|
725
737
|
}
|
|
726
|
-
/**
|
|
727
|
-
* When running as a facet, the parent DO owns the WebSocket registry
|
|
728
|
-
* (`ctx.getWebSockets()`). Iterating from the child isolate throws
|
|
729
|
-
* "Cannot perform I/O on behalf of a different Durable Object".
|
|
730
|
-
* Downstream callers (e.g. chat-streaming paths) invoke
|
|
731
|
-
* `this.broadcast()` directly, bypassing `_broadcastProtocol`'s
|
|
732
|
-
* guard, so override at the base to catch every path.
|
|
733
|
-
*/
|
|
734
|
-
broadcast(msg, without) {
|
|
735
|
-
if (this._isFacet) return;
|
|
736
|
-
super.broadcast(msg, without);
|
|
737
|
-
}
|
|
738
738
|
_setStateInternal(nextState, source = "server") {
|
|
739
739
|
this.validateStateChange(nextState, source);
|
|
740
740
|
this._state = nextState;
|
|
@@ -744,7 +744,7 @@ var Agent = class Agent extends Server {
|
|
|
744
744
|
`;
|
|
745
745
|
this._broadcastProtocol(JSON.stringify({
|
|
746
746
|
state: nextState,
|
|
747
|
-
type:
|
|
747
|
+
type: "cf_agent_state"
|
|
748
748
|
}), source !== "server" ? [source.id] : []);
|
|
749
749
|
const { connection, request, email } = __DO_NOT_USE_WILL_BREAK__agentContext.getStore() || {};
|
|
750
750
|
this.ctx.waitUntil((async () => {
|
|
@@ -1690,6 +1690,12 @@ var Agent = class Agent extends Server {
|
|
|
1690
1690
|
* alarm system, without creating schedule rows or emitting observability
|
|
1691
1691
|
* events. Configure via `static options = { keepAliveIntervalMs: 5000 }`.
|
|
1692
1692
|
*
|
|
1693
|
+
* No-op on facets. Facets share the parent's isolate and don't
|
|
1694
|
+
* need a separate alarm heartbeat — the parent's own activity,
|
|
1695
|
+
* any open WebSocket to the facet, and any in-flight Promise
|
|
1696
|
+
* already keep the shared machine alive for the duration of
|
|
1697
|
+
* real work.
|
|
1698
|
+
*
|
|
1693
1699
|
* @example
|
|
1694
1700
|
* ```ts
|
|
1695
1701
|
* const dispose = await this.keepAlive();
|
|
@@ -1701,7 +1707,7 @@ var Agent = class Agent extends Server {
|
|
|
1701
1707
|
* ```
|
|
1702
1708
|
*/
|
|
1703
1709
|
async keepAlive() {
|
|
1704
|
-
if (this._isFacet)
|
|
1710
|
+
if (this._isFacet) return () => {};
|
|
1705
1711
|
this._keepAliveRefs++;
|
|
1706
1712
|
if (this._keepAliveRefs === 1) await this._scheduleNextAlarm();
|
|
1707
1713
|
let disposed = false;
|
|
@@ -2001,6 +2007,108 @@ var Agent = class Agent extends Server {
|
|
|
2001
2007
|
await this._scheduleNextAlarm();
|
|
2002
2008
|
}
|
|
2003
2009
|
/**
|
|
2010
|
+
* Intercept incoming HTTP/WS requests whose URL contains a
|
|
2011
|
+
* `/sub/{child-class}/{child-name}` marker and forward them to
|
|
2012
|
+
* the facet. The `onBeforeSubAgent` hook fires first (authorize,
|
|
2013
|
+
* mutate, or short-circuit). If the hook doesn't return a
|
|
2014
|
+
* Response, the framework resolves the facet and hands the
|
|
2015
|
+
* request off.
|
|
2016
|
+
*
|
|
2017
|
+
* After a WebSocket upgrade completes, subsequent frames route
|
|
2018
|
+
* directly to the child — the parent is only on the path for the
|
|
2019
|
+
* initial request.
|
|
2020
|
+
*
|
|
2021
|
+
* @experimental The API surface may change before stabilizing.
|
|
2022
|
+
*/
|
|
2023
|
+
async fetch(request) {
|
|
2024
|
+
const ctx = this.ctx;
|
|
2025
|
+
const match = parseSubAgentPath(request.url, { knownClasses: ctx.exports ? Object.keys(ctx.exports) : void 0 });
|
|
2026
|
+
if (!match) return super.fetch(request);
|
|
2027
|
+
const decision = await this.onBeforeSubAgent(request, {
|
|
2028
|
+
className: match.childClass,
|
|
2029
|
+
name: match.childName
|
|
2030
|
+
});
|
|
2031
|
+
if (decision instanceof Response) return decision;
|
|
2032
|
+
const forwardReq = decision instanceof Request ? decision : request;
|
|
2033
|
+
return this._cf_forwardToFacet(forwardReq, match);
|
|
2034
|
+
}
|
|
2035
|
+
/**
|
|
2036
|
+
* Parent-side middleware hook. Fires before a request is
|
|
2037
|
+
* forwarded into a facet sub-agent. Mirrors `onBeforeConnect` /
|
|
2038
|
+
* `onBeforeRequest`.
|
|
2039
|
+
*
|
|
2040
|
+
* - return `void` (default) → forward the original request
|
|
2041
|
+
* - return `Request` → forward this (modified) request
|
|
2042
|
+
* - return `Response` → return this response to the
|
|
2043
|
+
* client; do not wake the child
|
|
2044
|
+
*
|
|
2045
|
+
* Default implementation: return void (permissive).
|
|
2046
|
+
*
|
|
2047
|
+
* The hook receives the **original** request with its URL intact —
|
|
2048
|
+
* including the `/sub/{class}/{name}` segment. The routing
|
|
2049
|
+
* decision for which facet to wake is fixed at parse time, so if
|
|
2050
|
+
* you return a modified `Request`, its headers, body, method, and
|
|
2051
|
+
* query string flow through to the child, but the **pathname**
|
|
2052
|
+
* the child sees is always the tail after `/sub/{class}/{name}`.
|
|
2053
|
+
* Customize via headers/body rather than URL-rewriting.
|
|
2054
|
+
*
|
|
2055
|
+
* WebSocket upgrade requests flow through this hook the same way as
|
|
2056
|
+
* plain HTTP. If you return a mutated `Request`, make sure it still
|
|
2057
|
+
* carries the original `Upgrade: websocket` and `Sec-WebSocket-*`
|
|
2058
|
+
* headers — the simplest safe recipe is to clone the incoming
|
|
2059
|
+
* request's headers (via `new Headers(req.headers)`) and only add
|
|
2060
|
+
* or replace entries, rather than constructing a fresh `Headers`
|
|
2061
|
+
* object from scratch.
|
|
2062
|
+
*
|
|
2063
|
+
* @experimental The API surface may change before stabilizing.
|
|
2064
|
+
*
|
|
2065
|
+
* @example
|
|
2066
|
+
* ```ts
|
|
2067
|
+
* class Inbox extends Agent {
|
|
2068
|
+
* override async onBeforeSubAgent(req, { className, name }) {
|
|
2069
|
+
* // Strict registry gate
|
|
2070
|
+
* if (!this.hasSubAgent(className, name)) {
|
|
2071
|
+
* return new Response("Not found", { status: 404 });
|
|
2072
|
+
* }
|
|
2073
|
+
* }
|
|
2074
|
+
* }
|
|
2075
|
+
* ```
|
|
2076
|
+
*/
|
|
2077
|
+
async onBeforeSubAgent(_request, _child) {}
|
|
2078
|
+
/**
|
|
2079
|
+
* Resolve the facet Fetcher for the match and forward the
|
|
2080
|
+
* request to it with `/sub/{class}/{name}` stripped.
|
|
2081
|
+
*
|
|
2082
|
+
* @internal
|
|
2083
|
+
*/
|
|
2084
|
+
async _cf_forwardToFacet(req, match) {
|
|
2085
|
+
let fetcher;
|
|
2086
|
+
try {
|
|
2087
|
+
fetcher = await this._cf_resolveSubAgent(match.childClass, match.childName);
|
|
2088
|
+
} catch (err) {
|
|
2089
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
2090
|
+
console.error("[agents] sub-agent route failed:", message);
|
|
2091
|
+
if (/null character/i.test(message) || /reserved/i.test(message)) return new Response("Bad Request", { status: 400 });
|
|
2092
|
+
return new Response("Not Found", { status: 404 });
|
|
2093
|
+
}
|
|
2094
|
+
const rewritten = new URL(req.url);
|
|
2095
|
+
rewritten.pathname = match.remainingPath;
|
|
2096
|
+
const forwarded = new Request(rewritten, req);
|
|
2097
|
+
return fetcher.fetch(forwarded);
|
|
2098
|
+
}
|
|
2099
|
+
/**
|
|
2100
|
+
* Bridge method used by `getSubAgentByName`. Resolves the facet
|
|
2101
|
+
* on each call (idempotent via `subAgent`) and dispatches one
|
|
2102
|
+
* RPC method. Stateless — no cached references.
|
|
2103
|
+
*
|
|
2104
|
+
* @internal
|
|
2105
|
+
*/
|
|
2106
|
+
async _cf_invokeSubAgent(className, name, method, args) {
|
|
2107
|
+
const handle = await this._cf_resolveSubAgent(className, name);
|
|
2108
|
+
if (typeof handle[method] !== "function") throw new Error(`Method "${method}" not found on ${className}.`);
|
|
2109
|
+
return await handle[method](...args);
|
|
2110
|
+
}
|
|
2111
|
+
/**
|
|
2004
2112
|
* Initialize this agent as a facet in a single RPC.
|
|
2005
2113
|
*
|
|
2006
2114
|
* Runs entirely inside the child's isolate, so every storage write
|
|
@@ -2010,19 +2118,105 @@ var Agent = class Agent extends Server {
|
|
|
2010
2118
|
* parent and triggered "Cannot perform I/O on behalf of a different
|
|
2011
2119
|
* Durable Object" on the child.
|
|
2012
2120
|
*
|
|
2013
|
-
*
|
|
2014
|
-
*
|
|
2015
|
-
*
|
|
2016
|
-
*
|
|
2121
|
+
* We still set `_isFacet` eagerly (before `__unsafe_ensureInitialized`)
|
|
2122
|
+
* so any code that legitimately branches on it — e.g. skipping
|
|
2123
|
+
* parent-owned alarms in schedule guards — sees the flag during
|
|
2124
|
+
* the first `onStart()` run. Broadcast paths no longer special-case
|
|
2125
|
+
* facets, since facets can be directly addressed via sub-agent
|
|
2126
|
+
* routing and have their own WebSocket connections.
|
|
2017
2127
|
*
|
|
2018
2128
|
* @internal Called by {@link subAgent}.
|
|
2019
2129
|
*/
|
|
2020
|
-
async _cf_initAsFacet(name) {
|
|
2130
|
+
async _cf_initAsFacet(name, parentPath = []) {
|
|
2021
2131
|
this._isFacet = true;
|
|
2022
|
-
|
|
2132
|
+
this._parentPath = parentPath;
|
|
2133
|
+
await Promise.all([
|
|
2134
|
+
this.ctx.storage.put("cf_agents_is_facet", true),
|
|
2135
|
+
this.ctx.storage.put("__ps_name", name),
|
|
2136
|
+
this.ctx.storage.put("cf_agents_parent_path", parentPath)
|
|
2137
|
+
]);
|
|
2023
2138
|
await this.__unsafe_ensureInitialized();
|
|
2024
2139
|
}
|
|
2025
2140
|
/**
|
|
2141
|
+
* Ancestor chain for this agent, root-first. Empty for top-level
|
|
2142
|
+
* DOs. Populated at facet init time; survives hibernation.
|
|
2143
|
+
*
|
|
2144
|
+
* @example
|
|
2145
|
+
* ```ts
|
|
2146
|
+
* class Chat extends Agent {
|
|
2147
|
+
* onStart() {
|
|
2148
|
+
* console.log("chat started under:", this.parentPath);
|
|
2149
|
+
* // → [{ className: "Tenant", name: "acme" }, { className: "Inbox", name: "alice" }]
|
|
2150
|
+
* }
|
|
2151
|
+
* }
|
|
2152
|
+
* ```
|
|
2153
|
+
*
|
|
2154
|
+
* @experimental The API surface may change before stabilizing.
|
|
2155
|
+
*/
|
|
2156
|
+
get parentPath() {
|
|
2157
|
+
return this._parentPath;
|
|
2158
|
+
}
|
|
2159
|
+
/**
|
|
2160
|
+
* Ancestor chain + self, root-first. Convenient for logging.
|
|
2161
|
+
*
|
|
2162
|
+
* @experimental The API surface may change before stabilizing.
|
|
2163
|
+
*/
|
|
2164
|
+
get selfPath() {
|
|
2165
|
+
return [...this._parentPath, {
|
|
2166
|
+
className: this.constructor.name,
|
|
2167
|
+
name: this.name
|
|
2168
|
+
}];
|
|
2169
|
+
}
|
|
2170
|
+
/**
|
|
2171
|
+
* Resolve a typed RPC stub for this facet's **immediate** parent
|
|
2172
|
+
* agent.
|
|
2173
|
+
*
|
|
2174
|
+
* Symmetric with `subAgent(Cls, name)`: while `subAgent` opens a
|
|
2175
|
+
* stub from parent to child, `parentAgent` opens one from child
|
|
2176
|
+
* to parent. Pass the direct parent's class reference — the
|
|
2177
|
+
* framework verifies it matches the last entry of
|
|
2178
|
+
* `this.parentPath` at runtime, then looks up `env[Cls.name]` to
|
|
2179
|
+
* find the namespace binding.
|
|
2180
|
+
*
|
|
2181
|
+
* `this.parentPath` is root-first, so the direct parent is the
|
|
2182
|
+
* **last** entry: `this.parentPath.at(-1)`. For grandparents and
|
|
2183
|
+
* further ancestors, iterate `this.parentPath` and use
|
|
2184
|
+
* `getAgentByName(env.X, this.parentPath[i].name)` directly.
|
|
2185
|
+
*
|
|
2186
|
+
* Assumes the standard "binding name matches class name" convention.
|
|
2187
|
+
* If your `wrangler.jsonc` binds the parent under a different name
|
|
2188
|
+
* (e.g. `{ class_name: "Inbox", name: "MY_INBOX" }`), call
|
|
2189
|
+
* `getAgentByName(env.MY_INBOX, this.parentPath.at(-1)!.name)`
|
|
2190
|
+
* directly instead.
|
|
2191
|
+
*
|
|
2192
|
+
* @experimental The API surface may change before stabilizing.
|
|
2193
|
+
*
|
|
2194
|
+
* @throws If this agent is not a facet (no parent).
|
|
2195
|
+
* @throws If `Cls.name` doesn't match the recorded direct-parent
|
|
2196
|
+
* class (guards against accidentally reaching the wrong
|
|
2197
|
+
* DO, especially in nested Root → Mid → Leaf chains).
|
|
2198
|
+
* @throws If no env binding named `Cls.name` is found.
|
|
2199
|
+
*
|
|
2200
|
+
* @example
|
|
2201
|
+
* ```ts
|
|
2202
|
+
* class Chat extends AIChatAgent<Env> {
|
|
2203
|
+
* async onChatMessage(...) {
|
|
2204
|
+
* const inbox = await this.parentAgent(Inbox);
|
|
2205
|
+
* const memory = await inbox.getSharedMemory("facts");
|
|
2206
|
+
* // ...
|
|
2207
|
+
* }
|
|
2208
|
+
* }
|
|
2209
|
+
* ```
|
|
2210
|
+
*/
|
|
2211
|
+
async parentAgent(cls) {
|
|
2212
|
+
const parent = this._parentPath[this._parentPath.length - 1];
|
|
2213
|
+
if (!parent) throw new Error(`parentAgent(): ${this.constructor.name} is not a facet — only sub-agents (spawned via \`subAgent()\`) have a parent.`);
|
|
2214
|
+
if (cls.name !== parent.className) throw new Error(`parentAgent(${cls.name}): this facet's recorded parent class is "${parent.className}", not "${cls.name}". Pass the class whose constructor actually spawned this facet.`);
|
|
2215
|
+
const binding = this.env[cls.name];
|
|
2216
|
+
if (!binding) throw new Error(`parentAgent(${cls.name}): no top-level binding "${cls.name}" found in env. If the parent is bound under a different name (e.g. "MY_${cls.name.toUpperCase()}"), use \`getAgentByName(env.MY_${cls.name.toUpperCase()}, this.parentPath.at(-1)!.name)\` directly.`);
|
|
2217
|
+
return await getServerByName(binding, parent.name);
|
|
2218
|
+
}
|
|
2219
|
+
/**
|
|
2026
2220
|
* Get or create a named sub-agent — a child Durable Object (facet)
|
|
2027
2221
|
* with its own isolated SQLite storage running on the same machine.
|
|
2028
2222
|
*
|
|
@@ -2043,12 +2237,29 @@ var Agent = class Agent extends Server {
|
|
|
2043
2237
|
* ```
|
|
2044
2238
|
*/
|
|
2045
2239
|
async subAgent(cls, name) {
|
|
2240
|
+
return await this._cf_resolveSubAgent(cls.name, name);
|
|
2241
|
+
}
|
|
2242
|
+
/**
|
|
2243
|
+
* Shared facet resolution — takes a CamelCase class name string
|
|
2244
|
+
* (matching `ctx.exports`) rather than a class reference. Both
|
|
2245
|
+
* `subAgent(cls, name)` and `_cf_invokeSubAgent(className, ...)`
|
|
2246
|
+
* funnel through here so registry bookkeeping and the
|
|
2247
|
+
* `_cf_initAsFacet` handshake are consistent.
|
|
2248
|
+
*
|
|
2249
|
+
* @internal
|
|
2250
|
+
*/
|
|
2251
|
+
async _cf_resolveSubAgent(className, name) {
|
|
2046
2252
|
const ctx = this.ctx;
|
|
2047
2253
|
if (!ctx.facets || !ctx.exports) throw new Error("subAgent() is not supported in this runtime — `ctx.facets` / `ctx.exports` are unavailable. Update to the latest `compatibility_date` in your wrangler.jsonc.");
|
|
2048
|
-
if (
|
|
2049
|
-
const
|
|
2050
|
-
|
|
2051
|
-
|
|
2254
|
+
if (camelCaseToKebabCase(className) === "sub") throw new Error(`Sub-agent class name "${className}" kebab-cases to "sub", which collides with the reserved URL separator — rename the class (e.g. "SubThing" or "Subtask").`);
|
|
2255
|
+
const Cls = ctx.exports[className];
|
|
2256
|
+
if (!Cls) throw new Error(`Sub-agent class "${className}" not found in worker exports. Make sure the class is exported from your worker entry point and that the export name matches the class name.`);
|
|
2257
|
+
if (name.includes("\0")) throw new Error(`Sub-agent name contains null character (\\0), which is reserved.`);
|
|
2258
|
+
const facetKey = `${className}\0${name}`;
|
|
2259
|
+
const stub = ctx.facets.get(facetKey, () => ({ class: Cls }));
|
|
2260
|
+
const childParentPath = this.selfPath;
|
|
2261
|
+
await stub._cf_initAsFacet(name, childParentPath);
|
|
2262
|
+
this._recordSubAgent(className, name);
|
|
2052
2263
|
return stub;
|
|
2053
2264
|
}
|
|
2054
2265
|
/**
|
|
@@ -2082,7 +2293,63 @@ var Agent = class Agent extends Server {
|
|
|
2082
2293
|
const ctx = this.ctx;
|
|
2083
2294
|
if (!ctx.facets) throw new Error("deleteSubAgent() is not supported in this runtime — `ctx.facets` is unavailable. Update to the latest `compatibility_date` in your wrangler.jsonc.");
|
|
2084
2295
|
const facetKey = `${cls.name}\0${name}`;
|
|
2085
|
-
|
|
2296
|
+
try {
|
|
2297
|
+
ctx.facets.delete(facetKey);
|
|
2298
|
+
} catch {}
|
|
2299
|
+
this._forgetSubAgent(cls.name, name);
|
|
2300
|
+
}
|
|
2301
|
+
/** @internal */
|
|
2302
|
+
_ensureSubAgentRegistry() {
|
|
2303
|
+
if (this._subAgentRegistryReady) return;
|
|
2304
|
+
this.sql`
|
|
2305
|
+
CREATE TABLE IF NOT EXISTS cf_agents_sub_agents (
|
|
2306
|
+
class TEXT NOT NULL,
|
|
2307
|
+
name TEXT NOT NULL,
|
|
2308
|
+
created_at INTEGER NOT NULL,
|
|
2309
|
+
PRIMARY KEY (class, name)
|
|
2310
|
+
)
|
|
2311
|
+
`;
|
|
2312
|
+
this._subAgentRegistryReady = true;
|
|
2313
|
+
}
|
|
2314
|
+
/** @internal */
|
|
2315
|
+
_recordSubAgent(className, name) {
|
|
2316
|
+
this._ensureSubAgentRegistry();
|
|
2317
|
+
this.sql`
|
|
2318
|
+
INSERT OR IGNORE INTO cf_agents_sub_agents (class, name, created_at)
|
|
2319
|
+
VALUES (${className}, ${name}, ${Date.now()})
|
|
2320
|
+
`;
|
|
2321
|
+
}
|
|
2322
|
+
/** @internal */
|
|
2323
|
+
_forgetSubAgent(className, name) {
|
|
2324
|
+
this._ensureSubAgentRegistry();
|
|
2325
|
+
this.sql`
|
|
2326
|
+
DELETE FROM cf_agents_sub_agents
|
|
2327
|
+
WHERE class = ${className} AND name = ${name}
|
|
2328
|
+
`;
|
|
2329
|
+
}
|
|
2330
|
+
hasSubAgent(classOrName, name) {
|
|
2331
|
+
const className = typeof classOrName === "string" ? classOrName : classOrName.name;
|
|
2332
|
+
this._ensureSubAgentRegistry();
|
|
2333
|
+
return (this.sql`
|
|
2334
|
+
SELECT COUNT(*) AS n FROM cf_agents_sub_agents
|
|
2335
|
+
WHERE class = ${className} AND name = ${name}
|
|
2336
|
+
`[0]?.n ?? 0) > 0;
|
|
2337
|
+
}
|
|
2338
|
+
listSubAgents(classOrName) {
|
|
2339
|
+
const className = typeof classOrName === "string" ? classOrName : classOrName?.name;
|
|
2340
|
+
this._ensureSubAgentRegistry();
|
|
2341
|
+
return (className ? this.sql`
|
|
2342
|
+
SELECT class, name, created_at FROM cf_agents_sub_agents
|
|
2343
|
+
WHERE class = ${className}
|
|
2344
|
+
ORDER BY created_at ASC
|
|
2345
|
+
` : this.sql`
|
|
2346
|
+
SELECT class, name, created_at FROM cf_agents_sub_agents
|
|
2347
|
+
ORDER BY created_at ASC
|
|
2348
|
+
`).map((r) => ({
|
|
2349
|
+
className: r.class,
|
|
2350
|
+
name: r.name,
|
|
2351
|
+
createdAt: r.created_at
|
|
2352
|
+
}));
|
|
2086
2353
|
}
|
|
2087
2354
|
/**
|
|
2088
2355
|
* Destroy the Agent, removing all state and scheduled tasks
|
|
@@ -2093,6 +2360,7 @@ var Agent = class Agent extends Server {
|
|
|
2093
2360
|
this.sql`DROP TABLE IF EXISTS cf_agents_schedules`;
|
|
2094
2361
|
this.sql`DROP TABLE IF EXISTS cf_agents_queues`;
|
|
2095
2362
|
this.sql`DROP TABLE IF EXISTS cf_agents_workflows`;
|
|
2363
|
+
this.sql`DROP TABLE IF EXISTS cf_agents_sub_agents`;
|
|
2096
2364
|
if (!this._isFacet) await this.ctx.storage.deleteAlarm();
|
|
2097
2365
|
await this.ctx.storage.deleteAll();
|
|
2098
2366
|
this._disposables.dispose();
|
|
@@ -3034,7 +3302,7 @@ var Agent = class Agent extends Server {
|
|
|
3034
3302
|
broadcastMcpServers() {
|
|
3035
3303
|
this._broadcastProtocol(JSON.stringify({
|
|
3036
3304
|
mcp: this.getMcpServers(),
|
|
3037
|
-
type:
|
|
3305
|
+
type: "cf_agent_mcp_servers"
|
|
3038
3306
|
}));
|
|
3039
3307
|
}
|
|
3040
3308
|
/**
|
|
@@ -3225,7 +3493,7 @@ var StreamingResponse = class {
|
|
|
3225
3493
|
id: this._id,
|
|
3226
3494
|
result: chunk,
|
|
3227
3495
|
success: true,
|
|
3228
|
-
type:
|
|
3496
|
+
type: "rpc"
|
|
3229
3497
|
};
|
|
3230
3498
|
this._connection.send(JSON.stringify(response));
|
|
3231
3499
|
return true;
|
|
@@ -3243,7 +3511,7 @@ var StreamingResponse = class {
|
|
|
3243
3511
|
id: this._id,
|
|
3244
3512
|
result: finalChunk,
|
|
3245
3513
|
success: true,
|
|
3246
|
-
type:
|
|
3514
|
+
type: "rpc"
|
|
3247
3515
|
};
|
|
3248
3516
|
this._connection.send(JSON.stringify(response));
|
|
3249
3517
|
return true;
|
|
@@ -3260,13 +3528,13 @@ var StreamingResponse = class {
|
|
|
3260
3528
|
error: message,
|
|
3261
3529
|
id: this._id,
|
|
3262
3530
|
success: false,
|
|
3263
|
-
type:
|
|
3531
|
+
type: "rpc"
|
|
3264
3532
|
};
|
|
3265
3533
|
this._connection.send(JSON.stringify(response));
|
|
3266
3534
|
return true;
|
|
3267
3535
|
}
|
|
3268
3536
|
};
|
|
3269
3537
|
//#endregion
|
|
3270
|
-
export { Agent, DEFAULT_AGENT_STATIC_OPTIONS, DurableObjectOAuthClientProvider, MessageType, SqlError, StreamingResponse, __DO_NOT_USE_WILL_BREAK__agentContext, callable, createHeaderBasedEmailResolver, getAgentByName, getCurrentAgent, routeAgentEmail, routeAgentRequest, unstable_callable };
|
|
3538
|
+
export { Agent, DEFAULT_AGENT_STATIC_OPTIONS, DurableObjectOAuthClientProvider, MessageType, SUB_PREFIX, SqlError, StreamingResponse, __DO_NOT_USE_WILL_BREAK__agentContext, callable, createHeaderBasedEmailResolver, getAgentByName, getCurrentAgent, getSubAgentByName, parseSubAgentPath, routeAgentEmail, routeAgentRequest, routeSubAgentRequest, unstable_callable };
|
|
3271
3539
|
|
|
3272
3540
|
//# sourceMappingURL=index.js.map
|