@ory/cloudflare-agents 0.10.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 ADDED
@@ -0,0 +1,37 @@
1
+ # @ory/cloudflare-agents
2
+
3
+ Ory Agent Security for the [Cloudflare Agents SDK](https://developers.cloudflare.com/agents/).
4
+
5
+ Cloudflare Agents drive tool calls through the Vercel AI SDK (`streamText({ tools })`), so
6
+ Ory wraps each tool's `execute` — authorizing every call against Ory Permissions, tracing it,
7
+ and propagating user → agent identity — built on [`@ory/argus`](../core).
8
+
9
+ ```bash
10
+ npm install @ory/cloudflare-agents
11
+ ```
12
+
13
+ ```ts
14
+ import { AIChatAgent } from "agents/ai-chat-agent";
15
+ import { streamText } from "ai";
16
+ import { withOry } from "@ory/cloudflare-agents";
17
+
18
+ export class MyAgent extends AIChatAgent<Env> {
19
+ async onChatMessage(onFinish) {
20
+ return streamText({
21
+ model: this.model,
22
+ messages: this.messages,
23
+ tools: withOry({ ...this.tools, ...this.mcp.getAITools() }), // gate every tool
24
+ onFinish,
25
+ });
26
+ }
27
+ }
28
+ ```
29
+
30
+ In **enforce** mode (`ORY_PERMISSION_MODE=enforce`) a denied tool throws — the error surfaces
31
+ to the model and the tool never runs. In **observe** mode (default) the tool runs and a
32
+ `permission.observe_deny` span is recorded. Spans are tagged with the `cloudflare-agents`
33
+ integration so the audit trail distinguishes Cloudflare from a plain Vercel app.
34
+
35
+ Depends only on `@ory/argus` (not `ai`/`agents`); tools are duck-typed. Credentials come from
36
+ the shared `~/.config/ory-agent-plugins/config.json`. See
37
+ [docs/sdk-integrations.md](../../docs/sdk-integrations.md).
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Ory Agent Security for the Cloudflare Agents SDK.
3
+ *
4
+ * Cloudflare Agents drive their LLM tool calls through the **Vercel AI SDK** — inside an
5
+ * `AIChatAgent.onChatMessage` you call `streamText({ tools })` with AI-SDK tools (and
6
+ * `this.mcp.getAITools()` for MCP tools). The interception point is therefore the same:
7
+ * wrap each tool's `execute`. {@link withOry} authorizes every call against Ory Permissions,
8
+ * traces it, and (on the first call) runs the Ory session gates — under the
9
+ * `cloudflare-agents` harness identity so the audit trail attributes Cloudflare distinctly
10
+ * from a plain Vercel app.
11
+ *
12
+ * import { withOry } from "@ory/cloudflare-agents";
13
+ * const result = streamText({
14
+ * model, messages,
15
+ * tools: withOry({ ...this.tools, ...this.mcp.getAITools() }),
16
+ * });
17
+ *
18
+ * Depends only on `@ory/argus` — the `ai` / `agents` packages are not dependencies; tools are
19
+ * duck-typed so any version works.
20
+ */
21
+ import { OryAgentClient } from "@ory/argus";
22
+ /** A Vercel AI SDK tool (as used by Cloudflare Agents) — duck-typed. */
23
+ export interface AiTool {
24
+ execute?: (input: unknown, options?: unknown) => unknown;
25
+ [key: string]: unknown;
26
+ }
27
+ export type ToolSet = Record<string, AiTool>;
28
+ export interface WithOryOptions {
29
+ /** Client to use. Defaults to `OryAgentClient.fromEnv("cloudflare-agents")`. */
30
+ client?: OryAgentClient;
31
+ /** Override the Ory project URL for the session gates. */
32
+ projectUrl?: string;
33
+ /** Whether a denied tool is hard-blocked (throws). Default true. */
34
+ canBlock?: boolean;
35
+ /** Derive the permission subject from the AI SDK call options (e.g. a thread/user id). */
36
+ subjectFromOptions?: (options: unknown) => string | undefined;
37
+ }
38
+ /**
39
+ * Wrap every tool in `tools` so its `execute` is gated through Ory. Tools without an
40
+ * `execute` (client-side / provider-defined) are passed through untouched. Apply it to the
41
+ * tool map you hand to `streamText` — including `this.mcp.getAITools()`.
42
+ */
43
+ export declare function withOry(tools: ToolSet, options?: WithOryOptions): ToolSet;
44
+ export { OryAgentClient, OryDenialError } from "@ory/argus";
package/dist/index.js ADDED
@@ -0,0 +1,84 @@
1
+ "use strict";
2
+ /**
3
+ * Ory Agent Security for the Cloudflare Agents SDK.
4
+ *
5
+ * Cloudflare Agents drive their LLM tool calls through the **Vercel AI SDK** — inside an
6
+ * `AIChatAgent.onChatMessage` you call `streamText({ tools })` with AI-SDK tools (and
7
+ * `this.mcp.getAITools()` for MCP tools). The interception point is therefore the same:
8
+ * wrap each tool's `execute`. {@link withOry} authorizes every call against Ory Permissions,
9
+ * traces it, and (on the first call) runs the Ory session gates — under the
10
+ * `cloudflare-agents` harness identity so the audit trail attributes Cloudflare distinctly
11
+ * from a plain Vercel app.
12
+ *
13
+ * import { withOry } from "@ory/cloudflare-agents";
14
+ * const result = streamText({
15
+ * model, messages,
16
+ * tools: withOry({ ...this.tools, ...this.mcp.getAITools() }),
17
+ * });
18
+ *
19
+ * Depends only on `@ory/argus` — the `ai` / `agents` packages are not dependencies; tools are
20
+ * duck-typed so any version works.
21
+ */
22
+ Object.defineProperty(exports, "__esModule", { value: true });
23
+ exports.OryDenialError = exports.OryAgentClient = void 0;
24
+ exports.withOry = withOry;
25
+ const argus_1 = require("@ory/argus");
26
+ const HARNESS = "cloudflare-agents";
27
+ /**
28
+ * Wrap every tool in `tools` so its `execute` is gated through Ory. Tools without an
29
+ * `execute` (client-side / provider-defined) are passed through untouched. Apply it to the
30
+ * tool map you hand to `streamText` — including `this.mcp.getAITools()`.
31
+ */
32
+ function withOry(tools, options = {}) {
33
+ const client = options.client ?? argus_1.OryAgentClient.fromEnv(HARNESS);
34
+ const canBlock = options.canBlock ?? true;
35
+ let sessionStarted = false;
36
+ const ensureSession = async () => {
37
+ if (sessionStarted)
38
+ return;
39
+ sessionStarted = true;
40
+ try {
41
+ await (0, argus_1.sessionStart)(client, { harness: HARNESS, projectUrl: options.projectUrl });
42
+ }
43
+ catch (err) {
44
+ client.logger.warn("session_start.failed", {
45
+ message: err instanceof Error ? err.message : String(err),
46
+ });
47
+ }
48
+ };
49
+ const wrapped = {};
50
+ for (const [name, tool] of Object.entries(tools)) {
51
+ if (!tool || typeof tool.execute !== "function") {
52
+ wrapped[name] = tool;
53
+ continue;
54
+ }
55
+ const originalExecute = tool.execute.bind(tool);
56
+ wrapped[name] = {
57
+ ...tool,
58
+ execute: async (input, callOptions) => {
59
+ await ensureSession();
60
+ const result = await (0, argus_1.gate)(client, {
61
+ harness: HARNESS,
62
+ toolName: name,
63
+ toolArgs: input,
64
+ subjectFallback: options.subjectFromOptions?.(callOptions),
65
+ canBlock,
66
+ });
67
+ if (result.blocked) {
68
+ throw new argus_1.OryDenialError({
69
+ tool: name,
70
+ subjectId: result.subject,
71
+ namespace: result.namespace,
72
+ });
73
+ }
74
+ const output = await originalExecute(input, callOptions);
75
+ (0, argus_1.complete)(client, { toolName: name, output });
76
+ return output;
77
+ },
78
+ };
79
+ }
80
+ return wrapped;
81
+ }
82
+ var argus_2 = require("@ory/argus");
83
+ Object.defineProperty(exports, "OryAgentClient", { enumerable: true, get: function () { return argus_2.OryAgentClient; } });
84
+ Object.defineProperty(exports, "OryDenialError", { enumerable: true, get: function () { return argus_2.OryDenialError; } });
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "@ory/cloudflare-agents",
3
+ "version": "0.10.0",
4
+ "description": "Ory Agent Security for the Cloudflare Agents SDK — per-tool authorization, tracing, and identity propagation by wrapping the AI SDK tools passed to streamText. Built on @ory/argus.",
5
+ "license": "Apache-2.0",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "default": "./dist/index.js"
12
+ }
13
+ },
14
+ "files": [
15
+ "dist",
16
+ "!dist/**/*.tsbuildinfo"
17
+ ],
18
+ "keywords": [
19
+ "ory",
20
+ "cloudflare",
21
+ "agents",
22
+ "workers",
23
+ "authorization",
24
+ "agent",
25
+ "ai"
26
+ ],
27
+ "dependencies": {
28
+ "@ory/argus": "0.10.0"
29
+ },
30
+ "devDependencies": {
31
+ "typescript": "^6.0.2",
32
+ "vitest": "4.1.4"
33
+ },
34
+ "scripts": {
35
+ "build": "tsc",
36
+ "clean": "rm -rf dist *.tsbuildinfo",
37
+ "test": "vitest run",
38
+ "test:watch": "vitest",
39
+ "typecheck": "tsc --noEmit"
40
+ }
41
+ }