agents 0.20.1 → 0.22.0
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 +51 -12
- package/dist/{agent-tool-types-BC-WFlsz.d.ts → agent-routing-CnkaHb-v.d.ts} +3305 -3138
- package/dist/agent-routing.d.ts +14 -0
- package/dist/agent-routing.js +187 -0
- package/dist/agent-routing.js.map +1 -0
- package/dist/agent-tool-types.d.ts +26 -26
- package/dist/{agent-tools-DeHe9Xov.d.ts → agent-tools-C0XJqWzB.d.ts} +7 -7
- package/dist/agent-tools.d.ts +44 -28
- package/dist/agent-tools.js +16 -7
- package/dist/agent-tools.js.map +1 -1
- package/dist/browser/ai.d.ts +5 -3
- package/dist/browser/ai.js +88 -8
- package/dist/browser/ai.js.map +1 -1
- package/dist/browser/index.d.ts +1 -1
- package/dist/browser/index.js +1 -1
- package/dist/browser/tanstack-ai.js +13 -1
- package/dist/browser/tanstack-ai.js.map +1 -1
- package/dist/capability-BjSKYpzg.js +42 -0
- package/dist/capability-BjSKYpzg.js.map +1 -0
- package/dist/capability-runner-CvHGZqUu.d.ts +150 -0
- package/dist/chat/index.d.ts +51 -15
- package/dist/chat/index.js +59 -4
- package/dist/chat/index.js.map +1 -1
- package/dist/chat/react.d.ts +19 -180
- package/dist/chat/react.js +93 -600
- package/dist/chat/react.js.map +1 -1
- package/dist/chat/transport.d.ts +10 -0
- package/dist/chat/transport.js +2 -0
- package/dist/chat-sdk/index.d.ts +4 -4
- package/dist/chat-sdk/index.js +1 -1
- package/dist/{client-zqKcsyFa.js → client-jagG8a9_.js} +129 -37
- package/dist/client-jagG8a9_.js.map +1 -0
- package/dist/client.d.ts +1 -1
- package/dist/client.js +1 -1
- package/dist/{cloudflare-BduZwmYK.js → cloudflare-Dzvc7V2N.js} +10 -3
- package/dist/{cloudflare-BduZwmYK.js.map → cloudflare-Dzvc7V2N.js.map} +1 -1
- package/dist/{connector-v2M1zlZp.d.ts → connector-CkQD4MK3.d.ts} +20 -3
- package/dist/{connector-KEJnl6e5.js → connector-CptFKzRh.js} +158 -40
- package/dist/connector-CptFKzRh.js.map +1 -0
- package/dist/current-agent-CuMErtly.d.ts +283 -0
- package/dist/current-agent-DhoDkSnH.js +51 -0
- package/dist/current-agent-DhoDkSnH.js.map +1 -0
- package/dist/diagnostics-CaBjfz4J.js +41 -0
- package/dist/diagnostics-CaBjfz4J.js.map +1 -0
- package/dist/{do-oauth-client-provider-VTZj2VtM.d.ts → do-oauth-client-provider-Tmf1vgKz.d.ts} +2 -2
- package/dist/durable-object-lifecycle-D6nNQJJd.js +862 -0
- package/dist/durable-object-lifecycle-D6nNQJJd.js.map +1 -0
- package/dist/{email-CL27preh.d.ts → email-7TatiTnl.d.ts} +38 -9
- package/dist/email-send.d.ts +15 -0
- package/dist/email-send.js +32 -0
- package/dist/email-send.js.map +1 -0
- package/dist/email.d.ts +14 -10
- package/dist/email.js.map +1 -1
- package/dist/experimental/memory/session/index.d.ts +3 -2
- package/dist/experimental/memory/session/index.js +15 -10
- package/dist/experimental/memory/session/index.js.map +1 -1
- package/dist/{handler-stateless-C_bo-Ytq.d.ts → handler-stateless-DxYpJ_XF.d.ts} +3 -3
- package/dist/{handler-stateless-CIkKPETH.js → handler-stateless-VvrWSAVA.js} +5 -5
- package/dist/handler-stateless-VvrWSAVA.js.map +1 -0
- package/dist/{index-BRnybD6X.d.ts → index-DcSAZKsB.d.ts} +19 -31
- package/dist/index.d.ts +102 -91
- package/dist/index.js +12 -7235
- package/dist/internal_context-BlxFEWfn.d.ts +19 -0
- package/dist/internal_context.d.ts +10 -4
- package/dist/internal_context.js +1 -10
- package/dist/{client-invoker-BNSZxAkv.d.ts → invoker-CG0_p_Wq.d.ts} +2 -2
- package/dist/{client-invoker-VNZ7X0nn.js → invoker-CHMnoxIA.js} +2 -2
- package/dist/invoker-CHMnoxIA.js.map +1 -0
- package/dist/lifecycle/index.d.ts +48 -0
- package/dist/lifecycle/index.js +4 -0
- package/dist/mcp/{do-oauth-client-provider.d.ts → client/do-oauth-client-provider.d.ts} +1 -1
- package/dist/mcp/{do-oauth-client-provider.js → client/do-oauth-client-provider.js} +1 -1
- package/dist/mcp/client/do-oauth-client-provider.js.map +1 -0
- package/dist/mcp/client/index.d.ts +42 -0
- package/dist/mcp/{client.js → client/index.js} +1 -1
- package/dist/mcp/{x402.d.ts → client/x402.d.ts} +2 -2
- package/dist/mcp/{x402.js → client/x402.js} +2 -2
- package/dist/mcp/client/x402.js.map +1 -0
- package/dist/mcp/index.d.ts +36 -36
- package/dist/mcp/index.js +14 -16
- package/dist/mcp/index.js.map +1 -1
- package/dist/mcp/{server.d.ts → server/index.d.ts} +1 -1
- package/dist/mcp/{server.js → server/index.js} +1 -1
- package/dist/observability/ai/index.d.ts +1 -130
- package/dist/observability/ai/index.js +88 -433
- package/dist/observability/ai/index.js.map +1 -1
- package/dist/observability/index.d.ts +4 -4
- package/dist/observability/index.js +3 -50
- package/dist/observability/index.js.map +1 -1
- package/dist/{wire-types-CU9rLoeS.js → protocol-B0nh6KNf.js} +20 -66
- package/dist/protocol-B0nh6KNf.js.map +1 -0
- package/dist/react.d.ts +4 -4
- package/dist/react.js +6 -9
- package/dist/react.js.map +1 -1
- package/dist/schedule.d.ts +25 -94
- package/dist/schedule.js +1 -98
- package/dist/schedule.js.map +1 -1
- package/dist/scheduler-CR9RHGos.js +857 -0
- package/dist/scheduler-CR9RHGos.js.map +1 -0
- package/dist/scheduler-DQoTGoAW.d.ts +224 -0
- package/dist/schedules/index.d.ts +22 -0
- package/dist/schedules/index.js +2 -0
- package/dist/schedules/parser.d.ts +79 -0
- package/dist/schedules/parser.js +103 -0
- package/dist/schedules/parser.js.map +1 -0
- package/dist/serializable.d.ts +1 -1
- package/dist/sql-error-CPY-GXyI.d.ts +12 -0
- package/dist/sql-error.d.ts +2 -0
- package/dist/sql-error.js +16 -0
- package/dist/sql-error.js.map +1 -0
- package/dist/src-5W6JNKVb.js +6613 -0
- package/dist/src-5W6JNKVb.js.map +1 -0
- package/dist/sub-routing.d.ts +18 -6
- package/dist/sub-routing.js +92 -2
- package/dist/sub-routing.js.map +1 -1
- package/dist/wire-types-CnMt6_HR.js +47 -0
- package/dist/wire-types-CnMt6_HR.js.map +1 -0
- package/dist/workflow-types.d.ts +25 -25
- package/dist/workflow-types.js.map +1 -1
- package/dist/workflows.d.ts +22 -22
- package/dist/workflows.js +2 -1
- package/dist/workflows.js.map +1 -1
- package/dist/ws-chat-transport-UNRIS2xl.d.ts +184 -0
- package/dist/ws-chat-transport-rWwta645.js +698 -0
- package/dist/ws-chat-transport-rWwta645.js.map +1 -0
- package/docs/adding-to-existing-project.md +4 -2
- package/docs/agent-class.md +29 -87
- package/docs/agent-tools.md +29 -0
- package/docs/browse-the-web.md +16 -1
- package/docs/chat-agents.md +16 -13
- package/docs/client-sdk.md +12 -8
- package/docs/configuration.md +7 -1
- package/docs/cross-domain-authentication.md +7 -35
- package/docs/durable-execution.md +1 -1
- package/docs/email.md +2 -13
- package/docs/http-websockets.md +1 -11
- package/docs/human-in-the-loop.md +16 -13
- package/docs/index.md +1 -0
- package/docs/lifecycle.md +323 -0
- package/docs/long-running-agents.md +13 -15
- package/docs/mcp-client.md +55 -0
- package/docs/mcp-servers.md +6 -0
- package/docs/mcp-transports.md +18 -12
- package/docs/migration-to-ai-sdk-v5.md +2 -2
- package/docs/migration-to-ai-sdk-v6.md +5 -1
- package/docs/observability.md +33 -77
- package/docs/resumable-streaming.md +1 -1
- package/docs/routing.md +27 -0
- package/docs/scheduling.md +175 -15
- package/docs/server-driven-messages.md +1 -1
- package/docs/sub-agents.md +47 -2
- package/docs/webhooks.md +109 -136
- package/docs/workflows.md +9 -1
- package/package.json +41 -23
- package/dist/cli/index.d.ts +0 -1
- package/dist/cli/index.js +0 -26
- package/dist/cli/index.js.map +0 -1
- package/dist/client-invoker-VNZ7X0nn.js.map +0 -1
- package/dist/client-zqKcsyFa.js.map +0 -1
- package/dist/connector-KEJnl6e5.js.map +0 -1
- package/dist/handler-stateless-CIkKPETH.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/internal_context-Dg4Cgjcu.d.ts +0 -37
- package/dist/internal_context.js.map +0 -1
- package/dist/mcp/client.d.ts +0 -42
- package/dist/mcp/do-oauth-client-provider.js.map +0 -1
- package/dist/mcp/x402.js.map +0 -1
- package/dist/wire-types-CU9rLoeS.js.map +0 -1
- package/dist/workflow-types-Baz_PO5v.d.ts +0 -280
package/dist/sub-routing.d.ts
CHANGED
|
@@ -1,13 +1,25 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
2
|
+
An as buildSubAgentPathUnchecked,
|
|
3
|
+
Cn as AgentPathStep,
|
|
4
|
+
Dn as buildAgentPath,
|
|
5
|
+
En as SubAgentPathMatch,
|
|
6
|
+
Mn as parseSubAgentPath,
|
|
7
|
+
Nn as routeSubAgentRequest,
|
|
8
|
+
On as buildAgentUrl,
|
|
9
|
+
Tn as SUB_PREFIX,
|
|
10
|
+
jn as getSubAgentByName,
|
|
11
|
+
kn as buildSubAgentPath,
|
|
12
|
+
wn as BuildAgentPathOptions
|
|
13
|
+
} from "./agent-routing-CnkaHb-v.js";
|
|
8
14
|
export {
|
|
15
|
+
AgentPathStep,
|
|
16
|
+
BuildAgentPathOptions,
|
|
9
17
|
SUB_PREFIX,
|
|
10
18
|
SubAgentPathMatch,
|
|
19
|
+
buildAgentPath,
|
|
20
|
+
buildAgentUrl,
|
|
21
|
+
buildSubAgentPath,
|
|
22
|
+
buildSubAgentPathUnchecked,
|
|
11
23
|
getSubAgentByName,
|
|
12
24
|
parseSubAgentPath,
|
|
13
25
|
routeSubAgentRequest
|
package/dist/sub-routing.js
CHANGED
|
@@ -26,6 +26,96 @@ import { camelCaseToKebabCase, isInternalJsStubProp } from "./utils.js";
|
|
|
26
26
|
* token everywhere (parent fetch, client, helpers).
|
|
27
27
|
*/
|
|
28
28
|
const SUB_PREFIX = "sub";
|
|
29
|
+
function validateLeafPath(leafPath) {
|
|
30
|
+
const normalized = leafPath.startsWith("/") ? leafPath : `/${leafPath}`;
|
|
31
|
+
const parsed = new URL(normalized, "https://agents.invalid");
|
|
32
|
+
if (normalized.includes("//") || normalized.length > 1 && normalized.endsWith("/") || parsed.pathname !== normalized || parsed.search || parsed.hash) throw new Error(`Cannot build an Agent path for leaf path ${JSON.stringify(leafPath)} because it is not a stable pathname.`);
|
|
33
|
+
return normalized;
|
|
34
|
+
}
|
|
35
|
+
function validateRoutingPrefix(prefix) {
|
|
36
|
+
const prefixParts = prefix.split("/");
|
|
37
|
+
const rawPath = `/${prefix}/leaf`;
|
|
38
|
+
const parsed = new URL(rawPath, "https://agents.invalid");
|
|
39
|
+
if (prefixParts.some((part) => !part || part === "." || part === ".." || part === "sub") || parsed.pathname !== rawPath || parsed.search || parsed.hash) throw new Error(`Cannot build an Agent path for routing prefix ${JSON.stringify(prefix)} because it is not externally routable.`);
|
|
40
|
+
return prefix;
|
|
41
|
+
}
|
|
42
|
+
function encodeAgentClassName(className) {
|
|
43
|
+
const segment = camelCaseToKebabCase(className);
|
|
44
|
+
if (segment === "sub") throw new Error(`Cannot build an Agent path for Agent class name ${JSON.stringify(className)} because ${JSON.stringify("sub")} is reserved.`);
|
|
45
|
+
const rawPath = `/root/${segment}/leaf`;
|
|
46
|
+
const parsed = new URL(rawPath, "https://agents.invalid");
|
|
47
|
+
const parts = parsed.pathname.split("/");
|
|
48
|
+
if (!segment || parsed.pathname !== rawPath || parsed.search || parsed.hash || parts.length !== 4 || parts[2] !== segment) throw new Error(`Cannot build an Agent path for Agent class name ${JSON.stringify(className)} because it is not externally routable.`);
|
|
49
|
+
return segment;
|
|
50
|
+
}
|
|
51
|
+
function encodeChildAgentName(name) {
|
|
52
|
+
if (!name || name === "." || name === ".." || name.includes("\0")) throw new Error(`Cannot build an Agent path for child Agent name ${JSON.stringify(name)} because it is not externally routable.`);
|
|
53
|
+
try {
|
|
54
|
+
return encodeURIComponent(name);
|
|
55
|
+
} catch {
|
|
56
|
+
throw new Error(`Cannot build an Agent path for child Agent name ${JSON.stringify(name)} because it is not valid Unicode.`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
function validateRootAgentName(name) {
|
|
60
|
+
if (name === "sub") throw new Error(`Cannot build an Agent path for root Agent name ${JSON.stringify(name)} because ${JSON.stringify("sub")} is reserved.`);
|
|
61
|
+
const rawPath = `/root/${name}/leaf`;
|
|
62
|
+
const parsed = new URL(rawPath, "https://agents.invalid");
|
|
63
|
+
const parts = parsed.pathname.split("/");
|
|
64
|
+
if (!name || parsed.pathname !== rawPath || parsed.search || parsed.hash || parts.length !== 4 || parts[2] !== name) throw new Error(`Cannot build an Agent path for root Agent name ${JSON.stringify(name)} because it is not externally routable.`);
|
|
65
|
+
return name;
|
|
66
|
+
}
|
|
67
|
+
function serializeSubAgentPath(path, leafPath, validate) {
|
|
68
|
+
if (path.length === 0) return leafPath ?? "";
|
|
69
|
+
const subPath = path.flatMap((child) => [
|
|
70
|
+
"sub",
|
|
71
|
+
validate ? encodeAgentClassName(child.className) : camelCaseToKebabCase(child.className),
|
|
72
|
+
validate ? encodeChildAgentName(child.name) : encodeURIComponent(child.name)
|
|
73
|
+
]).join("/");
|
|
74
|
+
if (!leafPath) return subPath;
|
|
75
|
+
return `${subPath}${leafPath.startsWith("/") ? leafPath : `/${leafPath}`}`;
|
|
76
|
+
}
|
|
77
|
+
/** @internal Build the strictly validated path tail for sub-agent routing. */
|
|
78
|
+
function buildSubAgentPath(path, leafPath) {
|
|
79
|
+
return serializeSubAgentPath(path, leafPath, true);
|
|
80
|
+
}
|
|
81
|
+
/** @internal Preserve React's tolerant path composition for disabled placeholders. */
|
|
82
|
+
function buildSubAgentPathUnchecked(path, leafPath) {
|
|
83
|
+
return serializeSubAgentPath(path, leafPath, false);
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Build the canonical pathname for a root Agent or nested sub-agent.
|
|
87
|
+
*
|
|
88
|
+
* The address is root-first and accepts `Agent#selfPath`. Pass
|
|
89
|
+
* `rootBinding` when the root Durable Object binding and class names differ.
|
|
90
|
+
*/
|
|
91
|
+
function buildAgentPath(path, options = {}) {
|
|
92
|
+
const [root, ...children] = path;
|
|
93
|
+
if (!root) throw new Error("Agent path must contain at least one step.");
|
|
94
|
+
const rootPath = [
|
|
95
|
+
validateRoutingPrefix(options.prefix ?? "agents"),
|
|
96
|
+
encodeAgentClassName(options.rootBinding ?? root.className),
|
|
97
|
+
validateRootAgentName(root.name)
|
|
98
|
+
].join("/");
|
|
99
|
+
const leafPath = options.leafPath ? validateLeafPath(options.leafPath) : void 0;
|
|
100
|
+
if (children.length === 0) return `/${rootPath}${leafPath ?? ""}`;
|
|
101
|
+
return `/${rootPath}/${buildSubAgentPath(children, leafPath)}`;
|
|
102
|
+
}
|
|
103
|
+
/** Build an absolute URL for a root Agent or nested sub-agent. */
|
|
104
|
+
function buildAgentUrl(origin, path, options = {}) {
|
|
105
|
+
let base;
|
|
106
|
+
try {
|
|
107
|
+
base = new URL(origin.toString());
|
|
108
|
+
} catch {
|
|
109
|
+
throw new Error(`Invalid Agent URL origin ${JSON.stringify(origin)}.`);
|
|
110
|
+
}
|
|
111
|
+
if (![
|
|
112
|
+
"http:",
|
|
113
|
+
"https:",
|
|
114
|
+
"ws:",
|
|
115
|
+
"wss:"
|
|
116
|
+
].includes(base.protocol) || base.username || base.password || base.pathname !== "/" || base.search || base.hash) throw new Error(`Invalid Agent URL origin ${JSON.stringify(origin.toString())}. Pass an HTTP(S) or WS(S) origin without credentials, a pathname, query, or fragment.`);
|
|
117
|
+
return new URL(buildAgentPath(path, options), base);
|
|
118
|
+
}
|
|
29
119
|
/**
|
|
30
120
|
* Parse a URL and extract the first `/sub/{class}/{name}` segment,
|
|
31
121
|
* if any. Recursive nesting is handled naturally: callers parse one
|
|
@@ -110,7 +200,7 @@ async function routeSubAgentRequest(req, parent, options) {
|
|
|
110
200
|
method: req.method,
|
|
111
201
|
headers: new Headers(req.headers)
|
|
112
202
|
};
|
|
113
|
-
if (req.body && req.method !== "GET" && req.method !== "HEAD") forwardInit.body =
|
|
203
|
+
if (req.body && req.method !== "GET" && req.method !== "HEAD") forwardInit.body = req.body;
|
|
114
204
|
const forwardReq = new Request(forwardUrl, forwardInit);
|
|
115
205
|
return parent.fetch(forwardReq);
|
|
116
206
|
}
|
|
@@ -172,6 +262,6 @@ async function getSubAgentByName(parent, cls, name) {
|
|
|
172
262
|
} });
|
|
173
263
|
}
|
|
174
264
|
//#endregion
|
|
175
|
-
export { SUB_PREFIX, getSubAgentByName, parseSubAgentPath, routeSubAgentRequest };
|
|
265
|
+
export { SUB_PREFIX, buildAgentPath, buildAgentUrl, buildSubAgentPath, buildSubAgentPathUnchecked, getSubAgentByName, parseSubAgentPath, routeSubAgentRequest };
|
|
176
266
|
|
|
177
267
|
//# sourceMappingURL=sub-routing.js.map
|
package/dist/sub-routing.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sub-routing.js","names":[],"sources":["../src/sub-routing.ts"],"sourcesContent":["/**\n * Sub-agent routing primitives — external addressability for facets.\n *\n * The public surface:\n * - `routeSubAgentRequest(req, parent, options?)` — the sub-agent\n * analog of `routeAgentRequest`. Use in custom fetch handlers.\n * - `getSubAgentByName(parent, Cls, name)` — the sub-agent analog\n * of `getAgentByName`. Returns a typed RPC stub that proxies\n * method calls through the parent. No `.fetch()` support —\n * external HTTP/WS routing goes through `routeSubAgentRequest`.\n *\n * Internal:\n * - `parseSubAgentPath(url)` — URL → `{ childClass, childName, remainingPath }`.\n * - `forwardToFacet(req, parent, match)` — resolves `ctx.facets.get(...)`\n * on the parent and returns `facetStub.fetch(rewrittenReq)`.\n *\n * @experimental The API surface may change before stabilizing.\n */\n\nimport { camelCaseToKebabCase, isInternalJsStubProp } from \"./utils\";\nimport type { Agent, SubAgentClass, SubAgentStub } from \"./index\";\n\n/**\n * URL segment marking a parent↔child boundary.\n *\n * Exposed as a constant so callers can build URLs symbolically, but\n * not configurable — the routing layer matches on the literal `sub`\n * token everywhere (parent fetch, client, helpers).\n */\nexport const SUB_PREFIX = \"sub\";\n\nexport interface SubAgentPathMatch {\n /** CamelCase class name of the child, as it appears in `ctx.exports`. */\n childClass: string;\n /** URL-decoded child name. */\n childName: string;\n /**\n * Request path to forward to the child, with the\n * `/sub/{class}/{name}` segment stripped. Always begins with `/`;\n * may itself contain further `/sub/...` markers when a\n * recursively nested sub-agent is being routed.\n */\n remainingPath: string;\n}\n\n/**\n * Parse a URL and extract the first `/sub/{class}/{name}` segment,\n * if any. Recursive nesting is handled naturally: callers parse one\n * level at a time; the child then parses its own URL (which still\n * contains any deeper `/sub/...` markers).\n *\n * Names are URL-decoded. Classes are kebab-to-CamelCase converted\n * via a best-effort match against a provided lookup — pass\n * `ctx.exports` keys to get exact CamelCase; pass `undefined` for\n * a tolerant conversion without validation.\n *\n * Returns `null` when the URL doesn't contain the marker at a\n * recognized position, or when the marker has no following\n * class+name pair.\n */\nexport function parseSubAgentPath(\n url: string,\n options?: {\n /** CamelCase class names to match against (usually `ctx.exports` keys). */\n knownClasses?: readonly string[];\n }\n): SubAgentPathMatch | null {\n const pathname = new URL(url).pathname;\n const parts = pathname.split(\"/\").filter(Boolean);\n\n // Walk every occurrence of the `sub` segment — a plain\n // `indexOf(SUB_PREFIX)` would mis-match when the literal token\n // appears earlier in the URL (parent instance name == \"sub\", a\n // `basePath` segment that happens to be \"sub\", etc). We return\n // the first position where `parts[i+1]` resolves to a valid\n // class, which pins the real parent↔child boundary.\n for (let i = 0; i < parts.length; i++) {\n if (parts[i] !== SUB_PREFIX) continue;\n if (i + 2 >= parts.length) continue;\n\n const classSegment = parts[i + 1];\n const nameSegment = parts[i + 2];\n\n const childClass = resolveClassName(classSegment, options?.knownClasses);\n if (!childClass) continue;\n\n let childName: string;\n try {\n childName = decodeURIComponent(nameSegment);\n } catch {\n continue;\n }\n\n const remainingParts = parts.slice(i + 3);\n const remainingPath =\n remainingParts.length > 0 ? \"/\" + remainingParts.join(\"/\") : \"/\";\n\n return { childClass, childName, remainingPath };\n }\n\n return null;\n}\n\n/**\n * Best-effort kebab-to-CamelCase match. If `knownClasses` is\n * provided, returns the matching CamelCase entry (or null if no\n * match). If not, performs a naive kebab→CamelCase conversion.\n */\nfunction resolveClassName(\n segment: string,\n knownClasses?: readonly string[]\n): string | null {\n if (knownClasses) {\n const match = knownClasses.find(\n (name) => camelCaseToKebabCase(name) === segment\n );\n return match ?? null;\n }\n return segment\n .split(\"-\")\n .map((s) => s.charAt(0).toUpperCase() + s.slice(1))\n .join(\"\");\n}\n\n// ── routeSubAgentRequest ───────────────────────────────────────────\n\n/**\n * Minimal parent-side shape that `routeSubAgentRequest` relies on:\n * something fetchable (a DO stub, a sub-agent stub, etc.).\n *\n * @internal\n */\ninterface FetchableParent {\n fetch(req: Request): Promise<Response>;\n}\n\n/**\n * Route a request into a sub-agent via its parent DO.\n *\n * Use this in a custom fetch handler when your URL shape doesn't\n * match the `/agents/{class}/{name}` default — you identify and\n * fetch the parent yourself, then let this helper parse the\n * `/sub/{child}/...` tail and forward it.\n *\n * Runs `onBeforeSubAgent` on the parent DO (authorization / request\n * mutation / short-circuit response).\n *\n * For the default `/agents/...` URL shape, use `routeAgentRequest`\n * instead — it handles the parent lookup and this dispatch in one\n * call.\n *\n * @example\n * ```ts\n * export default {\n * async fetch(req, env) {\n * const { parentName, rest } = myCustomParse(req.url);\n * const parent = await getAgentByName(env.Inbox, parentName);\n * return routeSubAgentRequest(req, parent, { fromPath: rest });\n * }\n * };\n * ```\n *\n * @experimental The API surface may change before stabilizing.\n */\nexport async function routeSubAgentRequest(\n req: Request,\n parent: unknown,\n options?: {\n /**\n * Path to route on. Defaults to `req.url`'s pathname. Useful\n * when your outer URL is custom (e.g. `/api/v1/...`) and you\n * want to route the sub-agent tail without rewriting the\n * Request first.\n */\n fromPath?: string;\n }\n): Promise<Response> {\n // We don't know the parent's ctx.exports from here, so parse with\n // a permissive resolver. If the class doesn't exist, the parent's\n // bridge will 404. This lets us keep the helper self-contained.\n const pathForParsing = options?.fromPath\n ? `http://placeholder${options.fromPath.startsWith(\"/\") ? \"\" : \"/\"}${options.fromPath}`\n : req.url;\n\n const match = parseSubAgentPath(pathForParsing);\n if (!match) {\n return new Response(\"Sub-agent path not found in request URL\", {\n status: 400\n });\n }\n\n // Hand the request to the parent so `onBeforeSubAgent` fires in\n // the parent's isolate. The parent's `fetch` handler recognizes\n // the marker internally — we preserve the original request URL\n // (possibly rewritten by `fromPath`) so the parent's parse sees\n // the same match.\n //\n // Key subtlety: when rewriting the pathname via `fromPath`, we\n // mutate the *original* URL's pathname instead of constructing a\n // new URL from scratch. `new URL(\"/path\", baseWithQuery)` discards\n // the base's search; we want the caller's query params (e.g. auth\n // tokens, PartySocket's `_pk=...` handshake key) to survive.\n // Mirrors how `_cf_forwardToFacet` rewrites only pathname when\n // handing off to the child facet. If `fromPath` itself contains a\n // `?query` segment, that overrides the original.\n const forwardUrl =\n options?.fromPath !== undefined\n ? rewritePathname(req.url, options.fromPath)\n : req.url;\n const forwardInit: RequestInit = {\n method: req.method,\n headers: new Headers(req.headers)\n };\n if (req.body && req.method !== \"GET\" && req.method !== \"HEAD\") {\n forwardInit.body = await req.arrayBuffer();\n }\n const forwardReq = new Request(forwardUrl, forwardInit);\n\n return (parent as FetchableParent).fetch(forwardReq);\n}\n\n/**\n * Replace a URL's pathname (and optionally its search) while\n * preserving every other component. Matches how `_cf_forwardToFacet`\n * forwards requests — pathname is the only thing that changes by\n * default; if the replacement path carries its own query string,\n * that wins.\n */\nfunction rewritePathname(url: string, fromPath: string): string {\n const normalized = fromPath.startsWith(\"/\") ? fromPath : `/${fromPath}`;\n const queryIdx = normalized.indexOf(\"?\");\n const pathOnly = queryIdx >= 0 ? normalized.slice(0, queryIdx) : normalized;\n const querySuffix = queryIdx >= 0 ? normalized.slice(queryIdx) : \"\";\n\n const rewritten = new URL(url);\n rewritten.pathname = pathOnly;\n if (querySuffix) {\n rewritten.search = querySuffix; // URL setter keeps the `?` prefix\n }\n return rewritten.toString();\n}\n\n// ── getSubAgentByName ──────────────────────────────────────────────\n\n/**\n * Parent-side RPC bridge shape that `getSubAgentByName` relies on.\n *\n * @internal\n */\ninterface SubAgentInvokeEndpoint {\n _cf_invokeSubAgent(\n className: string,\n name: string,\n method: string,\n args: unknown[]\n ): Promise<unknown>;\n}\n\n/**\n * Get a typed RPC stub for a sub-agent from outside the parent DO.\n *\n * The returned stub proxies method calls through the parent via a\n * stateless per-call bridge (caller → parent → facet), so each\n * method invocation costs one extra RPC hop. Works across parent\n * hibernation — no cached references to go stale.\n *\n * Limitations:\n * - RPC methods only. `.fetch()` is not supported (will throw).\n * Use `routeSubAgentRequest` for external HTTP/WS.\n * - Arguments and return values must be structured-cloneable,\n * same as any DO RPC call.\n * - Does not run `onBeforeSubAgent` on the parent — analogous to\n * `getAgentByName` not running `onBeforeConnect`. The caller is\n * assumed to have performed whatever access checks are needed.\n *\n * @example\n * ```ts\n * const inbox = await getAgentByName(env.MyInbox, userId);\n * const chat = await getSubAgentByName(inbox, MyChat, chatId);\n * await chat.addMessage({ role: \"user\", content: \"hi\" });\n * ```\n *\n * @experimental The API surface may change before stabilizing.\n */\nexport async function getSubAgentByName<T extends Agent>(\n parent: unknown,\n cls: SubAgentClass<T>,\n name: string\n): Promise<SubAgentStub<T>> {\n if (name.includes(\"\\0\")) {\n throw new Error(\n `Sub-agent name contains null character (\\\\0), which is reserved.`\n );\n }\n\n const bridge = parent as SubAgentInvokeEndpoint;\n const className = cls?.name;\n if (!className) {\n throw new Error(\n `getSubAgentByName: could not determine class name from ${cls}. ` +\n `Ensure you are passing the class constructor (e.g. getSubAgentByName(parent, MyChat, name)), not a string or undefined.`\n );\n }\n\n return new Proxy(\n {},\n {\n get(_target, prop) {\n // JS / runtime / test-framework probes (thenable check,\n // serialization, inspection, matcher duck-typing) must NOT\n // dispatch an RPC — returning `undefined` is the contract\n // the inner `createStubProxy` uses for `useAgent` stubs.\n // Without this guard, `JSON.stringify(stub)`, `console.log`,\n // Vitest matchers, and `await stub` would all trigger bogus\n // `_cf_invokeSubAgent` calls that fail with \"Method not found\".\n if (isInternalJsStubProp(prop)) return undefined;\n if (typeof prop !== \"string\") return undefined;\n // `.fetch` gets a dedicated error so users who try to use\n // the stub for HTTP/WS get a helpful pointer.\n if (prop === \"fetch\") {\n return () => {\n throw new Error(\n `getSubAgentByName returns an RPC-only stub — .fetch() is ` +\n `not supported. Use routeSubAgentRequest() or the ` +\n `/agents/{parent}/{name}/sub/{child}/{name} URL for ` +\n `external HTTP/WS routing.`\n );\n };\n }\n return async (...args: unknown[]) =>\n bridge._cf_invokeSubAgent(className, name, prop, args);\n }\n }\n ) as SubAgentStub<T>;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"sub-routing.js","names":[],"sources":["../src/sub-routing.ts"],"sourcesContent":["/**\n * Sub-agent routing primitives — external addressability for facets.\n *\n * The public surface:\n * - `routeSubAgentRequest(req, parent, options?)` — the sub-agent\n * analog of `routeAgentRequest`. Use in custom fetch handlers.\n * - `getSubAgentByName(parent, Cls, name)` — the sub-agent analog\n * of `getAgentByName`. Returns a typed RPC stub that proxies\n * method calls through the parent. No `.fetch()` support —\n * external HTTP/WS routing goes through `routeSubAgentRequest`.\n *\n * Internal:\n * - `parseSubAgentPath(url)` — URL → `{ childClass, childName, remainingPath }`.\n * - `forwardToFacet(req, parent, match)` — resolves `ctx.facets.get(...)`\n * on the parent and returns `facetStub.fetch(rewrittenReq)`.\n *\n * @experimental The API surface may change before stabilizing.\n */\n\nimport { camelCaseToKebabCase, isInternalJsStubProp } from \"./utils\";\nimport type { Agent, SubAgentClass, SubAgentStub } from \"./index\";\n\n/**\n * URL segment marking a parent↔child boundary.\n *\n * Exposed as a constant so callers can build URLs symbolically, but\n * not configurable — the routing layer matches on the literal `sub`\n * token everywhere (parent fetch, client, helpers).\n */\nexport const SUB_PREFIX = \"sub\";\n\n/** One agent identity in a root-first address chain. */\nexport interface AgentPathStep {\n /** Agent class name as exported by the Worker. */\n className: string;\n /** Logical Agent instance name. */\n name: string;\n}\n\nexport interface BuildAgentPathOptions {\n /** Top-level route prefix. Must match `routeAgentRequest`; defaults to `agents`. */\n prefix?: string;\n /** Pathname suffix appended after the destination Agent identity. */\n leafPath?: string;\n /** Root Durable Object binding name, when it differs from the root class name. */\n rootBinding?: string;\n}\n\nfunction validateLeafPath(leafPath: string): string {\n const normalized = leafPath.startsWith(\"/\") ? leafPath : `/${leafPath}`;\n const parsed = new URL(normalized, \"https://agents.invalid\");\n if (\n normalized.includes(\"//\") ||\n (normalized.length > 1 && normalized.endsWith(\"/\")) ||\n parsed.pathname !== normalized ||\n parsed.search ||\n parsed.hash\n ) {\n throw new Error(\n `Cannot build an Agent path for leaf path ${JSON.stringify(leafPath)} because it is not a stable pathname.`\n );\n }\n return normalized;\n}\n\nfunction validateRoutingPrefix(prefix: string): string {\n const prefixParts = prefix.split(\"/\");\n const rawPath = `/${prefix}/leaf`;\n const parsed = new URL(rawPath, \"https://agents.invalid\");\n if (\n prefixParts.some(\n (part) => !part || part === \".\" || part === \"..\" || part === SUB_PREFIX\n ) ||\n parsed.pathname !== rawPath ||\n parsed.search ||\n parsed.hash\n ) {\n throw new Error(\n `Cannot build an Agent path for routing prefix ${JSON.stringify(prefix)} because it is not externally routable.`\n );\n }\n return prefix;\n}\n\nfunction encodeAgentClassName(className: string): string {\n const segment = camelCaseToKebabCase(className);\n if (segment === SUB_PREFIX) {\n throw new Error(\n `Cannot build an Agent path for Agent class name ${JSON.stringify(className)} because ${JSON.stringify(SUB_PREFIX)} is reserved.`\n );\n }\n\n const rawPath = `/root/${segment}/leaf`;\n const parsed = new URL(rawPath, \"https://agents.invalid\");\n const parts = parsed.pathname.split(\"/\");\n if (\n !segment ||\n parsed.pathname !== rawPath ||\n parsed.search ||\n parsed.hash ||\n parts.length !== 4 ||\n parts[2] !== segment\n ) {\n throw new Error(\n `Cannot build an Agent path for Agent class name ${JSON.stringify(className)} because it is not externally routable.`\n );\n }\n return segment;\n}\n\nfunction encodeChildAgentName(name: string): string {\n if (!name || name === \".\" || name === \"..\" || name.includes(\"\\0\")) {\n throw new Error(\n `Cannot build an Agent path for child Agent name ${JSON.stringify(name)} because it is not externally routable.`\n );\n }\n try {\n return encodeURIComponent(name);\n } catch {\n throw new Error(\n `Cannot build an Agent path for child Agent name ${JSON.stringify(name)} because it is not valid Unicode.`\n );\n }\n}\n\nfunction validateRootAgentName(name: string): string {\n if (name === SUB_PREFIX) {\n throw new Error(\n `Cannot build an Agent path for root Agent name ${JSON.stringify(name)} because ${JSON.stringify(SUB_PREFIX)} is reserved.`\n );\n }\n\n const rawPath = `/root/${name}/leaf`;\n const parsed = new URL(rawPath, \"https://agents.invalid\");\n const parts = parsed.pathname.split(\"/\");\n if (\n !name ||\n parsed.pathname !== rawPath ||\n parsed.search ||\n parsed.hash ||\n parts.length !== 4 ||\n parts[2] !== name\n ) {\n throw new Error(\n `Cannot build an Agent path for root Agent name ${JSON.stringify(name)} because it is not externally routable.`\n );\n }\n return name;\n}\n\nfunction serializeSubAgentPath(\n path: ReadonlyArray<AgentPathStep>,\n leafPath: string | undefined,\n validate: boolean\n): string {\n if (path.length === 0) return leafPath ?? \"\";\n\n const segments = path.flatMap((child) => [\n SUB_PREFIX,\n validate\n ? encodeAgentClassName(child.className)\n : camelCaseToKebabCase(child.className),\n validate ? encodeChildAgentName(child.name) : encodeURIComponent(child.name)\n ]);\n const subPath = segments.join(\"/\");\n if (!leafPath) return subPath;\n const normalizedLeaf = leafPath.startsWith(\"/\") ? leafPath : `/${leafPath}`;\n return `${subPath}${normalizedLeaf}`;\n}\n\n/** @internal Build the strictly validated path tail for sub-agent routing. */\nexport function buildSubAgentPath(\n path: ReadonlyArray<AgentPathStep>,\n leafPath?: string\n): string {\n return serializeSubAgentPath(path, leafPath, true);\n}\n\n/** @internal Preserve React's tolerant path composition for disabled placeholders. */\nexport function buildSubAgentPathUnchecked(\n path: ReadonlyArray<AgentPathStep>,\n leafPath?: string\n): string {\n return serializeSubAgentPath(path, leafPath, false);\n}\n\n/**\n * Build the canonical pathname for a root Agent or nested sub-agent.\n *\n * The address is root-first and accepts `Agent#selfPath`. Pass\n * `rootBinding` when the root Durable Object binding and class names differ.\n */\nexport function buildAgentPath(\n path: ReadonlyArray<AgentPathStep>,\n options: BuildAgentPathOptions = {}\n): string {\n const [root, ...children] = path;\n if (!root) {\n throw new Error(\"Agent path must contain at least one step.\");\n }\n\n const rootPath = [\n validateRoutingPrefix(options.prefix ?? \"agents\"),\n encodeAgentClassName(options.rootBinding ?? root.className),\n validateRootAgentName(root.name)\n ].join(\"/\");\n const leafPath = options.leafPath\n ? validateLeafPath(options.leafPath)\n : undefined;\n if (children.length === 0) {\n return `/${rootPath}${leafPath ?? \"\"}`;\n }\n return `/${rootPath}/${buildSubAgentPath(children, leafPath)}`;\n}\n\n/** Build an absolute URL for a root Agent or nested sub-agent. */\nexport function buildAgentUrl(\n origin: string | URL,\n path: ReadonlyArray<AgentPathStep>,\n options: BuildAgentPathOptions = {}\n): URL {\n let base: URL;\n try {\n base = new URL(origin.toString());\n } catch {\n throw new Error(`Invalid Agent URL origin ${JSON.stringify(origin)}.`);\n }\n\n if (\n ![\"http:\", \"https:\", \"ws:\", \"wss:\"].includes(base.protocol) ||\n base.username ||\n base.password ||\n base.pathname !== \"/\" ||\n base.search ||\n base.hash\n ) {\n throw new Error(\n `Invalid Agent URL origin ${JSON.stringify(origin.toString())}. Pass an HTTP(S) or WS(S) origin without credentials, a pathname, query, or fragment.`\n );\n }\n\n return new URL(buildAgentPath(path, options), base);\n}\n\nexport interface SubAgentPathMatch {\n /** CamelCase class name of the child, as it appears in `ctx.exports`. */\n childClass: string;\n /** URL-decoded child name. */\n childName: string;\n /**\n * Request path to forward to the child, with the\n * `/sub/{class}/{name}` segment stripped. Always begins with `/`;\n * may itself contain further `/sub/...` markers when a\n * recursively nested sub-agent is being routed.\n */\n remainingPath: string;\n}\n\n/**\n * Parse a URL and extract the first `/sub/{class}/{name}` segment,\n * if any. Recursive nesting is handled naturally: callers parse one\n * level at a time; the child then parses its own URL (which still\n * contains any deeper `/sub/...` markers).\n *\n * Names are URL-decoded. Classes are kebab-to-CamelCase converted\n * via a best-effort match against a provided lookup — pass\n * `ctx.exports` keys to get exact CamelCase; pass `undefined` for\n * a tolerant conversion without validation.\n *\n * Returns `null` when the URL doesn't contain the marker at a\n * recognized position, or when the marker has no following\n * class+name pair.\n */\nexport function parseSubAgentPath(\n url: string,\n options?: {\n /** CamelCase class names to match against (usually `ctx.exports` keys). */\n knownClasses?: readonly string[];\n }\n): SubAgentPathMatch | null {\n const pathname = new URL(url).pathname;\n const parts = pathname.split(\"/\").filter(Boolean);\n\n // Walk every occurrence of the `sub` segment — a plain\n // `indexOf(SUB_PREFIX)` would mis-match when the literal token\n // appears earlier in the URL (parent instance name == \"sub\", a\n // `basePath` segment that happens to be \"sub\", etc). We return\n // the first position where `parts[i+1]` resolves to a valid\n // class, which pins the real parent↔child boundary.\n for (let i = 0; i < parts.length; i++) {\n if (parts[i] !== SUB_PREFIX) continue;\n if (i + 2 >= parts.length) continue;\n\n const classSegment = parts[i + 1];\n const nameSegment = parts[i + 2];\n\n const childClass = resolveClassName(classSegment, options?.knownClasses);\n if (!childClass) continue;\n\n let childName: string;\n try {\n childName = decodeURIComponent(nameSegment);\n } catch {\n continue;\n }\n\n const remainingParts = parts.slice(i + 3);\n const remainingPath =\n remainingParts.length > 0 ? \"/\" + remainingParts.join(\"/\") : \"/\";\n\n return { childClass, childName, remainingPath };\n }\n\n return null;\n}\n\n/**\n * Best-effort kebab-to-CamelCase match. If `knownClasses` is\n * provided, returns the matching CamelCase entry (or null if no\n * match). If not, performs a naive kebab→CamelCase conversion.\n */\nfunction resolveClassName(\n segment: string,\n knownClasses?: readonly string[]\n): string | null {\n if (knownClasses) {\n const match = knownClasses.find(\n (name) => camelCaseToKebabCase(name) === segment\n );\n return match ?? null;\n }\n return segment\n .split(\"-\")\n .map((s) => s.charAt(0).toUpperCase() + s.slice(1))\n .join(\"\");\n}\n\n// ── routeSubAgentRequest ───────────────────────────────────────────\n\n/**\n * Minimal parent-side shape that `routeSubAgentRequest` relies on:\n * something fetchable (a DO stub, a sub-agent stub, etc.).\n *\n * @internal\n */\ninterface FetchableParent {\n fetch(req: Request): Promise<Response>;\n}\n\n/**\n * Route a request into a sub-agent via its parent DO.\n *\n * Use this in a custom fetch handler when your URL shape doesn't\n * match the `/agents/{class}/{name}` default — you identify and\n * fetch the parent yourself, then let this helper parse the\n * `/sub/{child}/...` tail and forward it.\n *\n * Runs `onBeforeSubAgent` on the parent DO (authorization / request\n * mutation / short-circuit response).\n *\n * For the default `/agents/...` URL shape, use `routeAgentRequest`\n * instead — it handles the parent lookup and this dispatch in one\n * call.\n *\n * @example\n * ```ts\n * export default {\n * async fetch(req, env) {\n * const { parentName, rest } = myCustomParse(req.url);\n * const parent = await getAgentByName(env.Inbox, parentName);\n * return routeSubAgentRequest(req, parent, { fromPath: rest });\n * }\n * };\n * ```\n *\n * @experimental The API surface may change before stabilizing.\n */\nexport async function routeSubAgentRequest(\n req: Request,\n parent: unknown,\n options?: {\n /**\n * Path to route on. Defaults to `req.url`'s pathname. Useful\n * when your outer URL is custom (e.g. `/api/v1/...`) and you\n * want to route the sub-agent tail without rewriting the\n * Request first.\n */\n fromPath?: string;\n }\n): Promise<Response> {\n // We don't know the parent's ctx.exports from here, so parse with\n // a permissive resolver. If the class doesn't exist, the parent's\n // bridge will 404. This lets us keep the helper self-contained.\n const pathForParsing = options?.fromPath\n ? `http://placeholder${options.fromPath.startsWith(\"/\") ? \"\" : \"/\"}${options.fromPath}`\n : req.url;\n\n const match = parseSubAgentPath(pathForParsing);\n if (!match) {\n return new Response(\"Sub-agent path not found in request URL\", {\n status: 400\n });\n }\n\n // Hand the request to the parent so `onBeforeSubAgent` fires in\n // the parent's isolate. The parent's `fetch` handler recognizes\n // the marker internally — we preserve the original request URL\n // (possibly rewritten by `fromPath`) so the parent's parse sees\n // the same match.\n //\n // Key subtlety: when rewriting the pathname via `fromPath`, we\n // mutate the *original* URL's pathname instead of constructing a\n // new URL from scratch. `new URL(\"/path\", baseWithQuery)` discards\n // the base's search; we want the caller's query params (e.g. auth\n // tokens, PartySocket's `_pk=...` handshake key) to survive.\n // Mirrors how `_cf_forwardToFacet` rewrites only pathname when\n // handing off to the child facet. If `fromPath` itself contains a\n // `?query` segment, that overrides the original.\n const forwardUrl =\n options?.fromPath !== undefined\n ? rewritePathname(req.url, options.fromPath)\n : req.url;\n const forwardInit: RequestInit = {\n method: req.method,\n headers: new Headers(req.headers)\n };\n // Stream the body through rather than buffering it — see #2015. This\n // helper runs in the caller's isolate, but the same request then hits\n // `_cf_forwardToFacet` on the parent, so buffering here would put a\n // second unbounded copy in front of the child.\n if (req.body && req.method !== \"GET\" && req.method !== \"HEAD\") {\n forwardInit.body = req.body;\n }\n const forwardReq = new Request(forwardUrl, forwardInit);\n\n return (parent as FetchableParent).fetch(forwardReq);\n}\n\n/**\n * Replace a URL's pathname (and optionally its search) while\n * preserving every other component. Matches how `_cf_forwardToFacet`\n * forwards requests — pathname is the only thing that changes by\n * default; if the replacement path carries its own query string,\n * that wins.\n */\nfunction rewritePathname(url: string, fromPath: string): string {\n const normalized = fromPath.startsWith(\"/\") ? fromPath : `/${fromPath}`;\n const queryIdx = normalized.indexOf(\"?\");\n const pathOnly = queryIdx >= 0 ? normalized.slice(0, queryIdx) : normalized;\n const querySuffix = queryIdx >= 0 ? normalized.slice(queryIdx) : \"\";\n\n const rewritten = new URL(url);\n rewritten.pathname = pathOnly;\n if (querySuffix) {\n rewritten.search = querySuffix; // URL setter keeps the `?` prefix\n }\n return rewritten.toString();\n}\n\n// ── getSubAgentByName ──────────────────────────────────────────────\n\n/**\n * Parent-side RPC bridge shape that `getSubAgentByName` relies on.\n *\n * @internal\n */\ninterface SubAgentInvokeEndpoint {\n _cf_invokeSubAgent(\n className: string,\n name: string,\n method: string,\n args: unknown[]\n ): Promise<unknown>;\n}\n\n/**\n * Get a typed RPC stub for a sub-agent from outside the parent DO.\n *\n * The returned stub proxies method calls through the parent via a\n * stateless per-call bridge (caller → parent → facet), so each\n * method invocation costs one extra RPC hop. Works across parent\n * hibernation — no cached references to go stale.\n *\n * Limitations:\n * - RPC methods only. `.fetch()` is not supported (will throw).\n * Use `routeSubAgentRequest` for external HTTP/WS.\n * - Arguments and return values must be structured-cloneable,\n * same as any DO RPC call.\n * - Does not run `onBeforeSubAgent` on the parent — analogous to\n * `getAgentByName` not running `onBeforeConnect`. The caller is\n * assumed to have performed whatever access checks are needed.\n *\n * @example\n * ```ts\n * const inbox = await getAgentByName(env.MyInbox, userId);\n * const chat = await getSubAgentByName(inbox, MyChat, chatId);\n * await chat.addMessage({ role: \"user\", content: \"hi\" });\n * ```\n *\n * @experimental The API surface may change before stabilizing.\n */\nexport async function getSubAgentByName<T extends Agent>(\n parent: unknown,\n cls: SubAgentClass<T>,\n name: string\n): Promise<SubAgentStub<T>> {\n if (name.includes(\"\\0\")) {\n throw new Error(\n `Sub-agent name contains null character (\\\\0), which is reserved.`\n );\n }\n\n const bridge = parent as SubAgentInvokeEndpoint;\n const className = cls?.name;\n if (!className) {\n throw new Error(\n `getSubAgentByName: could not determine class name from ${cls}. ` +\n `Ensure you are passing the class constructor (e.g. getSubAgentByName(parent, MyChat, name)), not a string or undefined.`\n );\n }\n\n return new Proxy(\n {},\n {\n get(_target, prop) {\n // JS / runtime / test-framework probes (thenable check,\n // serialization, inspection, matcher duck-typing) must NOT\n // dispatch an RPC — returning `undefined` is the contract\n // the inner `createStubProxy` uses for `useAgent` stubs.\n // Without this guard, `JSON.stringify(stub)`, `console.log`,\n // Vitest matchers, and `await stub` would all trigger bogus\n // `_cf_invokeSubAgent` calls that fail with \"Method not found\".\n if (isInternalJsStubProp(prop)) return undefined;\n if (typeof prop !== \"string\") return undefined;\n // `.fetch` gets a dedicated error so users who try to use\n // the stub for HTTP/WS get a helpful pointer.\n if (prop === \"fetch\") {\n return () => {\n throw new Error(\n `getSubAgentByName returns an RPC-only stub — .fetch() is ` +\n `not supported. Use routeSubAgentRequest() or the ` +\n `/agents/{parent}/{name}/sub/{child}/{name} URL for ` +\n `external HTTP/WS routing.`\n );\n };\n }\n return async (...args: unknown[]) =>\n bridge._cf_invokeSubAgent(className, name, prop, args);\n }\n }\n ) as SubAgentStub<T>;\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
//#region src/chat/wire-types.ts
|
|
2
|
+
/**
|
|
3
|
+
* Enum for message types to improve type safety and maintainability
|
|
4
|
+
*/
|
|
5
|
+
let MessageType = /* @__PURE__ */ function(MessageType) {
|
|
6
|
+
MessageType["CF_AGENT_CHAT_MESSAGES"] = "cf_agent_chat_messages";
|
|
7
|
+
MessageType["CF_AGENT_USE_CHAT_REQUEST"] = "cf_agent_use_chat_request";
|
|
8
|
+
MessageType["CF_AGENT_USE_CHAT_RESPONSE"] = "cf_agent_use_chat_response";
|
|
9
|
+
MessageType["CF_AGENT_CHAT_CLEAR"] = "cf_agent_chat_clear";
|
|
10
|
+
MessageType["CF_AGENT_CHAT_REQUEST_CANCEL"] = "cf_agent_chat_request_cancel";
|
|
11
|
+
/** Sent by server when client connects and there's an active stream to resume */
|
|
12
|
+
MessageType["CF_AGENT_STREAM_RESUMING"] = "cf_agent_stream_resuming";
|
|
13
|
+
/** Sent by client to acknowledge stream resuming notification and request chunks */
|
|
14
|
+
MessageType["CF_AGENT_STREAM_RESUME_ACK"] = "cf_agent_stream_resume_ack";
|
|
15
|
+
/** Sent by client after message handler is ready, requesting stream resume check */
|
|
16
|
+
MessageType["CF_AGENT_STREAM_RESUME_REQUEST"] = "cf_agent_stream_resume_request";
|
|
17
|
+
/** Sent by server when client requests resume but no active stream exists */
|
|
18
|
+
MessageType["CF_AGENT_STREAM_RESUME_NONE"] = "cf_agent_stream_resume_none";
|
|
19
|
+
/**
|
|
20
|
+
* Sent by server when a turn is accepted but its resumable stream has not
|
|
21
|
+
* started yet (queued / debouncing / waiting on MCP / async setup). Tells a
|
|
22
|
+
* reconnecting client to keep waiting rather than resolve its resume probe to
|
|
23
|
+
* "no stream". Resolved by a later `CF_AGENT_STREAM_RESUMING` (stream started)
|
|
24
|
+
* or `CF_AGENT_STREAM_RESUME_NONE` (settled without streaming). See #1784.
|
|
25
|
+
*/
|
|
26
|
+
MessageType["CF_AGENT_STREAM_PENDING"] = "cf_agent_stream_pending";
|
|
27
|
+
/** Client sends tool result to server (for client-side tools) */
|
|
28
|
+
MessageType["CF_AGENT_TOOL_RESULT"] = "cf_agent_tool_result";
|
|
29
|
+
/** Server notifies client that a message was updated (e.g., tool result applied) */
|
|
30
|
+
MessageType["CF_AGENT_MESSAGE_UPDATED"] = "cf_agent_message_updated";
|
|
31
|
+
/** Client sends tool approval response to server (for tools with needsApproval) */
|
|
32
|
+
MessageType["CF_AGENT_TOOL_APPROVAL"] = "cf_agent_tool_approval";
|
|
33
|
+
/**
|
|
34
|
+
* Server→client progress hint: a durable chat turn is being recovered
|
|
35
|
+
* (interrupted by a deploy/eviction or a stream-stall watchdog abort and now
|
|
36
|
+
* resuming). Sent when a recovery continuation is scheduled and cleared on
|
|
37
|
+
* every terminal outcome. (`@cloudflare/think` also replays it on connect;
|
|
38
|
+
* `@cloudflare/ai-chat` broadcasts the live signal only — see #1645.)
|
|
39
|
+
* Backward-compatible — clients that don't understand it ignore it. See #1620.
|
|
40
|
+
*/
|
|
41
|
+
MessageType["CF_AGENT_CHAT_RECOVERING"] = "cf_agent_chat_recovering";
|
|
42
|
+
return MessageType;
|
|
43
|
+
}({});
|
|
44
|
+
//#endregion
|
|
45
|
+
export { MessageType as t };
|
|
46
|
+
|
|
47
|
+
//# sourceMappingURL=wire-types-CnMt6_HR.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wire-types-CnMt6_HR.js","names":[],"sources":["../src/chat/wire-types.ts"],"sourcesContent":["import type { JSONSchema7, UIMessage } from \"ai\";\nimport type { StreamResumeNoneReason } from \"./protocol\";\n\n/**\n * Enum for message types to improve type safety and maintainability\n */\nexport enum MessageType {\n CF_AGENT_CHAT_MESSAGES = \"cf_agent_chat_messages\",\n CF_AGENT_USE_CHAT_REQUEST = \"cf_agent_use_chat_request\",\n CF_AGENT_USE_CHAT_RESPONSE = \"cf_agent_use_chat_response\",\n CF_AGENT_CHAT_CLEAR = \"cf_agent_chat_clear\",\n CF_AGENT_CHAT_REQUEST_CANCEL = \"cf_agent_chat_request_cancel\",\n\n /** Sent by server when client connects and there's an active stream to resume */\n CF_AGENT_STREAM_RESUMING = \"cf_agent_stream_resuming\",\n /** Sent by client to acknowledge stream resuming notification and request chunks */\n CF_AGENT_STREAM_RESUME_ACK = \"cf_agent_stream_resume_ack\",\n /** Sent by client after message handler is ready, requesting stream resume check */\n CF_AGENT_STREAM_RESUME_REQUEST = \"cf_agent_stream_resume_request\",\n /** Sent by server when client requests resume but no active stream exists */\n CF_AGENT_STREAM_RESUME_NONE = \"cf_agent_stream_resume_none\",\n /**\n * Sent by server when a turn is accepted but its resumable stream has not\n * started yet (queued / debouncing / waiting on MCP / async setup). Tells a\n * reconnecting client to keep waiting rather than resolve its resume probe to\n * \"no stream\". Resolved by a later `CF_AGENT_STREAM_RESUMING` (stream started)\n * or `CF_AGENT_STREAM_RESUME_NONE` (settled without streaming). See #1784.\n */\n CF_AGENT_STREAM_PENDING = \"cf_agent_stream_pending\",\n\n /** Client sends tool result to server (for client-side tools) */\n CF_AGENT_TOOL_RESULT = \"cf_agent_tool_result\",\n /** Server notifies client that a message was updated (e.g., tool result applied) */\n CF_AGENT_MESSAGE_UPDATED = \"cf_agent_message_updated\",\n /** Client sends tool approval response to server (for tools with needsApproval) */\n CF_AGENT_TOOL_APPROVAL = \"cf_agent_tool_approval\",\n\n /**\n * Server→client progress hint: a durable chat turn is being recovered\n * (interrupted by a deploy/eviction or a stream-stall watchdog abort and now\n * resuming). Sent when a recovery continuation is scheduled and cleared on\n * every terminal outcome. (`@cloudflare/think` also replays it on connect;\n * `@cloudflare/ai-chat` broadcasts the live signal only — see #1645.)\n * Backward-compatible — clients that don't understand it ignore it. See #1620.\n */\n CF_AGENT_CHAT_RECOVERING = \"cf_agent_chat_recovering\"\n}\n\n/**\n * Types of messages sent from the Agent to clients\n */\nexport type OutgoingMessage<ChatMessage extends UIMessage = UIMessage> =\n | {\n /** Indicates this message is a command to clear chat history */\n type: MessageType.CF_AGENT_CHAT_CLEAR;\n }\n | {\n /** Indicates this message contains updated chat messages */\n type: MessageType.CF_AGENT_CHAT_MESSAGES;\n /** Array of chat messages */\n messages: readonly ChatMessage[];\n }\n | {\n /** Indicates this message is a response to a chat request */\n type: MessageType.CF_AGENT_USE_CHAT_RESPONSE;\n /** Unique ID of the request this response corresponds to */\n id: string;\n /** Content body of the response */\n body: string;\n /** Whether this is the final chunk of the response */\n done: boolean;\n /** Whether this response contains an error */\n error?: boolean;\n /** Whether this is a continuation (append to last assistant message) */\n continuation?: boolean;\n /** Whether this chunk is being replayed from storage (stream resumption) */\n replay?: boolean;\n /** Signals that replay of stored chunks is complete (stream is still active) */\n replayComplete?: boolean;\n }\n | {\n /** Indicates the server is resuming an active stream */\n type: MessageType.CF_AGENT_STREAM_RESUMING;\n /** The request ID of the stream being resumed */\n id: string;\n /** Present when this offer directly answers a client resume probe. */\n probeId?: string;\n }\n | {\n /** Server notifies client that a message was updated (e.g., tool result applied) */\n type: MessageType.CF_AGENT_MESSAGE_UPDATED;\n /** The updated message */\n message: ChatMessage;\n }\n | {\n /** Server responds to a resume request with no stream for this client. */\n type: MessageType.CF_AGENT_STREAM_RESUME_NONE;\n /**\n * Why no stream was offered. Only `idle` proves global inactivity;\n * omitted by older servers and by non-authoritative delayed releases.\n */\n reason?: StreamResumeNoneReason;\n /** Correlates an authoritative response to its client resume probe. */\n probeId?: string;\n }\n | {\n /**\n * Server signals an accepted turn whose resumable stream has not started\n * yet — the client should keep waiting for `STREAM_RESUMING` (or a later\n * `STREAM_RESUME_NONE`) rather than give up. See #1784.\n */\n type: MessageType.CF_AGENT_STREAM_PENDING;\n /** The accepted request id, when known. */\n id?: string;\n /** Correlates a direct keep-waiting response to its client probe. */\n probeId?: string;\n }\n | {\n /**\n * Progress hint: a durable chat turn is being recovered (`recovering:\n * true`) or recovery has resolved (`recovering: false`). Purely advisory;\n * a client renders a \"recovering…\" indicator while true.\n */\n type: MessageType.CF_AGENT_CHAT_RECOVERING;\n /** Whether recovery is in progress (true) or has resolved (false). */\n recovering: boolean;\n /** The recovery-root request id of the turn being recovered, if known. */\n id?: string;\n };\n\n/**\n * Types of messages sent from clients to the Agent\n */\nexport type IncomingMessage<ChatMessage extends UIMessage = UIMessage> =\n | {\n /** Indicates this message is a command to clear chat history */\n type: MessageType.CF_AGENT_CHAT_CLEAR;\n }\n | {\n /** Indicates this message is a request to the chat API */\n type: MessageType.CF_AGENT_USE_CHAT_REQUEST;\n /** Unique ID for this request */\n id: string;\n /** Request initialization options */\n init: Pick<\n RequestInit,\n | \"method\"\n | \"keepalive\"\n | \"headers\"\n | \"body\"\n | \"redirect\"\n | \"integrity\"\n | \"credentials\"\n | \"mode\"\n | \"referrer\"\n | \"referrerPolicy\"\n | \"window\"\n >;\n }\n | {\n /** Indicates this message contains updated chat messages */\n type: MessageType.CF_AGENT_CHAT_MESSAGES;\n /** Array of chat messages */\n messages: ChatMessage[];\n }\n | {\n /** Indicates the user wants to stop generation of this message */\n type: MessageType.CF_AGENT_CHAT_REQUEST_CANCEL;\n id: string;\n }\n | {\n /** Client acknowledges stream resuming notification and is ready to receive chunks */\n type: MessageType.CF_AGENT_STREAM_RESUME_ACK;\n /** The request ID of the stream being resumed */\n id: string;\n }\n | {\n /** Client requests stream resume check after message handler is registered */\n type: MessageType.CF_AGENT_STREAM_RESUME_REQUEST;\n /** Opaque correlation id echoed by direct server responses. */\n probeId?: string;\n }\n | {\n /** Client sends tool result to server (for client-side tools) */\n type: MessageType.CF_AGENT_TOOL_RESULT;\n /** The tool call ID this result is for */\n toolCallId: string;\n /** The name of the tool */\n toolName: string;\n /** The output from the tool execution */\n output: unknown;\n /** Override the tool part state (e.g. \"output-error\" for custom denial) */\n state?: \"output-available\" | \"output-error\";\n /** Error message when state is \"output-error\" */\n errorText?: string;\n /** Whether server should auto-continue the conversation after applying result */\n autoContinue?: boolean;\n /** Client tool schemas for continuation (client is source of truth) */\n clientTools?: Array<{\n name: string;\n description?: string;\n parameters?: JSONSchema7;\n }>;\n }\n | {\n /** Client sends tool approval response to server (for tools with needsApproval) */\n type: MessageType.CF_AGENT_TOOL_APPROVAL;\n /** The tool call ID this approval is for */\n toolCallId: string;\n /** Whether the tool execution was approved */\n approved: boolean;\n /** Whether server should auto-continue the conversation after applying approval */\n autoContinue?: boolean;\n };\n"],"mappings":";;;;AAMA,IAAY,cAAL,yBAAA,aAAA;CACL,YAAA,4BAAA;CACA,YAAA,+BAAA;CACA,YAAA,gCAAA;CACA,YAAA,yBAAA;CACA,YAAA,kCAAA;;CAGA,YAAA,8BAAA;;CAEA,YAAA,gCAAA;;CAEA,YAAA,oCAAA;;CAEA,YAAA,iCAAA;;;;;;;;CAQA,YAAA,6BAAA;;CAGA,YAAA,0BAAA;;CAEA,YAAA,8BAAA;;CAEA,YAAA,4BAAA;;;;;;;;;CAUA,YAAA,8BAAA;;AACF,EAAA,CAAA,CAAA"}
|
package/dist/workflow-types.d.ts
CHANGED
|
@@ -1,29 +1,29 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
} from "./
|
|
2
|
+
At as WorkflowRejectedError,
|
|
3
|
+
Ct as WorkflowErrorCallback,
|
|
4
|
+
Dt as WorkflowPage,
|
|
5
|
+
Et as WorkflowInfo,
|
|
6
|
+
Mt as WorkflowTrackingRow,
|
|
7
|
+
Ot as WorkflowProgressCallback,
|
|
8
|
+
St as WorkflowCompleteCallback,
|
|
9
|
+
Tt as WorkflowEventPayload,
|
|
10
|
+
_t as RunWorkflowOptions,
|
|
11
|
+
bt as WorkflowCallbackBase,
|
|
12
|
+
dt as AgentWorkflowOrigin,
|
|
13
|
+
ft as AgentWorkflowParams,
|
|
14
|
+
gt as DefaultProgress,
|
|
15
|
+
ht as ApprovalEventPayload,
|
|
16
|
+
jt as WorkflowStatus,
|
|
17
|
+
kt as WorkflowQueryCriteria,
|
|
18
|
+
lt as AgentWorkflowEvent,
|
|
19
|
+
mt as AgentWorkflowStep,
|
|
20
|
+
pt as AgentWorkflowPathStep,
|
|
21
|
+
ut as AgentWorkflowInternalParams,
|
|
22
|
+
vt as WaitForApprovalOptions,
|
|
23
|
+
wt as WorkflowEventCallback,
|
|
24
|
+
xt as WorkflowCallbackType,
|
|
25
|
+
yt as WorkflowCallback
|
|
26
|
+
} from "./agent-routing-CnkaHb-v.js";
|
|
27
27
|
export {
|
|
28
28
|
AgentWorkflowEvent,
|
|
29
29
|
AgentWorkflowInternalParams,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workflow-types.js","names":[],"sources":["../src/workflow-types.ts"],"sourcesContent":["/**\n * Workflow integration types for Agents\n *\n * These types provide seamless integration between Cloudflare Agents\n * and Cloudflare Workflows for durable, multi-step background processing.\n *\n * Note: This file is kept separate from workflows.ts to avoid circular dependencies.\n * Both index.ts (Agent class) and workflows.ts (AgentWorkflow class) import from here.\n */\n\nimport type {\n WorkflowEvent,\n WorkflowStep,\n WorkflowSleepDuration\n} from \"cloudflare:workers\";\n\nexport type AgentWorkflowPathStep = { className: string; name: string };\n\nexport type AgentWorkflowOrigin =\n | {\n kind: \"agent\";\n version: 1;\n /** Environment binding name for the top-level Agent namespace */\n binding: string;\n /** Name/ID of the top-level Agent */\n name: string;\n }\n | {\n kind: \"facet\";\n version: 1;\n /** Environment binding name for the root Agent namespace */\n rootBinding: string;\n /** Root-first path to the originating facet, including itself */\n path: AgentWorkflowPathStep[];\n };\n\n/**\n * Type alias for WorkflowEvent in AgentWorkflow context.\n * Identical to WorkflowEvent - provided for naming consistency with AgentWorkflowStep.\n */\nexport type AgentWorkflowEvent<Params = unknown> = WorkflowEvent<Params>;\n\n/**\n * Extended WorkflowStep with durable Agent communication methods.\n * All added methods on this interface are durable - they're idempotent and won't\n * repeat on workflow retry.\n */\nexport interface AgentWorkflowStep extends WorkflowStep {\n /**\n * Report successful completion to the Agent (durable).\n * Triggers onWorkflowComplete() on the Agent.\n * @param result - Optional result data\n */\n reportComplete<T = unknown>(result?: T): Promise<void>;\n\n /**\n * Report an error to the Agent (durable).\n * Triggers onWorkflowError() on the Agent.\n * @param error - Error or error message\n */\n reportError(error: Error | string): Promise<void>;\n\n /**\n * Send a custom event to the Agent (durable).\n * Triggers onWorkflowEvent() on the Agent.\n * @param event - Custom event payload\n */\n sendEvent<T = unknown>(event: T): Promise<void>;\n\n /**\n * Update the Agent's state entirely (durable).\n * This will replace the Agent's state and broadcast to all connected clients.\n * @param state - New state to set\n */\n updateAgentState(state: unknown): Promise<void>;\n\n /**\n * Merge partial state into the Agent's existing state (durable).\n * Performs a shallow merge and broadcasts to all connected clients.\n * @param partialState - Partial state to merge\n */\n mergeAgentState(partialState: Record<string, unknown>): Promise<void>;\n\n /**\n * Reset the Agent's state to its initialState (durable).\n * Broadcasts the reset state to all connected clients.\n */\n resetAgentState(): Promise<void>;\n}\n\n/**\n * Internal parameters injected by runWorkflow() to identify the originating Agent\n */\nexport type AgentWorkflowInternalParams = {\n /** Name/ID of the Agent that started this workflow */\n __agentName: string;\n /** Environment binding name for the Agent's namespace */\n __agentBinding: string;\n /** Workflow binding name (for callbacks) */\n __workflowName: string;\n /** Versioned origin identity for top-level Agents and sub-agent facets */\n __agentOrigin?: AgentWorkflowOrigin;\n};\n\n/**\n * Combined workflow params: user params + internal agent params\n */\nexport type AgentWorkflowParams<T = unknown> = T & AgentWorkflowInternalParams;\n\n/**\n * Workflow callback types for Agent-Workflow communication\n */\nexport type WorkflowCallbackType = \"progress\" | \"complete\" | \"error\" | \"event\";\n\n/**\n * Base callback structure sent from Workflow to Agent\n */\nexport type WorkflowCallbackBase = {\n /** Workflow binding name */\n workflowName: string;\n /** ID of the workflow instance */\n workflowId: string;\n /** Type of callback */\n type: WorkflowCallbackType;\n /** Timestamp when callback was sent */\n timestamp: number;\n};\n\n/**\n * Default progress type - covers common use cases.\n * Developers can define their own progress type for domain-specific needs.\n */\nexport type DefaultProgress = {\n /** Current step name */\n step?: string;\n /** Step/overall status */\n status?: \"pending\" | \"running\" | \"complete\" | \"error\";\n /** Human-readable message */\n message?: string;\n /** Progress percentage (0-1) */\n percent?: number;\n /** Allow additional custom fields */\n [key: string]: unknown;\n};\n\n/**\n * Progress callback - reports workflow progress with typed payload\n */\nexport type WorkflowProgressCallback<P = DefaultProgress> =\n WorkflowCallbackBase & {\n type: \"progress\";\n /** Typed progress data */\n progress: P;\n };\n\n/**\n * Complete callback - workflow finished successfully\n */\nexport type WorkflowCompleteCallback = WorkflowCallbackBase & {\n type: \"complete\";\n /** Result of the workflow */\n result?: unknown;\n};\n\n/**\n * Error callback - workflow encountered an error\n */\nexport type WorkflowErrorCallback = WorkflowCallbackBase & {\n type: \"error\";\n /** Error message */\n error: string;\n};\n\n/**\n * Event callback - custom event from workflow\n */\nexport type WorkflowEventCallback = WorkflowCallbackBase & {\n type: \"event\";\n /** Custom event payload */\n event: unknown;\n};\n\n/**\n * Union of all callback types\n */\nexport type WorkflowCallback<P = DefaultProgress> =\n | WorkflowProgressCallback<P>\n | WorkflowCompleteCallback\n | WorkflowErrorCallback\n | WorkflowEventCallback;\n\n/**\n * Workflow status values - derived from Cloudflare's InstanceStatus\n */\nexport type WorkflowStatus = InstanceStatus[\"status\"];\n\n/**\n * Row structure for cf_agents_workflows tracking table\n */\nexport type WorkflowTrackingRow = {\n /** Internal row ID (UUID) */\n id: string;\n /** Cloudflare Workflow instance ID */\n workflow_id: string;\n /** Workflow binding name */\n workflow_name: string;\n /** Current workflow status */\n status: WorkflowStatus;\n /** JSON-serialized metadata for querying */\n metadata: string | null;\n /** Error name if workflow failed */\n error_name: string | null;\n /** Error message if workflow failed */\n error_message: string | null;\n /** Unix timestamp when workflow was created */\n created_at: number;\n /** Unix timestamp when workflow was last updated */\n updated_at: number;\n /** Unix timestamp when workflow completed (null if not complete) */\n completed_at: number | null;\n};\n\n/**\n * Options for runWorkflow()\n */\nexport type RunWorkflowOptions = {\n /** Custom workflow instance ID (auto-generated if not provided) */\n id?: string;\n /** Optional metadata for querying (stored as JSON) */\n metadata?: Record<string, unknown>;\n /** Agent binding name (auto-detected from class name if not provided) */\n agentBinding?: string;\n};\n\n/**\n * Event payload for sendWorkflowEvent()\n */\nexport type WorkflowEventPayload = {\n /** Event type name */\n type: string;\n /** Event payload data */\n payload: unknown;\n};\n\n/**\n * Parsed workflow tracking info returned by getWorkflow()\n */\nexport type WorkflowInfo = {\n /** Internal row ID */\n id: string;\n /** Cloudflare Workflow instance ID */\n workflowId: string;\n /** Workflow binding name */\n workflowName: string;\n /** Current workflow status */\n status: WorkflowStatus;\n /** Metadata (parsed from JSON) */\n metadata: Record<string, unknown> | null;\n /** Error info if workflow failed */\n error: { name: string; message: string } | null;\n /** When workflow was created */\n createdAt: Date;\n /** When workflow was last updated */\n updatedAt: Date;\n /** When workflow completed (null if not complete) */\n completedAt: Date | null;\n};\n\n/**\n * Criteria for querying tracked workflows\n */\nexport type WorkflowQueryCriteria = {\n /** Filter by status */\n status?: WorkflowStatus | WorkflowStatus[];\n /** Filter by workflow binding name */\n workflowName?: string;\n /** Filter by metadata key-value pairs (exact match) */\n metadata?: Record<string, string | number | boolean>;\n /** Limit number of results (default 50, max 100) */\n limit?: number;\n /** Order by created_at */\n orderBy?: \"asc\" | \"desc\";\n /** Cursor for pagination (from previous WorkflowPage.nextCursor) */\n cursor?: string;\n};\n\n/**\n * Paginated result from getWorkflows()\n */\nexport type WorkflowPage = {\n /** Workflows for this page */\n workflows: WorkflowInfo[];\n /** Total count of workflows matching the criteria (ignoring pagination) */\n total: number;\n /** Cursor for next page, or null if no more pages */\n nextCursor: string | null;\n};\n\n/**\n * Standard approval event payload used by approveWorkflow/rejectWorkflow\n */\nexport type ApprovalEventPayload = {\n /** Whether the workflow was approved */\n approved: boolean;\n /** Optional reason for approval/rejection */\n reason?: string;\n /** Optional additional metadata */\n metadata?: Record<string, unknown>;\n};\n\n/**\n * Options for waitForApproval()\n */\nexport type WaitForApprovalOptions = {\n /** Step name for waitForEvent (default: \"wait-for-approval\") */\n stepName?: string;\n /** Timeout duration (e.g., \"7 days\") */\n timeout?: WorkflowSleepDuration;\n /** Event type to wait for (default: \"approval\") */\n eventType?: string;\n};\n\n/**\n * Error thrown when a workflow is rejected via rejectWorkflow()\n */\nexport class WorkflowRejectedError extends Error {\n constructor(\n public readonly reason?: string,\n public readonly workflowId?: string\n ) {\n super(reason ? `Workflow rejected: ${reason}` : \"Workflow rejected\");\n this.name = \"WorkflowRejectedError\";\n }\n}\n"],"mappings":";;;;AAqUA,IAAa,wBAAb,cAA2C,MAAM;CAC/C,YACE,QACA,YACA;EACA,MAAM,SAAS,sBAAsB,WAAW,mBAAmB;EAHnD,KAAA,SAAA;EACA,KAAA,aAAA;EAGhB,KAAK,OAAO;CACd;AACF"}
|
|
1
|
+
{"version":3,"file":"workflow-types.js","names":[],"sources":["../src/workflow-types.ts"],"sourcesContent":["/**\n * Workflow integration types for Agents\n *\n * These types provide seamless integration between Cloudflare Agents\n * and Cloudflare Workflows for durable, multi-step background processing.\n *\n * Note: This file is kept separate from workflows.ts to avoid circular dependencies.\n * Both index.ts (Agent class) and workflows.ts (AgentWorkflow class) import from here.\n */\n\nimport type {\n WorkflowEvent,\n WorkflowStep,\n WorkflowSleepDuration\n} from \"cloudflare:workers\";\nimport type { AgentPathStep } from \"./sub-routing\";\n\nexport type AgentWorkflowPathStep = AgentPathStep;\n\nexport type AgentWorkflowOrigin =\n | {\n kind: \"agent\";\n version: 1;\n /** Environment binding name for the top-level Agent namespace */\n binding: string;\n /** Name/ID of the top-level Agent */\n name: string;\n }\n | {\n kind: \"facet\";\n version: 1;\n /** Environment binding name for the root Agent namespace */\n rootBinding: string;\n /** Root-first path to the originating facet, including itself */\n path: AgentWorkflowPathStep[];\n };\n\n/**\n * Type alias for WorkflowEvent in AgentWorkflow context.\n * Identical to WorkflowEvent - provided for naming consistency with AgentWorkflowStep.\n */\nexport type AgentWorkflowEvent<Params = unknown> = WorkflowEvent<Params>;\n\n/**\n * Extended WorkflowStep with durable Agent communication methods.\n * All added methods on this interface are durable - they're idempotent and won't\n * repeat on workflow retry.\n */\nexport interface AgentWorkflowStep extends WorkflowStep {\n /**\n * Report successful completion to the Agent (durable).\n * Triggers onWorkflowComplete() on the Agent.\n * @param result - Optional result data\n */\n reportComplete<T = unknown>(result?: T): Promise<void>;\n\n /**\n * Report an error to the Agent (durable).\n * Triggers onWorkflowError() on the Agent.\n * @param error - Error or error message\n */\n reportError(error: Error | string): Promise<void>;\n\n /**\n * Send a custom event to the Agent (durable).\n * Triggers onWorkflowEvent() on the Agent.\n * @param event - Custom event payload\n */\n sendEvent<T = unknown>(event: T): Promise<void>;\n\n /**\n * Update the Agent's state entirely (durable).\n * This will replace the Agent's state and broadcast to all connected clients.\n * @param state - New state to set\n */\n updateAgentState(state: unknown): Promise<void>;\n\n /**\n * Merge partial state into the Agent's existing state (durable).\n * Performs a shallow merge and broadcasts to all connected clients.\n * @param partialState - Partial state to merge\n */\n mergeAgentState(partialState: Record<string, unknown>): Promise<void>;\n\n /**\n * Reset the Agent's state to its initialState (durable).\n * Broadcasts the reset state to all connected clients.\n */\n resetAgentState(): Promise<void>;\n}\n\n/**\n * Internal parameters injected by runWorkflow() to identify the originating Agent\n */\nexport type AgentWorkflowInternalParams = {\n /** Name/ID of the Agent that started this workflow */\n __agentName: string;\n /** Environment binding name for the Agent's namespace */\n __agentBinding: string;\n /** Workflow binding name (for callbacks) */\n __workflowName: string;\n /** Versioned origin identity for top-level Agents and sub-agent facets */\n __agentOrigin?: AgentWorkflowOrigin;\n};\n\n/**\n * Combined workflow params: user params + internal agent params\n */\nexport type AgentWorkflowParams<T = unknown> = T & AgentWorkflowInternalParams;\n\n/**\n * Workflow callback types for Agent-Workflow communication\n */\nexport type WorkflowCallbackType = \"progress\" | \"complete\" | \"error\" | \"event\";\n\n/**\n * Base callback structure sent from Workflow to Agent\n */\nexport type WorkflowCallbackBase = {\n /** Workflow binding name */\n workflowName: string;\n /** ID of the workflow instance */\n workflowId: string;\n /** Type of callback */\n type: WorkflowCallbackType;\n /** Timestamp when callback was sent */\n timestamp: number;\n};\n\n/**\n * Default progress type - covers common use cases.\n * Developers can define their own progress type for domain-specific needs.\n */\nexport type DefaultProgress = {\n /** Current step name */\n step?: string;\n /** Step/overall status */\n status?: \"pending\" | \"running\" | \"complete\" | \"error\";\n /** Human-readable message */\n message?: string;\n /** Progress percentage (0-1) */\n percent?: number;\n /** Allow additional custom fields */\n [key: string]: unknown;\n};\n\n/**\n * Progress callback - reports workflow progress with typed payload\n */\nexport type WorkflowProgressCallback<P = DefaultProgress> =\n WorkflowCallbackBase & {\n type: \"progress\";\n /** Typed progress data */\n progress: P;\n };\n\n/**\n * Complete callback - workflow finished successfully\n */\nexport type WorkflowCompleteCallback = WorkflowCallbackBase & {\n type: \"complete\";\n /** Result of the workflow */\n result?: unknown;\n};\n\n/**\n * Error callback - workflow encountered an error\n */\nexport type WorkflowErrorCallback = WorkflowCallbackBase & {\n type: \"error\";\n /** Error message */\n error: string;\n};\n\n/**\n * Event callback - custom event from workflow\n */\nexport type WorkflowEventCallback = WorkflowCallbackBase & {\n type: \"event\";\n /** Custom event payload */\n event: unknown;\n};\n\n/**\n * Union of all callback types\n */\nexport type WorkflowCallback<P = DefaultProgress> =\n | WorkflowProgressCallback<P>\n | WorkflowCompleteCallback\n | WorkflowErrorCallback\n | WorkflowEventCallback;\n\n/**\n * Workflow status values - derived from Cloudflare's InstanceStatus\n */\nexport type WorkflowStatus = InstanceStatus[\"status\"];\n\n/**\n * Row structure for cf_agents_workflows tracking table\n */\nexport type WorkflowTrackingRow = {\n /** Internal row ID (UUID) */\n id: string;\n /** Cloudflare Workflow instance ID */\n workflow_id: string;\n /** Workflow binding name */\n workflow_name: string;\n /** Current workflow status */\n status: WorkflowStatus;\n /** JSON-serialized metadata for querying */\n metadata: string | null;\n /** Error name if workflow failed */\n error_name: string | null;\n /** Error message if workflow failed */\n error_message: string | null;\n /** Unix timestamp when workflow was created */\n created_at: number;\n /** Unix timestamp when workflow was last updated */\n updated_at: number;\n /** Unix timestamp when workflow completed (null if not complete) */\n completed_at: number | null;\n};\n\n/**\n * Options for runWorkflow()\n */\nexport type RunWorkflowOptions = {\n /** Custom workflow instance ID (auto-generated if not provided) */\n id?: string;\n /** Optional metadata for querying (stored as JSON) */\n metadata?: Record<string, unknown>;\n /** Agent binding name (auto-detected from class name if not provided) */\n agentBinding?: string;\n /** Retention policy for the underlying Workflow instance */\n retention?: WorkflowInstanceCreateOptions[\"retention\"];\n};\n\n/**\n * Event payload for sendWorkflowEvent()\n */\nexport type WorkflowEventPayload = {\n /** Event type name */\n type: string;\n /** Event payload data */\n payload: unknown;\n};\n\n/**\n * Parsed workflow tracking info returned by getWorkflow()\n */\nexport type WorkflowInfo = {\n /** Internal row ID */\n id: string;\n /** Cloudflare Workflow instance ID */\n workflowId: string;\n /** Workflow binding name */\n workflowName: string;\n /** Current workflow status */\n status: WorkflowStatus;\n /** Metadata (parsed from JSON) */\n metadata: Record<string, unknown> | null;\n /** Error info if workflow failed */\n error: { name: string; message: string } | null;\n /** When workflow was created */\n createdAt: Date;\n /** When workflow was last updated */\n updatedAt: Date;\n /** When workflow completed (null if not complete) */\n completedAt: Date | null;\n};\n\n/**\n * Criteria for querying tracked workflows\n */\nexport type WorkflowQueryCriteria = {\n /** Filter by status */\n status?: WorkflowStatus | WorkflowStatus[];\n /** Filter by workflow binding name */\n workflowName?: string;\n /** Filter by metadata key-value pairs (exact match) */\n metadata?: Record<string, string | number | boolean>;\n /** Limit number of results (default 50, max 100) */\n limit?: number;\n /** Order by created_at */\n orderBy?: \"asc\" | \"desc\";\n /** Cursor for pagination (from previous WorkflowPage.nextCursor) */\n cursor?: string;\n};\n\n/**\n * Paginated result from getWorkflows()\n */\nexport type WorkflowPage = {\n /** Workflows for this page */\n workflows: WorkflowInfo[];\n /** Total count of workflows matching the criteria (ignoring pagination) */\n total: number;\n /** Cursor for next page, or null if no more pages */\n nextCursor: string | null;\n};\n\n/**\n * Standard approval event payload used by approveWorkflow/rejectWorkflow\n */\nexport type ApprovalEventPayload = {\n /** Whether the workflow was approved */\n approved: boolean;\n /** Optional reason for approval/rejection */\n reason?: string;\n /** Optional additional metadata */\n metadata?: Record<string, unknown>;\n};\n\n/**\n * Options for waitForApproval()\n */\nexport type WaitForApprovalOptions = {\n /** Step name for waitForEvent (default: \"wait-for-approval\") */\n stepName?: string;\n /** Timeout duration (e.g., \"7 days\") */\n timeout?: WorkflowSleepDuration;\n /** Event type to wait for (default: \"approval\") */\n eventType?: string;\n};\n\n/**\n * Error thrown when a workflow is rejected via rejectWorkflow()\n */\nexport class WorkflowRejectedError extends Error {\n constructor(\n public readonly reason?: string,\n public readonly workflowId?: string\n ) {\n super(reason ? `Workflow rejected: ${reason}` : \"Workflow rejected\");\n this.name = \"WorkflowRejectedError\";\n }\n}\n"],"mappings":";;;;AAwUA,IAAa,wBAAb,cAA2C,MAAM;CAC/C,YACE,QACA,YACA;EACA,MAAM,SAAS,sBAAsB,WAAW,mBAAmB;EAHnD,KAAA,SAAA;EACA,KAAA,aAAA;EAGhB,KAAK,OAAO;CACd;AACF"}
|
package/dist/workflows.d.ts
CHANGED
|
@@ -1,26 +1,26 @@
|
|
|
1
|
-
import { O as Agent } from "./agent-tool-types-BC-WFlsz.js";
|
|
2
1
|
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
2
|
+
At as WorkflowRejectedError,
|
|
3
|
+
Ct as WorkflowErrorCallback,
|
|
4
|
+
Dt as WorkflowPage,
|
|
5
|
+
Et as WorkflowInfo,
|
|
6
|
+
Mt as WorkflowTrackingRow,
|
|
7
|
+
Ot as WorkflowProgressCallback,
|
|
8
|
+
St as WorkflowCompleteCallback,
|
|
9
|
+
Tt as WorkflowEventPayload,
|
|
10
|
+
_t as RunWorkflowOptions,
|
|
11
|
+
c as Agent,
|
|
12
|
+
ft as AgentWorkflowParams,
|
|
13
|
+
gt as DefaultProgress,
|
|
14
|
+
ht as ApprovalEventPayload,
|
|
15
|
+
jt as WorkflowStatus,
|
|
16
|
+
kt as WorkflowQueryCriteria,
|
|
17
|
+
lt as AgentWorkflowEvent,
|
|
18
|
+
mt as AgentWorkflowStep,
|
|
19
|
+
vt as WaitForApprovalOptions,
|
|
20
|
+
wt as WorkflowEventCallback,
|
|
21
|
+
xt as WorkflowCallbackType,
|
|
22
|
+
yt as WorkflowCallback
|
|
23
|
+
} from "./agent-routing-CnkaHb-v.js";
|
|
24
24
|
import { WorkflowEntrypoint, WorkflowEvent } from "cloudflare:workers";
|
|
25
25
|
|
|
26
26
|
//#region src/workflows.d.ts
|
package/dist/workflows.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { isInternalJsStubProp } from "./utils.js";
|
|
2
|
-
import { getAgentByName } from "./
|
|
2
|
+
import { getAgentByName } from "./agent-routing.js";
|
|
3
|
+
import "./src-5W6JNKVb.js";
|
|
3
4
|
import { WorkflowRejectedError } from "./workflow-types.js";
|
|
4
5
|
import { WorkflowEntrypoint } from "cloudflare:workers";
|
|
5
6
|
//#region src/workflows.ts
|
package/dist/workflows.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workflows.js","names":[],"sources":["../src/workflows.ts"],"sourcesContent":["/**\n * AgentWorkflow - Base class for Workflows that integrate with Agents\n *\n * Extends Cloudflare's WorkflowEntrypoint to provide seamless access to\n * the Agent that started the workflow, enabling bidirectional communication.\n *\n * @example\n * ```typescript\n * import { AgentWorkflow } from 'agents/workflows';\n * import type { MyAgent } from './agent';\n *\n * type TaskParams = { taskId: string; data: string };\n *\n * export class ProcessingWorkflow extends AgentWorkflow<MyAgent, TaskParams> {\n * async run(event: AgentWorkflowEvent<TaskParams>, step: WorkflowStep) {\n * // Access the originating Agent via typed RPC\n * await this.agent.updateTaskStatus(event.payload.taskId, 'processing');\n *\n * const result = await step.do('process', async () => {\n * // ... processing logic\n * return { processed: true };\n * });\n *\n * // Report progress to Agent (typed)\n * await this.reportProgress({ step: 'process', status: 'complete', percent: 0.5 });\n *\n * // Broadcast to connected clients\n * await this.broadcastToClients({ type: 'progress', data: result });\n *\n * return result;\n * }\n * }\n * ```\n */\n\nimport { WorkflowEntrypoint } from \"cloudflare:workers\";\nimport type {\n WorkflowEvent,\n WorkflowStep,\n WorkflowStepEvent\n} from \"cloudflare:workers\";\nimport { getAgentByName, type Agent } from \"./index\";\nimport type {\n AgentWorkflowParams,\n AgentWorkflowStep,\n WorkflowCallback,\n DefaultProgress,\n WaitForApprovalOptions\n} from \"./workflow-types\";\nimport { WorkflowRejectedError } from \"./workflow-types\";\nimport type {\n AgentWorkflowOrigin,\n AgentWorkflowPathStep\n} from \"./workflow-types\";\nimport { isInternalJsStubProp } from \"./utils\";\n\ntype AgentPathInvoker = {\n _cf_invokeAgentPath(\n path: ReadonlyArray<AgentWorkflowPathStep>,\n method: string,\n args: unknown[]\n ): Promise<unknown>;\n};\n\n/**\n * WeakSet to track which prototypes have been wrapped.\n * This prevents re-wrapping on subsequent instantiations of the same class.\n */\nconst wrappedPrototypes = new WeakSet<object>();\n\n/**\n * Base class for Workflows that need access to their originating Agent.\n *\n * @template AgentType - The Agent class type (for typed RPC access)\n * @template Params - User-defined params passed to the workflow (optional)\n * @template ProgressType - Type for progress reporting (defaults to DefaultProgress)\n * @template Env - Environment type (defaults to Cloudflare.Env)\n */\nexport class AgentWorkflow<\n AgentType extends Agent = Agent,\n Params = unknown,\n ProgressType = DefaultProgress,\n Env extends Cloudflare.Env = Cloudflare.Env\n> extends WorkflowEntrypoint<Env, AgentWorkflowParams<Params>> {\n /**\n * The Agent stub - initialized before run() is called.\n * Use this.agent to access the Agent's RPC methods.\n */\n private _agent?: DurableObjectStub<AgentType>;\n\n /**\n * Workflow instance ID\n */\n private _workflowId!: string;\n\n /**\n * Workflow binding name (for callbacks)\n */\n private _workflowName!: string;\n\n /**\n * Instance-level guard to prevent double initialization.\n * Used when a subclass calls super.run() after its own run() was wrapped.\n */\n private __agentInitCalled = false;\n\n /**\n * Guard to prevent double error notification.\n * Set to true when reportError() is called explicitly, so the automatic\n * error catch in the run() wrapper doesn't send a duplicate notification.\n */\n private _errorReported = false;\n\n constructor(ctx: ExecutionContext, env: Env) {\n super(ctx, env);\n\n const proto = Object.getPrototypeOf(this);\n\n // Only wrap if:\n // 1. This prototype defines its own run method (hasOwnProperty)\n // 2. It hasn't been wrapped yet (WeakSet check)\n // This prevents double-wrapping inherited methods and ensures each subclass\n // that defines run() gets wrapped exactly once.\n if (Object.hasOwn(proto, \"run\") && !wrappedPrototypes.has(proto)) {\n const originalRun = proto.run as (\n event: WorkflowEvent<Params>,\n step: AgentWorkflowStep\n ) => Promise<unknown>;\n\n // Replace the prototype's run method with a wrapper that initializes\n // the agent before calling the user's implementation\n proto.run = async function (\n this: AgentWorkflow<AgentType, Params, ProgressType, Env>,\n event: WorkflowEvent<AgentWorkflowParams<Params>>,\n step: WorkflowStep\n ) {\n // Instance-level guard: only init once per instance\n // (prevents double init if super.run() is called from a subclass)\n if (!this.__agentInitCalled) {\n const {\n __agentName,\n __agentBinding,\n __workflowName,\n __agentOrigin,\n ...userParams\n } = event.payload;\n\n // Initialize agent connection\n await this._initAgent(\n __agentName,\n __agentBinding,\n __workflowName,\n __agentOrigin,\n event.instanceId\n );\n this.__agentInitCalled = true;\n\n try {\n // Pass cleaned event and wrapped step to user's implementation\n const cleanedEvent = {\n ...event,\n payload: userParams as Params\n } as WorkflowEvent<Params>;\n\n const wrappedStep = this.extendStep(\n this._wrapStep(step),\n cleanedEvent\n );\n\n return await this._runWithErrorReporting(\n originalRun,\n cleanedEvent,\n wrappedStep\n );\n } finally {\n this._disposeAgent();\n }\n }\n\n // If already initialized (e.g., called via super.run()),\n // just call the original with the event as-is.\n return await this._runWithErrorReporting(\n originalRun,\n event as WorkflowEvent<Params>,\n step as AgentWorkflowStep\n );\n };\n\n wrappedPrototypes.add(proto);\n }\n }\n\n /**\n * Initialize the Agent stub from workflow params.\n * Called automatically before run() executes.\n */\n private async _initAgent(\n agentName: string | undefined,\n agentBinding: string | undefined,\n workflowName: string | undefined,\n agentOrigin: AgentWorkflowOrigin | undefined,\n instanceId: string\n ): Promise<void> {\n if (!workflowName || (!agentOrigin && (!agentName || !agentBinding))) {\n throw new Error(\n \"AgentWorkflow requires __agentName, __agentBinding, and __workflowName in params. \" +\n \"Use agent.runWorkflow() to start workflows with proper agent context.\"\n );\n }\n\n this._workflowId = instanceId;\n this._workflowName = workflowName;\n this._errorReported = false;\n\n // The origin payload is durably persisted in workflow params, so a workflow\n // started by an older SDK can resume against newer code (and vice versa).\n // Reject origin versions this build does not understand rather than\n // silently misreading a future shape.\n if (agentOrigin && agentOrigin.version !== 1) {\n throw new Error(\n `AgentWorkflow received an unsupported origin version (${\n (agentOrigin as { version?: unknown }).version\n }). Upgrade the \"agents\" package running this Workflow to match the Agent that started it.`\n );\n }\n\n if (agentOrigin?.kind === \"facet\") {\n this._agent = await this._initFacetAgent(agentOrigin);\n return;\n }\n\n const resolvedAgentName =\n agentOrigin?.kind === \"agent\" ? agentOrigin.name : agentName;\n const resolvedAgentBinding =\n agentOrigin?.kind === \"agent\" ? agentOrigin.binding : agentBinding;\n\n if (!resolvedAgentName || !resolvedAgentBinding) {\n throw new Error(\n \"AgentWorkflow requires a valid Agent origin. Use agent.runWorkflow() to start workflows with proper agent context.\"\n );\n }\n\n // Get the Agent namespace from env\n const namespace = (this.env as Record<string, unknown>)[\n resolvedAgentBinding\n ] as DurableObjectNamespace<AgentType>;\n\n if (!namespace) {\n throw new Error(\n `Agent binding '${resolvedAgentBinding}' not found in environment`\n );\n }\n\n // Get the Agent stub by name\n this._agent = await getAgentByName<Cloudflare.Env, AgentType>(\n namespace,\n resolvedAgentName\n );\n }\n\n private async _initFacetAgent(\n origin: Extract<AgentWorkflowOrigin, { kind: \"facet\" }>\n ): Promise<DurableObjectStub<AgentType>> {\n const root = origin.path[0];\n if (!root) {\n throw new Error(\"AgentWorkflow facet origin requires a non-empty path\");\n }\n\n const namespace = (this.env as Record<string, unknown>)[\n origin.rootBinding\n ] as DurableObjectNamespace<Agent> | undefined;\n\n if (!namespace) {\n throw new Error(\n `Agent binding '${origin.rootBinding}' not found in environment`\n );\n }\n\n const rootAgent = (await getAgentByName<Cloudflare.Env, Agent>(\n namespace,\n root.name\n )) as unknown as AgentPathInvoker;\n\n return new Proxy(\n {},\n {\n get(_target, prop) {\n if (isInternalJsStubProp(prop)) return undefined;\n if (typeof prop !== \"string\") return undefined;\n if (prop === \"fetch\") {\n return () => {\n throw new Error(\n \"AgentWorkflow.agent for sub-agent origins is an RPC-only stub — .fetch() is not supported. Use routeSubAgentRequest() or the /agents/{parent}/{name}/sub/{child}/{name} URL for external HTTP/WS routing.\"\n );\n };\n }\n return async (...args: unknown[]) =>\n rootAgent._cf_invokeAgentPath(origin.path, prop, args);\n }\n }\n ) as DurableObjectStub<AgentType>;\n }\n\n /**\n * Call user workflow code and report unhandled errors to the Agent.\n */\n private async _runWithErrorReporting(\n originalRun: (\n event: WorkflowEvent<Params>,\n step: AgentWorkflowStep\n ) => Promise<unknown>,\n event: WorkflowEvent<Params>,\n step: AgentWorkflowStep\n ): Promise<unknown> {\n try {\n return await originalRun.call(this, event, step);\n } catch (err) {\n await this._autoReportError(err);\n throw err;\n }\n }\n\n /**\n * Dispose the Agent stub owned by this workflow run.\n */\n private _disposeAgent(): void {\n const agent = this._agent;\n this._agent = undefined;\n this.__agentInitCalled = false;\n disposeIfPresent(agent);\n }\n\n /**\n * Wrap WorkflowStep with durable Agent communication methods.\n * Methods added to the wrapped step are idempotent and won't repeat on retry.\n *\n * Note: We add methods directly to the step object to preserve instanceof checks\n * that Cloudflare's runtime may perform on the WorkflowStep class.\n */\n private _wrapStep(step: WorkflowStep): AgentWorkflowStep {\n let stepCounter = 0;\n\n // Cast step to our extended type and add methods directly\n // This preserves the original object identity and instanceof relationship\n const wrappedStep = step as AgentWorkflowStep;\n\n // Add durable Agent methods directly to the step object\n wrappedStep.reportComplete = async <T>(result?: T): Promise<void> => {\n await step.do(`__agent_reportComplete_${stepCounter++}`, async () => {\n await this.notifyAgent({\n workflowName: this._workflowName,\n workflowId: this._workflowId,\n type: \"complete\",\n result,\n timestamp: Date.now()\n });\n });\n };\n\n wrappedStep.reportError = async (error: Error | string): Promise<void> => {\n const errorMessage = error instanceof Error ? error.message : error;\n this._errorReported = true;\n await step.do(`__agent_reportError_${stepCounter++}`, async () => {\n await this.notifyAgent({\n workflowName: this._workflowName,\n workflowId: this._workflowId,\n type: \"error\",\n error: errorMessage,\n timestamp: Date.now()\n });\n });\n };\n\n wrappedStep.sendEvent = async <T>(event: T): Promise<void> => {\n await step.do(`__agent_sendEvent_${stepCounter++}`, async () => {\n await this.notifyAgent({\n workflowName: this._workflowName,\n workflowId: this._workflowId,\n type: \"event\",\n event,\n timestamp: Date.now()\n });\n });\n };\n\n wrappedStep.updateAgentState = async (state: unknown): Promise<void> => {\n await step.do(`__agent_updateState_${stepCounter++}`, async () => {\n await this.agent._workflow_updateState(\"set\", state);\n });\n };\n\n wrappedStep.mergeAgentState = async (\n partialState: Record<string, unknown>\n ): Promise<void> => {\n await step.do(`__agent_mergeState_${stepCounter++}`, async () => {\n await this.agent._workflow_updateState(\"merge\", partialState);\n });\n };\n\n wrappedStep.resetAgentState = async (): Promise<void> => {\n await step.do(`__agent_resetState_${stepCounter++}`, async () => {\n await this.agent._workflow_updateState(\"reset\");\n });\n };\n\n return wrappedStep;\n }\n\n /**\n * Extend the Agent-aware workflow step before user code receives it.\n *\n * Subclasses can override this to add framework-specific step helpers while\n * preserving the underlying WorkflowStep object identity.\n */\n protected extendStep(\n step: AgentWorkflowStep,\n _event: WorkflowEvent<Params>\n ): AgentWorkflowStep {\n return step;\n }\n\n /**\n * Get the Agent stub for RPC calls.\n * Provides typed access to the Agent's methods.\n *\n * @example\n * ```typescript\n * // Call any public method on the Agent\n * await this.agent.updateStatus('processing');\n * const data = await this.agent.getData();\n * ```\n */\n get agent(): DurableObjectStub<AgentType> {\n if (!this._agent) {\n throw new Error(\n \"Agent not initialized. Ensure you're accessing this.agent inside run().\"\n );\n }\n return this._agent;\n }\n\n /**\n * Get the workflow instance ID\n */\n get workflowId(): string {\n return this._workflowId;\n }\n\n /**\n * Get the workflow binding name\n */\n get workflowName(): string {\n return this._workflowName;\n }\n\n /**\n * Automatically report an unhandled error to the Agent.\n * Skipped if reportError() was already called (prevents double notification).\n * Best-effort: notification failures are swallowed so the original error propagates.\n *\n * @param err - The caught error\n */\n private async _autoReportError(err: unknown): Promise<void> {\n if (this._errorReported) {\n return;\n }\n this._errorReported = true;\n const errorMessage = err instanceof Error ? err.message : String(err);\n try {\n await this.notifyAgent({\n workflowName: this._workflowName,\n workflowId: this._workflowId,\n type: \"error\",\n error: errorMessage,\n timestamp: Date.now()\n });\n } catch (_notifyErr) {\n // Best-effort: don't mask the original error\n }\n }\n\n /**\n * Send a notification to the Agent via RPC.\n *\n * @param callback - Callback payload to send\n */\n protected async notifyAgent(callback: WorkflowCallback): Promise<void> {\n await this.agent._workflow_handleCallback(callback);\n }\n\n /**\n * Report progress to the Agent with typed progress data.\n * Triggers onWorkflowProgress() on the Agent.\n *\n * @param progress - Typed progress data\n *\n * @example\n * ```typescript\n * // Using default progress type\n * await this.reportProgress({ step: 'fetch', status: 'running' });\n * await this.reportProgress({ step: 'fetch', status: 'complete', percent: 0.5 });\n *\n * // With custom progress type\n * await this.reportProgress({ stage: 'extract', recordsProcessed: 100 });\n * ```\n */\n protected async reportProgress(progress: ProgressType): Promise<void> {\n await this.notifyAgent({\n workflowName: this._workflowName,\n workflowId: this._workflowId,\n type: \"progress\",\n progress: progress as DefaultProgress,\n timestamp: Date.now()\n });\n }\n\n /**\n * Broadcast a message to all connected WebSocket clients via the Agent.\n * This is non-durable and may repeat on workflow retry.\n *\n * @param message - Message to broadcast (will be JSON-stringified)\n */\n protected broadcastToClients(message: unknown): void {\n this.agent._workflow_broadcast(message);\n }\n\n /**\n * Wait for approval from the Agent.\n * Handles rejection by reporting error (durably) and throwing WorkflowRejectedError.\n *\n * @param step - AgentWorkflowStep object\n * @param options - Wait options (timeout, eventType, stepName)\n * @returns Approval payload (throws WorkflowRejectedError if rejected)\n *\n * @example\n * ```typescript\n * const approval = await this.waitForApproval(step, { timeout: '7 days' });\n * // approval contains the payload from approveWorkflow()\n * ```\n */\n protected async waitForApproval<T = unknown>(\n step: AgentWorkflowStep,\n options?: WaitForApprovalOptions\n ): Promise<T> {\n const stepName = options?.stepName ?? \"wait-for-approval\";\n const eventType = options?.eventType ?? \"approval\";\n const timeout = options?.timeout;\n\n // Wait for the approval event\n // Note: Call reportProgress() before this method if you want to update progress\n const event = (await step.waitForEvent(stepName, {\n type: eventType,\n timeout\n })) as WorkflowStepEvent<{\n approved: boolean;\n reason?: string;\n metadata?: T;\n }>;\n\n try {\n const payload = event.payload;\n\n // Check if rejected\n if (!payload.approved) {\n const reason = payload.reason;\n await step.reportError(reason ?? \"Workflow rejected\");\n throw new WorkflowRejectedError(reason, this._workflowId);\n }\n\n // Return the approval metadata as the result\n return payload.metadata as T;\n } finally {\n disposeIfPresent(event);\n }\n }\n}\n\ntype DisposableResource = {\n [Symbol.dispose](): void;\n};\n\nfunction isDisposableResource(value: unknown): value is DisposableResource {\n return (\n !!value &&\n typeof value === \"object\" &&\n Symbol.dispose in value &&\n typeof value[Symbol.dispose] === \"function\"\n );\n}\n\nfunction disposeIfPresent(value: unknown): void {\n if (isDisposableResource(value)) {\n value[Symbol.dispose]();\n }\n}\n\n// Re-export types for convenience\nexport type {\n AgentWorkflowEvent,\n AgentWorkflowStep,\n WorkflowCallback,\n WorkflowCallbackType,\n WorkflowProgressCallback,\n WorkflowCompleteCallback,\n WorkflowErrorCallback,\n WorkflowEventCallback,\n DefaultProgress,\n WaitForApprovalOptions,\n ApprovalEventPayload,\n WorkflowStatus,\n WorkflowTrackingRow,\n RunWorkflowOptions,\n WorkflowEventPayload,\n WorkflowInfo,\n WorkflowQueryCriteria,\n WorkflowPage\n} from \"./workflow-types\";\n\nexport { WorkflowRejectedError } from \"./workflow-types\";\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"workflows.js","names":[],"sources":["../src/workflows.ts"],"sourcesContent":["/**\n * AgentWorkflow - Base class for Workflows that integrate with Agents\n *\n * Extends Cloudflare's WorkflowEntrypoint to provide seamless access to\n * the Agent that started the workflow, enabling bidirectional communication.\n *\n * @example\n * ```typescript\n * import { AgentWorkflow } from 'agents/workflows';\n * import type { MyAgent } from './agent';\n *\n * type TaskParams = { taskId: string; data: string };\n *\n * export class ProcessingWorkflow extends AgentWorkflow<MyAgent, TaskParams> {\n * async run(event: AgentWorkflowEvent<TaskParams>, step: WorkflowStep) {\n * // Access the originating Agent via typed RPC\n * await this.agent.updateTaskStatus(event.payload.taskId, 'processing');\n *\n * const result = await step.do('process', async () => {\n * // ... processing logic\n * return { processed: true };\n * });\n *\n * // Report progress to Agent (typed)\n * await this.reportProgress({ step: 'process', status: 'complete', percent: 0.5 });\n *\n * // Broadcast to connected clients\n * await this.broadcastToClients({ type: 'progress', data: result });\n *\n * return result;\n * }\n * }\n * ```\n */\n\nimport { WorkflowEntrypoint } from \"cloudflare:workers\";\nimport type {\n WorkflowEvent,\n WorkflowStep,\n WorkflowStepEvent\n} from \"cloudflare:workers\";\nimport { getAgentByName, type Agent } from \"./index\";\nimport type {\n AgentWorkflowParams,\n AgentWorkflowStep,\n WorkflowCallback,\n DefaultProgress,\n WaitForApprovalOptions\n} from \"./workflow-types\";\nimport { WorkflowRejectedError } from \"./workflow-types\";\nimport type {\n AgentWorkflowOrigin,\n AgentWorkflowPathStep\n} from \"./workflow-types\";\nimport { isInternalJsStubProp } from \"./utils\";\n\ntype AgentPathInvoker = {\n _cf_invokeAgentPath(\n path: ReadonlyArray<AgentWorkflowPathStep>,\n method: string,\n args: unknown[]\n ): Promise<unknown>;\n};\n\n/**\n * WeakSet to track which prototypes have been wrapped.\n * This prevents re-wrapping on subsequent instantiations of the same class.\n */\nconst wrappedPrototypes = new WeakSet<object>();\n\n/**\n * Base class for Workflows that need access to their originating Agent.\n *\n * @template AgentType - The Agent class type (for typed RPC access)\n * @template Params - User-defined params passed to the workflow (optional)\n * @template ProgressType - Type for progress reporting (defaults to DefaultProgress)\n * @template Env - Environment type (defaults to Cloudflare.Env)\n */\nexport class AgentWorkflow<\n AgentType extends Agent = Agent,\n Params = unknown,\n ProgressType = DefaultProgress,\n Env extends Cloudflare.Env = Cloudflare.Env\n> extends WorkflowEntrypoint<Env, AgentWorkflowParams<Params>> {\n /**\n * The Agent stub - initialized before run() is called.\n * Use this.agent to access the Agent's RPC methods.\n */\n private _agent?: DurableObjectStub<AgentType>;\n\n /**\n * Workflow instance ID\n */\n private _workflowId!: string;\n\n /**\n * Workflow binding name (for callbacks)\n */\n private _workflowName!: string;\n\n /**\n * Instance-level guard to prevent double initialization.\n * Used when a subclass calls super.run() after its own run() was wrapped.\n */\n private __agentInitCalled = false;\n\n /**\n * Guard to prevent double error notification.\n * Set to true when reportError() is called explicitly, so the automatic\n * error catch in the run() wrapper doesn't send a duplicate notification.\n */\n private _errorReported = false;\n\n constructor(ctx: ExecutionContext, env: Env) {\n super(ctx, env);\n\n const proto = Object.getPrototypeOf(this);\n\n // Only wrap if:\n // 1. This prototype defines its own run method (hasOwnProperty)\n // 2. It hasn't been wrapped yet (WeakSet check)\n // This prevents double-wrapping inherited methods and ensures each subclass\n // that defines run() gets wrapped exactly once.\n if (Object.hasOwn(proto, \"run\") && !wrappedPrototypes.has(proto)) {\n const originalRun = proto.run as (\n event: WorkflowEvent<Params>,\n step: AgentWorkflowStep\n ) => Promise<unknown>;\n\n // Replace the prototype's run method with a wrapper that initializes\n // the agent before calling the user's implementation\n proto.run = async function (\n this: AgentWorkflow<AgentType, Params, ProgressType, Env>,\n event: WorkflowEvent<AgentWorkflowParams<Params>>,\n step: WorkflowStep\n ) {\n // Instance-level guard: only init once per instance\n // (prevents double init if super.run() is called from a subclass)\n if (!this.__agentInitCalled) {\n const {\n __agentName,\n __agentBinding,\n __workflowName,\n __agentOrigin,\n ...userParams\n } = event.payload;\n\n // Initialize agent connection\n await this._initAgent(\n __agentName,\n __agentBinding,\n __workflowName,\n __agentOrigin,\n event.instanceId\n );\n this.__agentInitCalled = true;\n\n try {\n // Pass cleaned event and wrapped step to user's implementation\n const cleanedEvent = {\n ...event,\n payload: userParams as Params\n } as WorkflowEvent<Params>;\n\n const wrappedStep = this.extendStep(\n this._wrapStep(step),\n cleanedEvent\n );\n\n return await this._runWithErrorReporting(\n originalRun,\n cleanedEvent,\n wrappedStep\n );\n } finally {\n this._disposeAgent();\n }\n }\n\n // If already initialized (e.g., called via super.run()),\n // just call the original with the event as-is.\n return await this._runWithErrorReporting(\n originalRun,\n event as WorkflowEvent<Params>,\n step as AgentWorkflowStep\n );\n };\n\n wrappedPrototypes.add(proto);\n }\n }\n\n /**\n * Initialize the Agent stub from workflow params.\n * Called automatically before run() executes.\n */\n private async _initAgent(\n agentName: string | undefined,\n agentBinding: string | undefined,\n workflowName: string | undefined,\n agentOrigin: AgentWorkflowOrigin | undefined,\n instanceId: string\n ): Promise<void> {\n if (!workflowName || (!agentOrigin && (!agentName || !agentBinding))) {\n throw new Error(\n \"AgentWorkflow requires __agentName, __agentBinding, and __workflowName in params. \" +\n \"Use agent.runWorkflow() to start workflows with proper agent context.\"\n );\n }\n\n this._workflowId = instanceId;\n this._workflowName = workflowName;\n this._errorReported = false;\n\n // The origin payload is durably persisted in workflow params, so a workflow\n // started by an older SDK can resume against newer code (and vice versa).\n // Reject origin versions this build does not understand rather than\n // silently misreading a future shape.\n if (agentOrigin && agentOrigin.version !== 1) {\n throw new Error(\n `AgentWorkflow received an unsupported origin version (${\n (agentOrigin as { version?: unknown }).version\n }). Upgrade the \"agents\" package running this Workflow to match the Agent that started it.`\n );\n }\n\n if (agentOrigin?.kind === \"facet\") {\n this._agent = await this._initFacetAgent(agentOrigin);\n return;\n }\n\n const resolvedAgentName =\n agentOrigin?.kind === \"agent\" ? agentOrigin.name : agentName;\n const resolvedAgentBinding =\n agentOrigin?.kind === \"agent\" ? agentOrigin.binding : agentBinding;\n\n if (!resolvedAgentName || !resolvedAgentBinding) {\n throw new Error(\n \"AgentWorkflow requires a valid Agent origin. Use agent.runWorkflow() to start workflows with proper agent context.\"\n );\n }\n\n // Get the Agent namespace from env\n const namespace = (this.env as Record<string, unknown>)[\n resolvedAgentBinding\n ] as DurableObjectNamespace<AgentType>;\n\n if (!namespace) {\n throw new Error(\n `Agent binding '${resolvedAgentBinding}' not found in environment`\n );\n }\n\n // Get the Agent stub by name\n this._agent = await getAgentByName<Cloudflare.Env, AgentType>(\n namespace,\n resolvedAgentName\n );\n }\n\n private async _initFacetAgent(\n origin: Extract<AgentWorkflowOrigin, { kind: \"facet\" }>\n ): Promise<DurableObjectStub<AgentType>> {\n const root = origin.path[0];\n if (!root) {\n throw new Error(\"AgentWorkflow facet origin requires a non-empty path\");\n }\n\n const namespace = (this.env as Record<string, unknown>)[\n origin.rootBinding\n ] as DurableObjectNamespace<Agent> | undefined;\n\n if (!namespace) {\n throw new Error(\n `Agent binding '${origin.rootBinding}' not found in environment`\n );\n }\n\n const rootAgent = (await getAgentByName<Cloudflare.Env, Agent>(\n namespace,\n root.name\n )) as unknown as AgentPathInvoker;\n\n return new Proxy(\n {},\n {\n get(_target, prop) {\n if (isInternalJsStubProp(prop)) return undefined;\n if (typeof prop !== \"string\") return undefined;\n if (prop === \"fetch\") {\n return () => {\n throw new Error(\n \"AgentWorkflow.agent for sub-agent origins is an RPC-only stub — .fetch() is not supported. Use routeSubAgentRequest() or the /agents/{parent}/{name}/sub/{child}/{name} URL for external HTTP/WS routing.\"\n );\n };\n }\n return async (...args: unknown[]) =>\n rootAgent._cf_invokeAgentPath(origin.path, prop, args);\n }\n }\n ) as DurableObjectStub<AgentType>;\n }\n\n /**\n * Call user workflow code and report unhandled errors to the Agent.\n */\n private async _runWithErrorReporting(\n originalRun: (\n event: WorkflowEvent<Params>,\n step: AgentWorkflowStep\n ) => Promise<unknown>,\n event: WorkflowEvent<Params>,\n step: AgentWorkflowStep\n ): Promise<unknown> {\n try {\n return await originalRun.call(this, event, step);\n } catch (err) {\n await this._autoReportError(err);\n throw err;\n }\n }\n\n /**\n * Dispose the Agent stub owned by this workflow run.\n */\n private _disposeAgent(): void {\n const agent = this._agent;\n this._agent = undefined;\n this.__agentInitCalled = false;\n disposeIfPresent(agent);\n }\n\n /**\n * Wrap WorkflowStep with durable Agent communication methods.\n * Methods added to the wrapped step are idempotent and won't repeat on retry.\n *\n * Note: We add methods directly to the step object to preserve instanceof checks\n * that Cloudflare's runtime may perform on the WorkflowStep class.\n */\n private _wrapStep(step: WorkflowStep): AgentWorkflowStep {\n let stepCounter = 0;\n\n // Cast step to our extended type and add methods directly\n // This preserves the original object identity and instanceof relationship\n const wrappedStep = step as AgentWorkflowStep;\n\n // Add durable Agent methods directly to the step object\n wrappedStep.reportComplete = async <T>(result?: T): Promise<void> => {\n await step.do(`__agent_reportComplete_${stepCounter++}`, async () => {\n await this.notifyAgent({\n workflowName: this._workflowName,\n workflowId: this._workflowId,\n type: \"complete\",\n result,\n timestamp: Date.now()\n });\n });\n };\n\n wrappedStep.reportError = async (error: Error | string): Promise<void> => {\n const errorMessage = error instanceof Error ? error.message : error;\n this._errorReported = true;\n await step.do(`__agent_reportError_${stepCounter++}`, async () => {\n await this.notifyAgent({\n workflowName: this._workflowName,\n workflowId: this._workflowId,\n type: \"error\",\n error: errorMessage,\n timestamp: Date.now()\n });\n });\n };\n\n wrappedStep.sendEvent = async <T>(event: T): Promise<void> => {\n await step.do(`__agent_sendEvent_${stepCounter++}`, async () => {\n await this.notifyAgent({\n workflowName: this._workflowName,\n workflowId: this._workflowId,\n type: \"event\",\n event,\n timestamp: Date.now()\n });\n });\n };\n\n wrappedStep.updateAgentState = async (state: unknown): Promise<void> => {\n await step.do(`__agent_updateState_${stepCounter++}`, async () => {\n await this.agent._workflow_updateState(\"set\", state);\n });\n };\n\n wrappedStep.mergeAgentState = async (\n partialState: Record<string, unknown>\n ): Promise<void> => {\n await step.do(`__agent_mergeState_${stepCounter++}`, async () => {\n await this.agent._workflow_updateState(\"merge\", partialState);\n });\n };\n\n wrappedStep.resetAgentState = async (): Promise<void> => {\n await step.do(`__agent_resetState_${stepCounter++}`, async () => {\n await this.agent._workflow_updateState(\"reset\");\n });\n };\n\n return wrappedStep;\n }\n\n /**\n * Extend the Agent-aware workflow step before user code receives it.\n *\n * Subclasses can override this to add framework-specific step helpers while\n * preserving the underlying WorkflowStep object identity.\n */\n protected extendStep(\n step: AgentWorkflowStep,\n _event: WorkflowEvent<Params>\n ): AgentWorkflowStep {\n return step;\n }\n\n /**\n * Get the Agent stub for RPC calls.\n * Provides typed access to the Agent's methods.\n *\n * @example\n * ```typescript\n * // Call any public method on the Agent\n * await this.agent.updateStatus('processing');\n * const data = await this.agent.getData();\n * ```\n */\n get agent(): DurableObjectStub<AgentType> {\n if (!this._agent) {\n throw new Error(\n \"Agent not initialized. Ensure you're accessing this.agent inside run().\"\n );\n }\n return this._agent;\n }\n\n /**\n * Get the workflow instance ID\n */\n get workflowId(): string {\n return this._workflowId;\n }\n\n /**\n * Get the workflow binding name\n */\n get workflowName(): string {\n return this._workflowName;\n }\n\n /**\n * Automatically report an unhandled error to the Agent.\n * Skipped if reportError() was already called (prevents double notification).\n * Best-effort: notification failures are swallowed so the original error propagates.\n *\n * @param err - The caught error\n */\n private async _autoReportError(err: unknown): Promise<void> {\n if (this._errorReported) {\n return;\n }\n this._errorReported = true;\n const errorMessage = err instanceof Error ? err.message : String(err);\n try {\n await this.notifyAgent({\n workflowName: this._workflowName,\n workflowId: this._workflowId,\n type: \"error\",\n error: errorMessage,\n timestamp: Date.now()\n });\n } catch (_notifyErr) {\n // Best-effort: don't mask the original error\n }\n }\n\n /**\n * Send a notification to the Agent via RPC.\n *\n * @param callback - Callback payload to send\n */\n protected async notifyAgent(callback: WorkflowCallback): Promise<void> {\n await this.agent._workflow_handleCallback(callback);\n }\n\n /**\n * Report progress to the Agent with typed progress data.\n * Triggers onWorkflowProgress() on the Agent.\n *\n * @param progress - Typed progress data\n *\n * @example\n * ```typescript\n * // Using default progress type\n * await this.reportProgress({ step: 'fetch', status: 'running' });\n * await this.reportProgress({ step: 'fetch', status: 'complete', percent: 0.5 });\n *\n * // With custom progress type\n * await this.reportProgress({ stage: 'extract', recordsProcessed: 100 });\n * ```\n */\n protected async reportProgress(progress: ProgressType): Promise<void> {\n await this.notifyAgent({\n workflowName: this._workflowName,\n workflowId: this._workflowId,\n type: \"progress\",\n progress: progress as DefaultProgress,\n timestamp: Date.now()\n });\n }\n\n /**\n * Broadcast a message to all connected WebSocket clients via the Agent.\n * This is non-durable and may repeat on workflow retry.\n *\n * @param message - Message to broadcast (will be JSON-stringified)\n */\n protected broadcastToClients(message: unknown): void {\n this.agent._workflow_broadcast(message);\n }\n\n /**\n * Wait for approval from the Agent.\n * Handles rejection by reporting error (durably) and throwing WorkflowRejectedError.\n *\n * @param step - AgentWorkflowStep object\n * @param options - Wait options (timeout, eventType, stepName)\n * @returns Approval payload (throws WorkflowRejectedError if rejected)\n *\n * @example\n * ```typescript\n * const approval = await this.waitForApproval(step, { timeout: '7 days' });\n * // approval contains the payload from approveWorkflow()\n * ```\n */\n protected async waitForApproval<T = unknown>(\n step: AgentWorkflowStep,\n options?: WaitForApprovalOptions\n ): Promise<T> {\n const stepName = options?.stepName ?? \"wait-for-approval\";\n const eventType = options?.eventType ?? \"approval\";\n const timeout = options?.timeout;\n\n // Wait for the approval event\n // Note: Call reportProgress() before this method if you want to update progress\n const event = (await step.waitForEvent(stepName, {\n type: eventType,\n timeout\n })) as WorkflowStepEvent<{\n approved: boolean;\n reason?: string;\n metadata?: T;\n }>;\n\n try {\n const payload = event.payload;\n\n // Check if rejected\n if (!payload.approved) {\n const reason = payload.reason;\n await step.reportError(reason ?? \"Workflow rejected\");\n throw new WorkflowRejectedError(reason, this._workflowId);\n }\n\n // Return the approval metadata as the result\n return payload.metadata as T;\n } finally {\n disposeIfPresent(event);\n }\n }\n}\n\ntype DisposableResource = {\n [Symbol.dispose](): void;\n};\n\nfunction isDisposableResource(value: unknown): value is DisposableResource {\n return (\n !!value &&\n typeof value === \"object\" &&\n Symbol.dispose in value &&\n typeof value[Symbol.dispose] === \"function\"\n );\n}\n\nfunction disposeIfPresent(value: unknown): void {\n if (isDisposableResource(value)) {\n value[Symbol.dispose]();\n }\n}\n\n// Re-export types for convenience\nexport type {\n AgentWorkflowEvent,\n AgentWorkflowStep,\n WorkflowCallback,\n WorkflowCallbackType,\n WorkflowProgressCallback,\n WorkflowCompleteCallback,\n WorkflowErrorCallback,\n WorkflowEventCallback,\n DefaultProgress,\n WaitForApprovalOptions,\n ApprovalEventPayload,\n WorkflowStatus,\n WorkflowTrackingRow,\n RunWorkflowOptions,\n WorkflowEventPayload,\n WorkflowInfo,\n WorkflowQueryCriteria,\n WorkflowPage\n} from \"./workflow-types\";\n\nexport { WorkflowRejectedError } from \"./workflow-types\";\n"],"mappings":"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"}
|