@ory/vercel-ai 0.10.0 → 0.11.1

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 CHANGED
@@ -27,7 +27,10 @@ each call it authorizes the tool and records spans. In **enforce** mode
27
27
  in **observe** mode (default) the tool runs and a `permission.observe_deny` span is recorded.
28
28
  Tools without an `execute` (provider-defined) pass through untouched.
29
29
 
30
- Derive the permission subject from per-call context with `subjectFromOptions`:
30
+ Derive the permission subject from per-call context with `subjectFromOptions`. A non-empty
31
+ return value takes precedence over the client's user principal and env overrides for that
32
+ call — this is how multi-user servers attribute each request to its own acting user. When it
33
+ returns undefined/empty, resolution falls back to the principal / env chain:
31
34
 
32
35
  ```ts
33
36
  withOry(tools, { subjectFromOptions: (o) => o?.experimental_context?.userId });
package/dist/index.d.ts CHANGED
@@ -29,8 +29,10 @@ export interface WithOryOptions {
29
29
  canBlock?: boolean;
30
30
  /**
31
31
  * Derive the permission subject from the AI SDK call options (e.g. read a thread/user id
32
- * from `options.experimental_context`). Falls back to the client principal / env when the
33
- * function returns undefined.
32
+ * from `options.experimental_context`). A non-empty return value takes precedence over the
33
+ * client's user principal and env overrides for that call — this is how multi-user servers
34
+ * attribute each request to its own acting user. When the function returns
35
+ * undefined/empty, resolution falls back to the principal / env chain.
34
36
  */
35
37
  subjectFromOptions?: (options: unknown) => string | undefined;
36
38
  }
package/dist/index.js CHANGED
@@ -26,19 +26,22 @@ const HARNESS = "vercel-ai";
26
26
  function withOry(tools, options = {}) {
27
27
  const client = options.client ?? argus_1.OryAgentClient.fromEnv(HARNESS);
28
28
  const canBlock = options.canBlock ?? true;
29
- let sessionStarted = false;
30
- const ensureSession = async () => {
31
- if (sessionStarted)
32
- return;
33
- sessionStarted = true;
34
- try {
35
- await (0, argus_1.sessionStart)(client, { harness: HARNESS, projectUrl: options.projectUrl });
36
- }
37
- catch (err) {
29
+ let sessionPromise;
30
+ // Cache the in-flight promise (not a boolean) so concurrent first calls all
31
+ // await the same session start instead of racing past a still-running gate.
32
+ // Fail-open: a rejection is logged, never rethrown, and clears the cache so
33
+ // a later call can retry.
34
+ const ensureSession = () => {
35
+ sessionPromise ??= (0, argus_1.sessionStart)(client, {
36
+ harness: HARNESS,
37
+ projectUrl: options.projectUrl,
38
+ }).then(() => undefined, (err) => {
39
+ sessionPromise = undefined;
38
40
  client.logger.warn("session_start.failed", {
39
41
  message: err instanceof Error ? err.message : String(err),
40
42
  });
41
- }
43
+ });
44
+ return sessionPromise;
42
45
  };
43
46
  const wrapped = {};
44
47
  for (const [name, tool] of Object.entries(tools)) {
@@ -51,14 +54,14 @@ function withOry(tools, options = {}) {
51
54
  ...tool,
52
55
  execute: async (input, callOptions) => {
53
56
  await ensureSession();
54
- const subjectFallback = options.subjectFromOptions?.(callOptions);
55
- const result = await (0, argus_1.gate)(client, {
57
+ // A per-call subject wins over the client principal / env overrides.
58
+ const subjectOverride = options.subjectFromOptions?.(callOptions);
59
+ const result = await (0, argus_1.runWithUserSubject)(subjectOverride, () => (0, argus_1.gate)(client, {
56
60
  harness: HARNESS,
57
61
  toolName: name,
58
62
  toolArgs: input,
59
- subjectFallback,
60
63
  canBlock,
61
- });
64
+ }));
62
65
  if (result.blocked) {
63
66
  throw new argus_1.OryDenialError({
64
67
  tool: name,
package/package.json CHANGED
@@ -1,8 +1,13 @@
1
1
  {
2
2
  "name": "@ory/vercel-ai",
3
- "version": "0.10.0",
3
+ "version": "0.11.1",
4
4
  "description": "Ory Agent Security for the Vercel AI SDK — per-tool authorization, tracing, and identity propagation by wrapping tool execute(). Built on @ory/argus.",
5
5
  "license": "Apache-2.0",
6
+ "publishConfig": {
7
+ "access": "public",
8
+ "registry": "https://registry.npmjs.org/",
9
+ "provenance": true
10
+ },
6
11
  "main": "dist/index.js",
7
12
  "types": "dist/index.d.ts",
8
13
  "exports": {
@@ -25,7 +30,7 @@
25
30
  "permissions"
26
31
  ],
27
32
  "dependencies": {
28
- "@ory/argus": "0.10.0"
33
+ "@ory/argus": "0.11.1"
29
34
  },
30
35
  "devDependencies": {
31
36
  "typescript": "^6.0.2",