@agent-native/core 0.204.1-nightly-20261008153353 → 0.205.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.
Files changed (45) hide show
  1. package/dist/a2a/caller-auth.d.ts +1 -0
  2. package/dist/a2a/caller-auth.js +9 -3
  3. package/dist/a2a/client.d.ts +1 -0
  4. package/dist/a2a/client.js +1 -1
  5. package/dist/a2a/index.d.ts +2 -1
  6. package/dist/a2a/index.js +2 -1
  7. package/dist/agent/engine/ai-sdk-engine.js +3 -8
  8. package/dist/agent/engine/builder-engine.d.ts +1 -1
  9. package/dist/agent/engine/openrouter-tool-fetch.d.ts +1 -0
  10. package/dist/agent/engine/openrouter-tool-fetch.js +20 -0
  11. package/dist/agent/engine/translate-ai-sdk.d.ts +1 -1
  12. package/dist/agent/engine/translate-ai-sdk.js +3 -2
  13. package/dist/agent/model-config.d.ts +2 -2
  14. package/dist/agent/model-config.js +2 -0
  15. package/dist/app-config/observability.js +8 -1
  16. package/dist/client/analytics-session.js +25 -7
  17. package/dist/client/chat/agentkit-protocol.js +13 -2
  18. package/dist/client/url-scrub.js +5 -2
  19. package/dist/deploy/build.js +11 -0
  20. package/dist/file-upload/actions/upload-image.d.ts +3 -3
  21. package/dist/jobs/background-automation-runner.js +13 -2
  22. package/dist/mcp/build-server.js +7 -4
  23. package/dist/mcp/connect-route.js +16 -11
  24. package/dist/notifications/routes.d.ts +2 -2
  25. package/dist/observability/routes.d.ts +6 -6
  26. package/dist/observability/sentiment.d.ts +1 -1
  27. package/dist/observability/sentiment.js +30 -6
  28. package/dist/org/index.d.ts +1 -1
  29. package/dist/progress/routes.d.ts +1 -1
  30. package/dist/secrets/routes.d.ts +11 -11
  31. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  32. package/dist/server/agent-engine-ollama-models-route.d.ts +1 -1
  33. package/dist/server/attribution.d.ts +4 -6
  34. package/dist/server/attribution.js +20 -6
  35. package/dist/server/better-auth-instance.d.ts +2 -1
  36. package/dist/server/better-auth-instance.js +5 -1
  37. package/dist/server/magic-link-attribution.d.ts +1 -0
  38. package/dist/server/magic-link-attribution.js +5 -0
  39. package/dist/shared/analytics-session-id.d.ts +5 -0
  40. package/dist/shared/analytics-session-id.js +21 -0
  41. package/dist/triggers/actions/manage-automation.d.ts +3 -3
  42. package/dist/vite/sentry-source-maps.d.ts +1 -0
  43. package/dist/vite/sentry-source-maps.js +48 -22
  44. package/docs/content/actions-access-control.mdx +67 -21
  45. package/package.json +4 -4
@@ -1,26 +1,27 @@
1
1
  ---
2
2
  title: "Access & Authorization"
3
- description: "Who can call an action: exposure flags (agentTool, mcpTool, toolCallable), ctx-based scoping, accessFilter/assertAccess, and the authorize guard."
3
+ description: "Who can call an action: exposure flags (agentTool, mcpTool, toolCallable), the declarative access option, ctx-based scoping, accessFilter/assertAccess, and the authorize guard."
4
4
  ---
5
5
 
6
6
  # Access & Authorization
7
7
 
8
- Six settings decide who can call an action: the agent, the frontend, an extension, an outside API caller, or nobody without a human's approval first. Most actions never need to touch any of these, since the defaults already fit normal UI-and-agent use.
8
+ Seven settings decide who can call an action: the agent, the frontend, an extension, an outside API caller, or nobody without a human's approval first. Most actions never need to touch any of these, since the defaults already fit normal UI-and-agent use.
9
9
 
10
10
  ### Exposure flags {#exposure-flags}
11
11
 
12
- All six default to the permissive value — `mcpTool` by inheriting `agentTool` — so you only set one when you need to tighten a specific surface. The table below is a quick summary. The sections after it add the one detail each flag needs.
12
+ All seven default to the permissive value — `mcpTool` by inheriting `agentTool` — so you only set one when you need to tighten a specific surface. The table below is a quick summary. The sections after it add the one detail each flag needs.
13
13
 
14
- | Flag | Default | Restrictive value → who can still call | Typical use |
15
- | --------------- | ------------- | --------------------------------------------------------------------------- | -------------------------------------------------------------------- |
16
- | `agentTool` | `true` | `false` → UI, HTTP, and CLI only (hidden from the model, MCP, and A2A) | UI-only or programmatic actions that shouldn't take up a tool slot |
17
- | `mcpTool` | `agentTool` | `false` → your own app's agent only (hidden from MCP and A2A) | Actions that need an in-app screen or session on the other end |
18
- | `toolCallable` | `true` | `false` → everything **except** the sandboxed extension iframe bridge (403) | Sensitive account or org changes (delete account, change membership) |
19
- | `publicAgent` | off (private) | `{ expose: true }` → adds the action to **public** MCP/A2A/OpenAPI surfaces | Safe read or ingest tools that don't require authentication |
20
- | `needsApproval` | `false` | `true` → the agent **pauses**, and a human must approve the specific call | Consequential side effects (send email, charge a card, delete) |
21
- | `authorize` | none | a guard function → only callers it accepts, on **every** surface | Operations restricted to a role (per-app RBAC, admin-only ops) |
14
+ | Flag | Default | Restrictive value → who can still call | Typical use |
15
+ | --------------- | ------------- | -------------------------------------------------------------------------------- | -------------------------------------------------------------------- |
16
+ | `agentTool` | `true` | `false` → UI, HTTP, and CLI only (hidden from the model, MCP, and A2A) | UI-only or programmatic actions that shouldn't take up a tool slot |
17
+ | `mcpTool` | `agentTool` | `false` → your own app's agent only (hidden from MCP and A2A) | Actions that need an in-app screen or session on the other end |
18
+ | `toolCallable` | `true` | `false` → everything **except** the sandboxed extension iframe bridge (403) | Sensitive account or org changes (delete account, change membership) |
19
+ | `publicAgent` | off (private) | `{ expose: true }` → adds the action to **public** MCP/A2A/OpenAPI surfaces | Safe read or ingest tools that don't require authentication |
20
+ | `needsApproval` | `false` | `true` → the agent **pauses**, and a human must approve the specific call | Consequential side effects (send email, charge a card, delete) |
21
+ | `access` | none | a declared policy → only callers holding the role it names, on **every** surface | Actions that read or change one shared resource (edit a form) |
22
+ | `authorize` | none | a guard function → only callers it accepts, on **every** surface | Operations restricted to a role (per-app RBAC, admin-only ops) |
22
23
 
23
- These flags are independent, with one exception: an undeclared `mcpTool` inherits `agentTool`. `agentTool` controls what the model sees, see [Hide from the model](#agent-tool) below. `mcpTool` narrows that to outside agents only, see [Hide from external agents](#mcp-tool) below. `toolCallable` controls only the extension iframe, see [Block extension iframes](#tool-callable) below. `publicAgent` adds an opt-in public surface, and a public web route never implies public tool exposure, see [Expose to public agents](#public-agent) below. `needsApproval` gates execution after the call is already made, see [Require human approval](#needs-approval) below. `authorize` decides whether this caller may run the action at all, on every dispatch path, before `run()` is entered, see [Restrict callers by role](#authorize) below.
24
+ These flags are independent, with one exception: an undeclared `mcpTool` inherits `agentTool`. `agentTool` controls what the model sees, see [Hide from the model](#agent-tool) below. `mcpTool` narrows that to outside agents only, see [Hide from external agents](#mcp-tool) below. `toolCallable` controls only the extension iframe, see [Block extension iframes](#tool-callable) below. `publicAgent` adds an opt-in public surface, and a public web route never implies public tool exposure, see [Expose to public agents](#public-agent) below. `needsApproval` gates execution after the call is already made, see [Require human approval](#needs-approval) below. `access` declares the role the caller must hold on a resource, checked on every dispatch path before `run()` is entered, see [Require access to a resource](#access) below. `authorize` decides whether this caller may run the action at all, on every dispatch path, before `run()` is entered, see [Restrict callers by role](#authorize) below.
24
25
 
25
26
  ## Hide from the model {#agent-tool}
26
27
 
@@ -258,6 +259,48 @@ On `approval_required`, the chat UI renders an **Approve / Deny** affordance on
258
259
 
259
260
  The Mail template's `send-email` action is the canonical use of this gate in the framework, and it is intentionally rare. It sets `needsApproval: true` so the agent can draft and queue emails freely. It can never actually send a message without a human approving that specific send.
260
261
 
262
+ ## Require access to a resource {#access}
263
+
264
+ `access` declares what a caller must hold before an action runs. It is data on the definition, not code inside `run()`. Its most common form names a shared resource and the minimum role on it. The Forms template's `update-form` action uses it so only an editor of a form can change that form:
265
+
266
+ ```ts
267
+ // actions/update-form.ts
268
+ export default defineAction({
269
+ description: "Update an existing form.",
270
+ access: {
271
+ scope: "resource",
272
+ resource: { type: "form", idFrom: "id", level: "editor" },
273
+ },
274
+ schema: z.object({
275
+ id: z.string(),
276
+ title: z.string().optional(),
277
+ }),
278
+ run: async (args) => {
279
+ /* ...update the form... */
280
+ },
281
+ });
282
+ ```
283
+
284
+ `resource` takes three fields:
285
+
286
+ - **type**: the name the resource was registered under with `registerShareableResource()`, like `"form"` or `"deck"`. See [Sharing](/docs/sharing#building).
287
+ - **idFrom**: the input field that holds the resource's id. A dotted path like `"target.formId"` reads a nested field. If the value is missing or not a non-empty string, the call is denied.
288
+ - **level**: the minimum role the caller needs, one of `"viewer"`, `"commenter"`, `"editor"`, `"admin"`, or `"owner"`. It defaults to `"viewer"`.
289
+
290
+ Like `authorize`, the check wraps `run()` itself, so the UI, HTTP callers, the in-app agent, MCP clients, A2A callers, and the CLI all pass the same check before the body runs. It resolves the caller's role the same way `assertAccess()` does, so ownership, shares, and visibility all count. A caller below `level` gets a 403 such as `Requires editor access to form <id>.` A resource that doesn't exist gets the same 403.
291
+
292
+ Use `access` when one input field names the one resource the action touches. Use `assertAccess()` inside `run()` when the id comes from somewhere else, like a row you load first, or when one call touches several resources. List queries have no single id to check, so they use `accessFilter()`. See [Access control in actions](#access-control) below. The [doctor](/docs/doctor) check `resource-action-access` accepts either a declared `access` or an `assertAccess()` call.
293
+
294
+ ### Organization and app scopes {#access-scopes}
295
+
296
+ The other fields check membership instead of a single resource. Every field you set must pass.
297
+
298
+ - **`scope: "org"`**: the caller must be an active member of their current organization.
299
+ - **`scope: "app"`**: the caller must be signed in, and the workspace must have made this app available to them.
300
+ - **`permission`**: a permission key from this app's `defineAppRoles()` `permissions` map. The caller must hold an app role that grants it. It runs the `scope: "app"` check first.
301
+
302
+ `scope: "app"` and `permission` read the workspace's app registry, so they suit apps deployed as part of a workspace. In a standalone app, guard an app permission with `authorize` and `requirePermission()` instead, as shown in [App roles](/docs/organizations-teams-permissions#app-roles-per-app-rbac). That guard also rejects an undeclared permission key when the module loads. `access.permission` only denies it at request time.
303
+
261
304
  ## Restrict callers by role {#authorize}
262
305
 
263
306
  `authorize` answers one specific question: **may this caller run this operation at all?** Give it a guard function, and it runs before `run()` on every caller: agent tool, HTTP, frontend, MCP, A2A, and CLI.
@@ -296,10 +339,10 @@ The guard wraps `run()` itself, instead of attaching to some other part of the a
296
339
  The wrappers compose in this order:
297
340
 
298
341
  ```text
299
- validate input -> authorize -> run -> validate output -> audit
342
+ validate input -> access -> authorize -> run -> validate output -> audit
300
343
  ```
301
344
 
302
- Authorization sits _inside_ input validation, so a guard that inspects `args` gets the same parsed, type-checked value that `run()` receives, not whatever raw shape the caller sent. Auditing is outermost, so a denial is still recorded.
345
+ Authorization sits _inside_ input validation, so a guard that inspects `args` gets the same parsed, type-checked value that `run()` receives, not whatever raw shape the caller sent. `access` reads `idFrom` from that same parsed value. Auditing is outermost, so an audited action still records a denial. Read-only actions aren't audited by default, see [Audit logging](#audit) below.
303
346
 
304
347
  `requireAny()` fails at definition time, not at request time. Calling it with no roles, or with a role outside the declared list, throws as soon as the module loads. That way a mistake, like `authorize: coachAccess.requireAny()` with a dropped argument, breaks right where it happened, instead of showing up later as an unexplained 403.
305
348
 
@@ -352,17 +395,20 @@ export default defineAction({
352
395
  });
353
396
  ```
354
397
 
398
+ When the id comes straight from the input, as `id` does here, a declared [`access`](#access) policy runs the same check from the action definition.
399
+
355
400
  A create action calls neither helper. It only needs to stamp `ownerEmail` (and `orgId`) from the request context when inserting the new row, since there's no existing row yet to check access against. See [Sharing](/docs/sharing#building) for the full registration and create pattern, and [Run Context](/docs/actions-run-context) for the full shape of the `ctx` second argument used above.
356
401
 
357
- The three mechanisms are not interchangeable:
402
+ The four mechanisms are not interchangeable:
358
403
 
359
- | Mechanism | Question it answers | Applies to |
360
- | --------------------------------- | ---------------------------------------------------- | -------------------------------- |
361
- | `authorize` | May this caller perform the operation at all? | All six dispatch sites |
362
- | `needsApproval` | Should a human approve this specific permitted call? | The agent loop only |
363
- | `accessFilter()`/`assertAccess()` | Which rows may this permitted caller see or write? | Inside `run()`, per query or row |
404
+ | Mechanism | Question it answers | Applies to |
405
+ | --------------------------------- | ----------------------------------------------------- | -------------------------------- |
406
+ | `access` | Does the caller hold the declared role or membership? | All six dispatch sites |
407
+ | `authorize` | May this caller perform the operation at all? | All six dispatch sites |
408
+ | `needsApproval` | Should a human approve this specific permitted call? | The agent loop only |
409
+ | `accessFilter()`/`assertAccess()` | Which rows may this permitted caller see or write? | Inside `run()`, per query or row |
364
410
 
365
- A restricted write action typically needs both `authorize` and `assertAccess()`. The first keeps non-coaches out of the operation. The second keeps a coach out of another org's plan. `needsApproval` is a separate axis. It never restricts who may call, only whether the agent may proceed unattended.
411
+ A restricted write action typically needs both `authorize` and a row check. The first keeps non-coaches out of the operation. The second keeps a coach out of another org's plan. The row check is `assertAccess()`, or `access` when the row's id is an input field. `needsApproval` is a separate axis. It never restricts who may call, only whether the agent may proceed unattended.
366
412
 
367
413
  `coachAccess` above comes from `defineAppRoles()`, the per-app role overlay on org membership. See [Organizations, Teams & Permissions → App roles](/docs/organizations-teams-permissions#app-roles-per-app-rbac) for the role model and its guarantees.
368
414
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-native/core",
3
- "version": "0.204.1-nightly-20261008153353",
3
+ "version": "0.205.0",
4
4
  "description": "The agentic application framework for building autonomous agents with intuitive UIs",
5
5
  "homepage": "https://github.com/BuilderIO/agent-native#readme",
6
6
  "bugs": {
@@ -685,8 +685,8 @@
685
685
  "yaml": "^2.9.0",
686
686
  "yjs": "^13.6.33",
687
687
  "zod": "^4.3.6",
688
- "@agent-native/agentkit": "^0.204.1-nightly-20261008153353",
689
- "@agent-native/recap-cli": "^0.5.66"
688
+ "@agent-native/recap-cli": "^0.5.67",
689
+ "@agent-native/agentkit": "^0.205.0"
690
690
  },
691
691
  "devDependencies": {
692
692
  "@ai-sdk/anthropic": "^3.0.71",
@@ -756,7 +756,7 @@
756
756
  "xlsx": "^0.18.5"
757
757
  },
758
758
  "peerDependencies": {
759
- "@agent-native/core-corpus": "0.204.1-nightly-20261008153353",
759
+ "@agent-native/core-corpus": ">=0.196.0",
760
760
  "@ai-sdk/anthropic": ">=3",
761
761
  "@ai-sdk/cohere": ">=3",
762
762
  "@ai-sdk/google": ">=3",