@agent-native/core 0.201.0-nightly-20261005153421 → 0.201.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 +22 -22
- package/dist/a2a/server.d.ts +2 -2
- package/dist/a2a/server.js +13 -2
- package/dist/agent/thread-data-builder.d.ts +4 -0
- package/dist/agent/thread-data-builder.js +8 -0
- package/dist/agent-sql/analysis.d.ts +31 -0
- package/dist/agent-sql/analysis.js +169 -0
- package/dist/agent-sql/index.d.ts +4 -0
- package/dist/agent-sql/index.js +4 -0
- package/dist/agent-sql/lexer.d.ts +37 -0
- package/dist/agent-sql/lexer.js +357 -0
- package/dist/agent-sql/postgres.d.ts +51 -0
- package/dist/agent-sql/postgres.js +197 -0
- package/dist/agent-sql/query.d.ts +30 -0
- package/dist/agent-sql/query.js +514 -0
- package/dist/catalog.json +24 -24
- package/dist/client/analytics/index.d.ts +1 -1
- package/dist/client/analytics/index.js +1 -1
- package/dist/client/analytics.d.ts +8 -0
- package/dist/client/analytics.js +17 -2
- package/dist/client/session-replay.js +3 -2
- package/dist/identity/offboard.js +31 -3
- package/dist/identity/rekey.d.ts +12 -1
- package/dist/identity/rekey.js +77 -6
- package/dist/identity/retired-emails.d.ts +23 -0
- package/dist/identity/retired-emails.js +55 -0
- package/dist/mcp/actions/create-org-service-token.js +20 -8
- package/dist/mcp/actions/service-token-access.d.ts +1 -0
- package/dist/mcp/actions/service-token-access.js +41 -24
- package/dist/mcp/build-server.d.ts +20 -6
- package/dist/mcp/build-server.js +131 -35
- package/dist/mcp/connect-route.d.ts +4 -3
- package/dist/mcp/connect-route.js +140 -82
- package/dist/mcp/connect-store.d.ts +17 -11
- package/dist/mcp/connect-store.js +88 -60
- package/dist/mcp/credential-issuance.d.ts +23 -0
- package/dist/mcp/credential-issuance.js +77 -0
- package/dist/mcp/credential-membership.d.ts +26 -0
- package/dist/mcp/credential-membership.js +67 -0
- package/dist/mcp/oauth-route.js +133 -45
- package/dist/mcp/oauth-store.d.ts +15 -5
- package/dist/mcp/oauth-store.js +119 -34
- package/dist/mcp/oauth-token.d.ts +4 -0
- package/dist/mcp/oauth-token.js +5 -0
- package/dist/mcp/screen-memory-stdio.d.ts +7 -7
- package/dist/mcp/server.js +14 -0
- package/dist/onboarding/default-steps.js +1 -1
- package/dist/org/handlers.d.ts +1 -1
- package/dist/org/index.d.ts +2 -2
- package/dist/org/membership.d.ts +3 -1
- package/dist/org/membership.js +5 -2
- package/dist/provider-api/actions/custom-provider-registration.d.ts +12 -12
- package/dist/provider-api/actions/provider-api.d.ts +10 -10
- package/dist/provider-api/corpus-jobs.d.ts +2 -2
- package/dist/resource-changes/store.d.ts +2 -0
- package/dist/resource-changes/store.js +4 -0
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/scripts/db/exec.js +28 -101
- package/dist/scripts/db/patch.js +14 -34
- package/dist/scripts/db/postgres-client.d.ts +8 -1
- package/dist/scripts/db/postgres-client.js +20 -6
- package/dist/scripts/db/query.js +31 -33
- package/dist/scripts/db/safety.d.ts +47 -2
- package/dist/scripts/db/safety.js +383 -137
- package/dist/scripts/db/scoping.d.ts +1 -0
- package/dist/scripts/db/scoping.js +3 -2
- package/dist/search/index-store.d.ts +21 -0
- package/dist/search/index-store.js +47 -0
- package/dist/search/indexer.js +35 -32
- package/dist/search/registry.d.ts +6 -3
- package/dist/search/registry.js +30 -8
- package/dist/secrets/routes.d.ts +6 -6
- package/dist/server/agent-chat-plugin.js +18 -6
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/agent-engine-default-model-route.d.ts +1 -1
- package/dist/server/agent-run-context.js +9 -0
- package/dist/server/attribution.d.ts +2 -0
- package/dist/server/attribution.js +7 -1
- package/dist/server/auth.js +9 -0
- package/dist/server/credential-membership-unavailable.d.ts +13 -0
- package/dist/server/credential-membership-unavailable.js +22 -0
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.js +1 -0
- package/dist/server/onboarding-html.js +1 -1
- package/dist/server/realtime-token.d.ts +1 -1
- package/dist/server/recap-image-route.js +4 -0
- package/dist/server/release-schema.js +4 -0
- package/dist/shared/docs-url.d.ts +3 -1
- package/dist/shared/docs-url.js +6 -3
- package/dist/shared/environment-lanes.d.ts +8 -0
- package/dist/shared/environment-lanes.js +26 -0
- package/dist/templates/chat/.agents/skills/security/SKILL.md +9 -2
- package/dist/templates/chat/.agents/skills/storing-data/SKILL.md +12 -7
- package/dist/templates/chat/README.md +2 -2
- package/dist/templates/default/.agents/skills/security/SKILL.md +9 -2
- package/dist/templates/default/.agents/skills/storing-data/SKILL.md +12 -7
- package/dist/templates/default/app/routes/home.tsx +5 -1
- package/dist/templates/headless/.agents/skills/security/SKILL.md +9 -2
- package/dist/templates/headless/.agents/skills/storing-data/SKILL.md +12 -7
- package/dist/templates/workspace-core/.agents/skills/security/SKILL.md +9 -2
- package/dist/templates/workspace-core/.agents/skills/storing-data/SKILL.md +12 -7
- package/dist/tracking/providers.js +13 -1
- package/docs/content/authentication.mdx +5 -1
- package/docs/content/durable-background-runs.mdx +17 -8
- package/docs/content/external-agents.mdx +3 -1
- package/docs/content/mcp-protocol.mdx +6 -2
- package/docs/content/security.mdx +1 -1
- package/package.json +5 -4
- package/src/templates/chat/.agents/skills/security/SKILL.md +9 -2
- package/src/templates/chat/.agents/skills/storing-data/SKILL.md +12 -7
- package/src/templates/chat/README.md +2 -2
- package/src/templates/default/.agents/skills/security/SKILL.md +9 -2
- package/src/templates/default/.agents/skills/storing-data/SKILL.md +12 -7
- package/src/templates/default/app/routes/home.tsx +5 -1
- package/src/templates/headless/.agents/skills/security/SKILL.md +9 -2
- package/src/templates/headless/.agents/skills/storing-data/SKILL.md +12 -7
- package/src/templates/workspace-core/.agents/skills/security/SKILL.md +9 -2
- package/src/templates/workspace-core/.agents/skills/storing-data/SKILL.md +12 -7
|
@@ -41,6 +41,32 @@ export function resolveEnvironmentTargets(hostname) {
|
|
|
41
41
|
productionHost,
|
|
42
42
|
};
|
|
43
43
|
}
|
|
44
|
+
/**
|
|
45
|
+
* Moves an endpoint on a production lane host to that host's beta lane when
|
|
46
|
+
* the calling app is itself served from beta, so beta apps report to beta
|
|
47
|
+
* Analytics. Both lanes share one database: this picks which build ingests an
|
|
48
|
+
* event, not where the event is stored. Endpoints on any other host are an
|
|
49
|
+
* explicit choice and pass through unchanged.
|
|
50
|
+
*/
|
|
51
|
+
export function resolveLaneEndpoint(endpoint, appHostname) {
|
|
52
|
+
const appHost = appHostname?.trim().toLowerCase().replace(/\.$/, "");
|
|
53
|
+
if (!appHost || resolveEnvironmentTargets(appHost)?.betaHost !== appHost) {
|
|
54
|
+
return endpoint;
|
|
55
|
+
}
|
|
56
|
+
let url;
|
|
57
|
+
try {
|
|
58
|
+
url = new URL(endpoint);
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
// coercion-ok: A relative endpoint already targets the app's own lane.
|
|
62
|
+
return endpoint;
|
|
63
|
+
}
|
|
64
|
+
const betaHost = ENVIRONMENT_BETA_HOSTS[url.hostname];
|
|
65
|
+
if (!betaHost)
|
|
66
|
+
return endpoint;
|
|
67
|
+
url.hostname = betaHost;
|
|
68
|
+
return url.toString();
|
|
69
|
+
}
|
|
44
70
|
export function buildEnvironmentUrl(sourceHref, targetHost) {
|
|
45
71
|
try {
|
|
46
72
|
const target = new URL(sourceHref);
|
|
@@ -290,9 +290,16 @@ export default defineEventHandler(async (event) => {
|
|
|
290
290
|
|
|
291
291
|
## Data Scoping
|
|
292
292
|
|
|
293
|
-
In production, the framework automatically restricts all agent SQL queries to the current user's data using temporary views
|
|
293
|
+
In production, the framework automatically restricts all agent SQL queries to the current user's data using temporary views, and checks every statement before it runs so it can only reach those views.
|
|
294
294
|
|
|
295
|
-
The `db-query` / `db-exec` tools (and the extension SQL bridge, which shares the same path)
|
|
295
|
+
The `db-query` / `db-exec` / `db-patch` tools (and the extension SQL bridge, which shares the same path) read each statement the way Postgres does and refuse anything that could reach data around the temp views:
|
|
296
|
+
|
|
297
|
+
- schema- or database-qualified names like `public.<table>`, which resolve to the base table;
|
|
298
|
+
- names that resolve to anything other than the current user's temp views, such as materialized views or tables the scoping does not cover;
|
|
299
|
+
- app-defined SQL or PL/pgSQL functions and operators, whose bodies read tables without the views;
|
|
300
|
+
- built-ins that run SQL text, change session settings, or reach outside the database (`query_to_xml`, `set_config`, `dblink`, most `pg_*` functions).
|
|
301
|
+
|
|
302
|
+
`db-query` runs in a read-only transaction, and an `INSERT` must list its columns when the table has access-control columns. Use bare table names and plain expressions; scoping is applied automatically. When the agent needs data the views do not expose, add an app action with its own access checks.
|
|
296
303
|
|
|
297
304
|
### Per-User Scoping (`owner_email`)
|
|
298
305
|
|
|
@@ -75,10 +75,11 @@ state their PostgreSQL types directly.
|
|
|
75
75
|
|
|
76
76
|
Member offboarding and email changes refuse to run while any column named
|
|
77
77
|
`email`, `*_email`, `*scope_id`, `created_by`, `updated_by`, `invited_by`,
|
|
78
|
-
`owner`, `principal_id`, `session_id`, or `user_id` has no policy.
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
78
|
+
`owner`, `principal_id`, `session_id`, or `user_id` has no policy.
|
|
79
|
+
`createSharesTable()` tables are handled for you, and undeclared `owner_email`
|
|
80
|
+
columns transfer to the successor, which is right only for owned content.
|
|
81
|
+
Declare every other one, including columns that are not member identities, from
|
|
82
|
+
the app's database plugin graph (Clips does it in `server/db/index.ts`):
|
|
82
83
|
|
|
83
84
|
```ts
|
|
84
85
|
import { registerIdentityColumns } from "@agent-native/core/org";
|
|
@@ -88,13 +89,17 @@ registerIdentityColumns([
|
|
|
88
89
|
{ table: "space_members", column: "email", emailChange: "rekey", offboard: "delete", orgScope: { column: "space_id", references: { table: "spaces", column: "id", orgColumn: "org_id" } }, reason: "Space membership grants access." },
|
|
89
90
|
// Someone else's address: never rewritten.
|
|
90
91
|
{ table: "meeting_participants", column: "email", emailChange: "retain", offboard: "retain", reason: "Attendee address from the calendar provider." },
|
|
92
|
+
// A credential in an owner_email table: never handed to the successor.
|
|
93
|
+
{ table: "api_keys", column: "owner_email", emailChange: "rekey", offboard: "revoke", reason: "Bearer keys act as their owner." },
|
|
91
94
|
]);
|
|
92
95
|
```
|
|
93
96
|
|
|
94
|
-
Choose `delete` for grants, credentials, and pending tokens
|
|
97
|
+
Choose `delete` for grants, credentials, and pending tokens, or `revoke` (sets
|
|
98
|
+
`revoked_at`) when a reader treats a missing row as "not revoked"; `retain` for
|
|
95
99
|
attribution, history, and third-party addresses; `transfer` only for owned
|
|
96
|
-
data.
|
|
97
|
-
|
|
100
|
+
data. Declare `owner_email` tables that hold credentials or grants, or
|
|
101
|
+
offboarding hands them to the successor. A table without `org_id` needs
|
|
102
|
+
`orgScope` or an organization-scoped removal leaves its rows alone.
|
|
98
103
|
|
|
99
104
|
| Template | Tables |
|
|
100
105
|
| ------------ | --------------------------------------------- |
|
|
@@ -5,7 +5,7 @@ the center, durable threads, standard app navigation, auth, live sync, and
|
|
|
5
5
|
actions. Start here when you want a real browser app to build on without
|
|
6
6
|
committing to a domain template.
|
|
7
7
|
|
|
8
|
-
**Live app: [chat.agent-native.com](https://chat.agent-native.com)**
|
|
8
|
+
**Live app: [chat.agent-native.com](https://chat.agent-native.com?utm_source=github&utm_medium=referral&utm_content=chat-readme)**
|
|
9
9
|
|
|
10
10
|
Chat is the basic agent-native app starting point. It gives you the app-agent
|
|
11
11
|
loop wired end to end and one example action, so you can add your own UI, data,
|
|
@@ -30,4 +30,4 @@ pnpm install
|
|
|
30
30
|
pnpm dev
|
|
31
31
|
```
|
|
32
32
|
|
|
33
|
-
Full docs: [agent-native.com/docs/template-chat](https://agent-native.com/docs/template-chat).
|
|
33
|
+
Full docs: [agent-native.com/docs/template-chat](https://agent-native.com/docs/template-chat?utm_source=github&utm_medium=referral&utm_content=chat-readme).
|
|
@@ -290,9 +290,16 @@ export default defineEventHandler(async (event) => {
|
|
|
290
290
|
|
|
291
291
|
## Data Scoping
|
|
292
292
|
|
|
293
|
-
In production, the framework automatically restricts all agent SQL queries to the current user's data using temporary views
|
|
293
|
+
In production, the framework automatically restricts all agent SQL queries to the current user's data using temporary views, and checks every statement before it runs so it can only reach those views.
|
|
294
294
|
|
|
295
|
-
The `db-query` / `db-exec` tools (and the extension SQL bridge, which shares the same path)
|
|
295
|
+
The `db-query` / `db-exec` / `db-patch` tools (and the extension SQL bridge, which shares the same path) read each statement the way Postgres does and refuse anything that could reach data around the temp views:
|
|
296
|
+
|
|
297
|
+
- schema- or database-qualified names like `public.<table>`, which resolve to the base table;
|
|
298
|
+
- names that resolve to anything other than the current user's temp views, such as materialized views or tables the scoping does not cover;
|
|
299
|
+
- app-defined SQL or PL/pgSQL functions and operators, whose bodies read tables without the views;
|
|
300
|
+
- built-ins that run SQL text, change session settings, or reach outside the database (`query_to_xml`, `set_config`, `dblink`, most `pg_*` functions).
|
|
301
|
+
|
|
302
|
+
`db-query` runs in a read-only transaction, and an `INSERT` must list its columns when the table has access-control columns. Use bare table names and plain expressions; scoping is applied automatically. When the agent needs data the views do not expose, add an app action with its own access checks.
|
|
296
303
|
|
|
297
304
|
### Per-User Scoping (`owner_email`)
|
|
298
305
|
|
|
@@ -75,10 +75,11 @@ state their PostgreSQL types directly.
|
|
|
75
75
|
|
|
76
76
|
Member offboarding and email changes refuse to run while any column named
|
|
77
77
|
`email`, `*_email`, `*scope_id`, `created_by`, `updated_by`, `invited_by`,
|
|
78
|
-
`owner`, `principal_id`, `session_id`, or `user_id` has no policy.
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
78
|
+
`owner`, `principal_id`, `session_id`, or `user_id` has no policy.
|
|
79
|
+
`createSharesTable()` tables are handled for you, and undeclared `owner_email`
|
|
80
|
+
columns transfer to the successor, which is right only for owned content.
|
|
81
|
+
Declare every other one, including columns that are not member identities, from
|
|
82
|
+
the app's database plugin graph (Clips does it in `server/db/index.ts`):
|
|
82
83
|
|
|
83
84
|
```ts
|
|
84
85
|
import { registerIdentityColumns } from "@agent-native/core/org";
|
|
@@ -88,13 +89,17 @@ registerIdentityColumns([
|
|
|
88
89
|
{ table: "space_members", column: "email", emailChange: "rekey", offboard: "delete", orgScope: { column: "space_id", references: { table: "spaces", column: "id", orgColumn: "org_id" } }, reason: "Space membership grants access." },
|
|
89
90
|
// Someone else's address: never rewritten.
|
|
90
91
|
{ table: "meeting_participants", column: "email", emailChange: "retain", offboard: "retain", reason: "Attendee address from the calendar provider." },
|
|
92
|
+
// A credential in an owner_email table: never handed to the successor.
|
|
93
|
+
{ table: "api_keys", column: "owner_email", emailChange: "rekey", offboard: "revoke", reason: "Bearer keys act as their owner." },
|
|
91
94
|
]);
|
|
92
95
|
```
|
|
93
96
|
|
|
94
|
-
Choose `delete` for grants, credentials, and pending tokens
|
|
97
|
+
Choose `delete` for grants, credentials, and pending tokens, or `revoke` (sets
|
|
98
|
+
`revoked_at`) when a reader treats a missing row as "not revoked"; `retain` for
|
|
95
99
|
attribution, history, and third-party addresses; `transfer` only for owned
|
|
96
|
-
data.
|
|
97
|
-
|
|
100
|
+
data. Declare `owner_email` tables that hold credentials or grants, or
|
|
101
|
+
offboarding hands them to the successor. A table without `org_id` needs
|
|
102
|
+
`orgScope` or an organization-scoped removal leaves its rows alone.
|
|
98
103
|
|
|
99
104
|
| Template | Tables |
|
|
100
105
|
| ------------ | --------------------------------------------- |
|
|
@@ -47,7 +47,11 @@ export default function HomePage() {
|
|
|
47
47
|
|
|
48
48
|
<div className="grid grid-cols-2 gap-3 text-left">
|
|
49
49
|
<a
|
|
50
|
-
href={docsUrl("getting-started"
|
|
50
|
+
href={docsUrl("getting-started", {
|
|
51
|
+
source: "app",
|
|
52
|
+
campaign: null,
|
|
53
|
+
content: "docs-card",
|
|
54
|
+
})}
|
|
51
55
|
target="_blank"
|
|
52
56
|
rel="noopener noreferrer"
|
|
53
57
|
className="group rounded-lg border border-border/50 px-4 py-3 hover:bg-accent/50 transition-colors"
|
|
@@ -290,9 +290,16 @@ export default defineEventHandler(async (event) => {
|
|
|
290
290
|
|
|
291
291
|
## Data Scoping
|
|
292
292
|
|
|
293
|
-
In production, the framework automatically restricts all agent SQL queries to the current user's data using temporary views
|
|
293
|
+
In production, the framework automatically restricts all agent SQL queries to the current user's data using temporary views, and checks every statement before it runs so it can only reach those views.
|
|
294
294
|
|
|
295
|
-
The `db-query` / `db-exec` tools (and the extension SQL bridge, which shares the same path)
|
|
295
|
+
The `db-query` / `db-exec` / `db-patch` tools (and the extension SQL bridge, which shares the same path) read each statement the way Postgres does and refuse anything that could reach data around the temp views:
|
|
296
|
+
|
|
297
|
+
- schema- or database-qualified names like `public.<table>`, which resolve to the base table;
|
|
298
|
+
- names that resolve to anything other than the current user's temp views, such as materialized views or tables the scoping does not cover;
|
|
299
|
+
- app-defined SQL or PL/pgSQL functions and operators, whose bodies read tables without the views;
|
|
300
|
+
- built-ins that run SQL text, change session settings, or reach outside the database (`query_to_xml`, `set_config`, `dblink`, most `pg_*` functions).
|
|
301
|
+
|
|
302
|
+
`db-query` runs in a read-only transaction, and an `INSERT` must list its columns when the table has access-control columns. Use bare table names and plain expressions; scoping is applied automatically. When the agent needs data the views do not expose, add an app action with its own access checks.
|
|
296
303
|
|
|
297
304
|
### Per-User Scoping (`owner_email`)
|
|
298
305
|
|
|
@@ -75,10 +75,11 @@ state their PostgreSQL types directly.
|
|
|
75
75
|
|
|
76
76
|
Member offboarding and email changes refuse to run while any column named
|
|
77
77
|
`email`, `*_email`, `*scope_id`, `created_by`, `updated_by`, `invited_by`,
|
|
78
|
-
`owner`, `principal_id`, `session_id`, or `user_id` has no policy.
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
78
|
+
`owner`, `principal_id`, `session_id`, or `user_id` has no policy.
|
|
79
|
+
`createSharesTable()` tables are handled for you, and undeclared `owner_email`
|
|
80
|
+
columns transfer to the successor, which is right only for owned content.
|
|
81
|
+
Declare every other one, including columns that are not member identities, from
|
|
82
|
+
the app's database plugin graph (Clips does it in `server/db/index.ts`):
|
|
82
83
|
|
|
83
84
|
```ts
|
|
84
85
|
import { registerIdentityColumns } from "@agent-native/core/org";
|
|
@@ -88,13 +89,17 @@ registerIdentityColumns([
|
|
|
88
89
|
{ table: "space_members", column: "email", emailChange: "rekey", offboard: "delete", orgScope: { column: "space_id", references: { table: "spaces", column: "id", orgColumn: "org_id" } }, reason: "Space membership grants access." },
|
|
89
90
|
// Someone else's address: never rewritten.
|
|
90
91
|
{ table: "meeting_participants", column: "email", emailChange: "retain", offboard: "retain", reason: "Attendee address from the calendar provider." },
|
|
92
|
+
// A credential in an owner_email table: never handed to the successor.
|
|
93
|
+
{ table: "api_keys", column: "owner_email", emailChange: "rekey", offboard: "revoke", reason: "Bearer keys act as their owner." },
|
|
91
94
|
]);
|
|
92
95
|
```
|
|
93
96
|
|
|
94
|
-
Choose `delete` for grants, credentials, and pending tokens
|
|
97
|
+
Choose `delete` for grants, credentials, and pending tokens, or `revoke` (sets
|
|
98
|
+
`revoked_at`) when a reader treats a missing row as "not revoked"; `retain` for
|
|
95
99
|
attribution, history, and third-party addresses; `transfer` only for owned
|
|
96
|
-
data.
|
|
97
|
-
|
|
100
|
+
data. Declare `owner_email` tables that hold credentials or grants, or
|
|
101
|
+
offboarding hands them to the successor. A table without `org_id` needs
|
|
102
|
+
`orgScope` or an organization-scoped removal leaves its rows alone.
|
|
98
103
|
|
|
99
104
|
| Template | Tables |
|
|
100
105
|
| ------------ | --------------------------------------------- |
|
|
@@ -290,9 +290,16 @@ export default defineEventHandler(async (event) => {
|
|
|
290
290
|
|
|
291
291
|
## Data Scoping
|
|
292
292
|
|
|
293
|
-
In production, the framework automatically restricts all agent SQL queries to the current user's data using temporary views
|
|
293
|
+
In production, the framework automatically restricts all agent SQL queries to the current user's data using temporary views, and checks every statement before it runs so it can only reach those views.
|
|
294
294
|
|
|
295
|
-
The `db-query` / `db-exec` tools (and the extension SQL bridge, which shares the same path)
|
|
295
|
+
The `db-query` / `db-exec` / `db-patch` tools (and the extension SQL bridge, which shares the same path) read each statement the way Postgres does and refuse anything that could reach data around the temp views:
|
|
296
|
+
|
|
297
|
+
- schema- or database-qualified names like `public.<table>`, which resolve to the base table;
|
|
298
|
+
- names that resolve to anything other than the current user's temp views, such as materialized views or tables the scoping does not cover;
|
|
299
|
+
- app-defined SQL or PL/pgSQL functions and operators, whose bodies read tables without the views;
|
|
300
|
+
- built-ins that run SQL text, change session settings, or reach outside the database (`query_to_xml`, `set_config`, `dblink`, most `pg_*` functions).
|
|
301
|
+
|
|
302
|
+
`db-query` runs in a read-only transaction, and an `INSERT` must list its columns when the table has access-control columns. Use bare table names and plain expressions; scoping is applied automatically. When the agent needs data the views do not expose, add an app action with its own access checks.
|
|
296
303
|
|
|
297
304
|
### Per-User Scoping (`owner_email`)
|
|
298
305
|
|
|
@@ -75,10 +75,11 @@ state their PostgreSQL types directly.
|
|
|
75
75
|
|
|
76
76
|
Member offboarding and email changes refuse to run while any column named
|
|
77
77
|
`email`, `*_email`, `*scope_id`, `created_by`, `updated_by`, `invited_by`,
|
|
78
|
-
`owner`, `principal_id`, `session_id`, or `user_id` has no policy.
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
78
|
+
`owner`, `principal_id`, `session_id`, or `user_id` has no policy.
|
|
79
|
+
`createSharesTable()` tables are handled for you, and undeclared `owner_email`
|
|
80
|
+
columns transfer to the successor, which is right only for owned content.
|
|
81
|
+
Declare every other one, including columns that are not member identities, from
|
|
82
|
+
the app's database plugin graph (Clips does it in `server/db/index.ts`):
|
|
82
83
|
|
|
83
84
|
```ts
|
|
84
85
|
import { registerIdentityColumns } from "@agent-native/core/org";
|
|
@@ -88,13 +89,17 @@ registerIdentityColumns([
|
|
|
88
89
|
{ table: "space_members", column: "email", emailChange: "rekey", offboard: "delete", orgScope: { column: "space_id", references: { table: "spaces", column: "id", orgColumn: "org_id" } }, reason: "Space membership grants access." },
|
|
89
90
|
// Someone else's address: never rewritten.
|
|
90
91
|
{ table: "meeting_participants", column: "email", emailChange: "retain", offboard: "retain", reason: "Attendee address from the calendar provider." },
|
|
92
|
+
// A credential in an owner_email table: never handed to the successor.
|
|
93
|
+
{ table: "api_keys", column: "owner_email", emailChange: "rekey", offboard: "revoke", reason: "Bearer keys act as their owner." },
|
|
91
94
|
]);
|
|
92
95
|
```
|
|
93
96
|
|
|
94
|
-
Choose `delete` for grants, credentials, and pending tokens
|
|
97
|
+
Choose `delete` for grants, credentials, and pending tokens, or `revoke` (sets
|
|
98
|
+
`revoked_at`) when a reader treats a missing row as "not revoked"; `retain` for
|
|
95
99
|
attribution, history, and third-party addresses; `transfer` only for owned
|
|
96
|
-
data.
|
|
97
|
-
|
|
100
|
+
data. Declare `owner_email` tables that hold credentials or grants, or
|
|
101
|
+
offboarding hands them to the successor. A table without `org_id` needs
|
|
102
|
+
`orgScope` or an organization-scoped removal leaves its rows alone.
|
|
98
103
|
|
|
99
104
|
| Template | Tables |
|
|
100
105
|
| ------------ | --------------------------------------------- |
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { getAppConfig } from "../app-config/index.js";
|
|
2
2
|
import { getRequestContext } from "../server/request-context.js";
|
|
3
3
|
import { isTestIdentity } from "../server/test-identity.js";
|
|
4
|
+
import { resolveLaneEndpoint } from "../shared/environment-lanes.js";
|
|
4
5
|
import { reshapeTrackedExceptionProperties } from "./posthog-exception.js";
|
|
5
6
|
import { registerTrackingProvider } from "./registry.js";
|
|
6
7
|
const POSTHOG_DEFAULT_HOST = "https://us.i.posthog.com";
|
|
@@ -73,6 +74,17 @@ function isLocalhostUrl(value) {
|
|
|
73
74
|
return false;
|
|
74
75
|
}
|
|
75
76
|
}
|
|
77
|
+
function hostnameOf(url) {
|
|
78
|
+
if (!url)
|
|
79
|
+
return undefined;
|
|
80
|
+
try {
|
|
81
|
+
return new URL(url).hostname;
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
84
|
+
// coercion-ok: An unparseable app URL names no lane, so the endpoint stays as configured.
|
|
85
|
+
return undefined;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
76
88
|
function shouldSkipAgentNativeAnalyticsForLocalhost() {
|
|
77
89
|
if (process.env.AGENT_NATIVE_ANALYTICS_ALLOW_LOCALHOST === "true") {
|
|
78
90
|
return false;
|
|
@@ -358,7 +370,7 @@ export function registerBuiltinProviders() {
|
|
|
358
370
|
}
|
|
359
371
|
const { agentNativePublicKey, agentNativeEndpoint } = getAppConfig().analytics;
|
|
360
372
|
if (agentNativePublicKey && !shouldSkipAgentNativeAnalyticsForLocalhost()) {
|
|
361
|
-
registerTrackingProvider(createAgentNativeAnalyticsProvider(agentNativePublicKey, (agentNativeEndpoint || AGENT_NATIVE_ANALYTICS_DEFAULT_ENDPOINT).replace(/\/+$/, "")));
|
|
373
|
+
registerTrackingProvider(createAgentNativeAnalyticsProvider(agentNativePublicKey, resolveLaneEndpoint((agentNativeEndpoint || AGENT_NATIVE_ANALYTICS_DEFAULT_ENDPOINT).replace(/\/+$/, ""), hostnameOf(getAppConfig().app.url))));
|
|
362
374
|
}
|
|
363
375
|
const webhookUrl = process.env.TRACKING_WEBHOOK_URL;
|
|
364
376
|
if (webhookUrl) {
|
|
@@ -369,7 +369,11 @@ Unauthenticated MCP requests return a `WWW-Authenticate` challenge pointing at `
|
|
|
369
369
|
|
|
370
370
|
</Diagram>
|
|
371
371
|
|
|
372
|
-
Access tokens are signed with `A2A_SECRET` when set, otherwise `BETTER_AUTH_SECRET`. They carry the signed user/org identity and the `mcp:read`, `mcp:write`, `mcp:apps`, and/or `offline_access` scopes, and are audience-bound to the exact MCP resource URL. `offline_access` is advertised for hosts such as ChatGPT that require it before retaining refresh access. Refresh tokens are stored only as hashes and
|
|
372
|
+
Access tokens are signed with `A2A_SECRET` when set, otherwise `BETTER_AUTH_SECRET`. They carry the signed user/org identity and the `mcp:read`, `mcp:write`, `mcp:apps`, and/or `offline_access` scopes, and are audience-bound to the exact MCP resource URL. `offline_access` is advertised for hosts such as ChatGPT that require it before retaining refresh access. Refresh tokens are stored only as hashes and are not rotated: a refresh returns the same token and resets its expiry to 365 days out. Every request and every refresh re-checks that the user still belongs to the token's organization, so a removed member loses MCP access on their next request. Tool calls and MCP Apps resource reads run inside the same request context as the signed-in user; the embedded MCP App iframe never receives raw OAuth tokens.
|
|
373
|
+
|
|
374
|
+
New MCP authorization codes and refresh tokens record their owner at issuance. Token exchanges reject unbound legacy grants or an owner-binding mismatch with `invalid_grant`, without inferring a legacy owner. An intentional email rekey updates the issuance identity. It also retires the old address: access and Connect tokens signed for it before the rekey are refused, and no new ones are issued for it unless an account registers that address again. OAuth clients get tokens for the new address on their next refresh. Offboarding revokes or deletes grants without transferring the issuance binding.
|
|
375
|
+
|
|
376
|
+
The OAuth owner-binding update requires every existing OAuth connection to [reconnect once](/docs/external-agents#reconnect). Old OAuth access tokens are refused after rollout. Unbound legacy refresh tokens return `invalid_grant`, and pending old authorization codes must restart consent. Newly issued access tokens use their configured lifetime and live membership checks. Legacy A2A-format `mcp-connect` credentials and cross-app A2A tokens are unchanged by this cutover. Connections using old OAuth-format Connect tokens must reconnect too.
|
|
373
377
|
|
|
374
378
|
`npx @agent-native/core@latest connect <url> --client claude-code` writes the URL-only MCP entry for this standard flow. For clients that cannot perform remote MCP OAuth, use the Connect page or `npx @agent-native/core@latest connect --token <token>` fallback to write an explicit bearer-token entry.
|
|
375
379
|
|
|
@@ -16,7 +16,7 @@ framework — there is no app code to write.
|
|
|
16
16
|
</Callout>
|
|
17
17
|
|
|
18
18
|
A normal hosted agent turn runs inside the synchronous request function, which
|
|
19
|
-
is capped by the platform's request timeout (
|
|
19
|
+
is capped by the platform's request timeout (60s on Netlify, and
|
|
20
20
|
the framework's ~40s soft-timeout before it has to hand back to the client and
|
|
21
21
|
"continue from where you left off"). That is fine for quick answers, but a long
|
|
22
22
|
agentic turn — many tool calls, large analyses — ends up bouncing through
|
|
@@ -45,7 +45,7 @@ the first one. Only the dispatched agent turn runs on the second.
|
|
|
45
45
|
<small class="diagram-muted">decides + dispatches</small>
|
|
46
46
|
</div>
|
|
47
47
|
<small class="diagram-muted"
|
|
48
|
-
|
|
48
|
+
>60s timeout · nearly every request</small
|
|
49
49
|
>
|
|
50
50
|
</div>
|
|
51
51
|
<div class="diagram-arrow diagram-muted" aria-hidden="true">
|
|
@@ -205,12 +205,21 @@ The foreground returns a working turn either way: the background worker when it
|
|
|
205
205
|
|
|
206
206
|
## Cost and tradeoffs {#cost}
|
|
207
207
|
|
|
208
|
-
Netlify background functions are
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
208
|
+
Netlify background functions are available on every credit-based Netlify plan,
|
|
209
|
+
including Free, and on Enterprise. They bill as functions compute, the same
|
|
210
|
+
meter as the synchronous function: 10 credits per GB-hour of runtime at the
|
|
211
|
+
function's memory size (1 GB by default). The Free plan's 300 monthly credits
|
|
212
|
+
are a hard cap, and Netlify pauses the team's projects when they run out.
|
|
213
|
+
Legacy plans (accounts created before September 4, 2025) bill functions per
|
|
214
|
+
request, and Legacy Free and Starter don't include background functions; see
|
|
215
|
+
Netlify's
|
|
216
|
+
[functions usage and billing](https://docs.netlify.com/build/functions/usage-and-billing/)
|
|
217
|
+
page.
|
|
218
|
+
|
|
219
|
+
A multi-minute agent turn therefore costs more compute than a short synchronous
|
|
220
|
+
call — but it largely **replaces** the old pattern, where the turn hit the ~40s
|
|
221
|
+
wall and the client re-issued several continuation requests. It is the same
|
|
222
|
+
work consolidated into one long invocation, not purely additive.
|
|
214
223
|
|
|
215
224
|
<Callout id="doc-block-gjoj2d" tone="info">
|
|
216
225
|
|
|
@@ -299,6 +299,8 @@ The connection is **per-user, scoped, and revocable**. In the OAuth path, the ho
|
|
|
299
299
|
|
|
300
300
|
### Re-authenticating after a 401 {#reconnect}
|
|
301
301
|
|
|
302
|
+
The OAuth owner-binding update requires every existing OAuth connection to [reconnect once](/docs/external-agents#reconnect). Old OAuth access tokens are refused after rollout. Unbound legacy refresh tokens return `invalid_grant`, and pending old authorization codes must restart consent. Newly issued access tokens use their configured lifetime and live membership checks. Legacy A2A-format `mcp-connect` credentials and cross-app A2A tokens are unchanged by this cutover. Connections using old OAuth-format Connect tokens must reconnect too.
|
|
303
|
+
|
|
302
304
|
Once connected, auth should persist long-term — access tokens last 30 days by default (override with `MCP_OAUTH_ACCESS_TOKEN_TTL` on the server, e.g. `7d` or `12h`) with a sliding 365-day refresh window, so random 401s should be rare. When one does happen, use the lightweight reconnect command rather than reinstalling:
|
|
303
305
|
|
|
304
306
|
```bash
|
|
@@ -347,7 +349,7 @@ This is the same URL-only entry that `npx @agent-native/core@latest connect http
|
|
|
347
349
|
https://dispatch.agent-native.com/mcp
|
|
348
350
|
```
|
|
349
351
|
|
|
350
|
-
The OAuth flow is authorization-code + PKCE with refresh
|
|
352
|
+
The OAuth flow is authorization-code + PKCE with refresh tokens, which are not rotated. Access tokens are audience-bound to the exact MCP resource URL and carry the signed user/org identity, so tool calls, `resources/read`, and MCP App iframe-initiated `tools/call` all run through the same `runWithRequestContext` tenant scoping as the existing connect-minted JWT path. The iframe never receives raw OAuth tokens; the host mediates calls through the authenticated MCP connection.
|
|
351
353
|
|
|
352
354
|
Current scopes are:
|
|
353
355
|
|
|
@@ -28,7 +28,7 @@ Key concepts:
|
|
|
28
28
|
- **Same actions** — the exact same action registry that powers agent chat and A2A
|
|
29
29
|
- **`ask-agent` tool** — a meta-tool that delegates to the full agent loop for complex tasks
|
|
30
30
|
- **MCP Apps** — actions can advertise interactive UI resources through the official `io.modelcontextprotocol/ui` extension
|
|
31
|
-
- **Standard remote MCP OAuth** — OAuth 2.1 discovery, dynamic client registration, authorization-code + PKCE, refresh
|
|
31
|
+
- **Standard remote MCP OAuth** — OAuth 2.1 discovery, dynamic client registration, authorization-code + PKCE, refresh tokens
|
|
32
32
|
- **Bearer auth fallback** — uses `ACCESS_TOKEN`, `ACCESS_TOKENS`, or connect-minted JWTs for clients that cannot run OAuth
|
|
33
33
|
|
|
34
34
|
## Fetch-first discovery {#fetch-first-discovery}
|
|
@@ -380,7 +380,11 @@ Access tokens are signed JWTs whose audience is the exact MCP resource URL. The
|
|
|
380
380
|
| `mcp:write` | mutating actions and `ask-agent` |
|
|
381
381
|
| `mcp:apps` | MCP Apps resources (`ui://` HTML resources) |
|
|
382
382
|
|
|
383
|
-
Refresh tokens are stored only as hashes and are rotated
|
|
383
|
+
Refresh tokens are stored only as hashes and are not rotated: a refresh returns the same token and resets its expiry to 365 days out. Every request and every refresh re-checks that the user still belongs to the token's organization, so a removed member loses MCP access on their next request. `npx @agent-native/core@latest connect` writes this URL-only OAuth entry for Claude Code clients by default; keep the Connect page, `npx @agent-native/core@latest connect --token <token>`, and static bearer config for local stdio proxying, older clients, and emergency/debug flows.
|
|
384
|
+
|
|
385
|
+
New authorization codes and refresh tokens retain their issuance owner binding. Unbound legacy grants and owner mismatches return `invalid_grant`. Renewing a revoked or deleted grant returns `invalid_grant` even when the update affects no rows. A failed renewal write returns retryable HTTP 503 with `Retry-After: 5`. Neither failure issues an access token.
|
|
386
|
+
|
|
387
|
+
The OAuth owner-binding update requires every existing OAuth connection to [reconnect once](/docs/external-agents#reconnect). Old OAuth access tokens are refused after rollout. Unbound legacy refresh tokens return `invalid_grant`, and pending old authorization codes must restart consent. Newly issued access tokens use their configured lifetime and live membership checks. Legacy A2A-format `mcp-connect` credentials and cross-app A2A tokens are unchanged by this cutover. Connections using old OAuth-format Connect tokens must reconnect too.
|
|
384
388
|
|
|
385
389
|
## Custom MCP setup {#custom-setup}
|
|
386
390
|
|
|
@@ -244,7 +244,7 @@ CREATE TEMPORARY VIEW "notes" AS
|
|
|
244
244
|
|
|
245
245
|
INSERT statements get `owner_email` auto-injected when the column isn't already present.
|
|
246
246
|
|
|
247
|
-
The `db-query`
|
|
247
|
+
The `db-query`, `db-exec`, and `db-patch` tools check SQL token boundaries and verify, inside the transaction, that each relation name resolves to one of the temporary views above. They refuse schema- or database-qualified names (`public.<table>`), relations the views do not cover, names matching functions or operators outside `pg_catalog` (including extensions), and selected built-ins that execute SQL text or access server, session, or sequence state. PostgreSQL escape-string continuation is unsupported and refused. `db-query` runs read-only. Agents use bare table names. Scoping is applied automatically. These guards scope direct SQL reads and writes and reject unapproved explicit routines and type conversions; reviewed schema defaults, constraints, triggers, casts and type I/O remain trusted database behavior. Apps can reuse these checks through `@agent-native/core/agent-sql`. Its `readAgentSqlQuery()` identifies table sources and their exact text spans in supported `SELECT`/`WITH` queries, and `rewriteAgentSqlQuerySources()` replaces those spans. Callers must enforce allowed sources and read-only execution.
|
|
248
248
|
|
|
249
249
|
### Per-Org Scoping (`org_id`)
|
|
250
250
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agent-native/core",
|
|
3
|
-
"version": "0.201.0
|
|
3
|
+
"version": "0.201.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": {
|
|
@@ -141,6 +141,7 @@
|
|
|
141
141
|
"types": "./dist/config.d.ts",
|
|
142
142
|
"default": "./dist/config.js"
|
|
143
143
|
},
|
|
144
|
+
"./agent-sql": "./dist/agent-sql/index.js",
|
|
144
145
|
"./agent-web": "./dist/agent-web/index.js",
|
|
145
146
|
"./db": "./dist/db/index.js",
|
|
146
147
|
"./db-admin": "./dist/db-admin/index.js",
|
|
@@ -668,8 +669,8 @@
|
|
|
668
669
|
"yaml": "^2.9.0",
|
|
669
670
|
"yjs": "^13.6.33",
|
|
670
671
|
"zod": "^4.3.6",
|
|
671
|
-
"@agent-native/agentkit": "^0.201.0
|
|
672
|
-
"@agent-native/recap-cli": "^0.5.61
|
|
672
|
+
"@agent-native/agentkit": "^0.201.0",
|
|
673
|
+
"@agent-native/recap-cli": "^0.5.61"
|
|
673
674
|
},
|
|
674
675
|
"devDependencies": {
|
|
675
676
|
"@ai-sdk/anthropic": "^3.0.71",
|
|
@@ -739,7 +740,7 @@
|
|
|
739
740
|
"xlsx": "^0.18.5"
|
|
740
741
|
},
|
|
741
742
|
"peerDependencies": {
|
|
742
|
-
"@agent-native/core-corpus": "0.
|
|
743
|
+
"@agent-native/core-corpus": ">=0.196.0",
|
|
743
744
|
"@ai-sdk/anthropic": ">=3",
|
|
744
745
|
"@ai-sdk/cohere": ">=3",
|
|
745
746
|
"@ai-sdk/google": ">=3",
|
|
@@ -290,9 +290,16 @@ export default defineEventHandler(async (event) => {
|
|
|
290
290
|
|
|
291
291
|
## Data Scoping
|
|
292
292
|
|
|
293
|
-
In production, the framework automatically restricts all agent SQL queries to the current user's data using temporary views
|
|
293
|
+
In production, the framework automatically restricts all agent SQL queries to the current user's data using temporary views, and checks every statement before it runs so it can only reach those views.
|
|
294
294
|
|
|
295
|
-
The `db-query` / `db-exec` tools (and the extension SQL bridge, which shares the same path)
|
|
295
|
+
The `db-query` / `db-exec` / `db-patch` tools (and the extension SQL bridge, which shares the same path) read each statement the way Postgres does and refuse anything that could reach data around the temp views:
|
|
296
|
+
|
|
297
|
+
- schema- or database-qualified names like `public.<table>`, which resolve to the base table;
|
|
298
|
+
- names that resolve to anything other than the current user's temp views, such as materialized views or tables the scoping does not cover;
|
|
299
|
+
- app-defined SQL or PL/pgSQL functions and operators, whose bodies read tables without the views;
|
|
300
|
+
- built-ins that run SQL text, change session settings, or reach outside the database (`query_to_xml`, `set_config`, `dblink`, most `pg_*` functions).
|
|
301
|
+
|
|
302
|
+
`db-query` runs in a read-only transaction, and an `INSERT` must list its columns when the table has access-control columns. Use bare table names and plain expressions; scoping is applied automatically. When the agent needs data the views do not expose, add an app action with its own access checks.
|
|
296
303
|
|
|
297
304
|
### Per-User Scoping (`owner_email`)
|
|
298
305
|
|
|
@@ -75,10 +75,11 @@ state their PostgreSQL types directly.
|
|
|
75
75
|
|
|
76
76
|
Member offboarding and email changes refuse to run while any column named
|
|
77
77
|
`email`, `*_email`, `*scope_id`, `created_by`, `updated_by`, `invited_by`,
|
|
78
|
-
`owner`, `principal_id`, `session_id`, or `user_id` has no policy.
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
78
|
+
`owner`, `principal_id`, `session_id`, or `user_id` has no policy.
|
|
79
|
+
`createSharesTable()` tables are handled for you, and undeclared `owner_email`
|
|
80
|
+
columns transfer to the successor, which is right only for owned content.
|
|
81
|
+
Declare every other one, including columns that are not member identities, from
|
|
82
|
+
the app's database plugin graph (Clips does it in `server/db/index.ts`):
|
|
82
83
|
|
|
83
84
|
```ts
|
|
84
85
|
import { registerIdentityColumns } from "@agent-native/core/org";
|
|
@@ -88,13 +89,17 @@ registerIdentityColumns([
|
|
|
88
89
|
{ table: "space_members", column: "email", emailChange: "rekey", offboard: "delete", orgScope: { column: "space_id", references: { table: "spaces", column: "id", orgColumn: "org_id" } }, reason: "Space membership grants access." },
|
|
89
90
|
// Someone else's address: never rewritten.
|
|
90
91
|
{ table: "meeting_participants", column: "email", emailChange: "retain", offboard: "retain", reason: "Attendee address from the calendar provider." },
|
|
92
|
+
// A credential in an owner_email table: never handed to the successor.
|
|
93
|
+
{ table: "api_keys", column: "owner_email", emailChange: "rekey", offboard: "revoke", reason: "Bearer keys act as their owner." },
|
|
91
94
|
]);
|
|
92
95
|
```
|
|
93
96
|
|
|
94
|
-
Choose `delete` for grants, credentials, and pending tokens
|
|
97
|
+
Choose `delete` for grants, credentials, and pending tokens, or `revoke` (sets
|
|
98
|
+
`revoked_at`) when a reader treats a missing row as "not revoked"; `retain` for
|
|
95
99
|
attribution, history, and third-party addresses; `transfer` only for owned
|
|
96
|
-
data.
|
|
97
|
-
|
|
100
|
+
data. Declare `owner_email` tables that hold credentials or grants, or
|
|
101
|
+
offboarding hands them to the successor. A table without `org_id` needs
|
|
102
|
+
`orgScope` or an organization-scoped removal leaves its rows alone.
|
|
98
103
|
|
|
99
104
|
| Template | Tables |
|
|
100
105
|
| ------------ | --------------------------------------------- |
|
|
@@ -5,7 +5,7 @@ the center, durable threads, standard app navigation, auth, live sync, and
|
|
|
5
5
|
actions. Start here when you want a real browser app to build on without
|
|
6
6
|
committing to a domain template.
|
|
7
7
|
|
|
8
|
-
**Live app: [chat.agent-native.com](https://chat.agent-native.com)**
|
|
8
|
+
**Live app: [chat.agent-native.com](https://chat.agent-native.com?utm_source=github&utm_medium=referral&utm_content=chat-readme)**
|
|
9
9
|
|
|
10
10
|
Chat is the basic agent-native app starting point. It gives you the app-agent
|
|
11
11
|
loop wired end to end and one example action, so you can add your own UI, data,
|
|
@@ -30,4 +30,4 @@ pnpm install
|
|
|
30
30
|
pnpm dev
|
|
31
31
|
```
|
|
32
32
|
|
|
33
|
-
Full docs: [agent-native.com/docs/template-chat](https://agent-native.com/docs/template-chat).
|
|
33
|
+
Full docs: [agent-native.com/docs/template-chat](https://agent-native.com/docs/template-chat?utm_source=github&utm_medium=referral&utm_content=chat-readme).
|
|
@@ -290,9 +290,16 @@ export default defineEventHandler(async (event) => {
|
|
|
290
290
|
|
|
291
291
|
## Data Scoping
|
|
292
292
|
|
|
293
|
-
In production, the framework automatically restricts all agent SQL queries to the current user's data using temporary views
|
|
293
|
+
In production, the framework automatically restricts all agent SQL queries to the current user's data using temporary views, and checks every statement before it runs so it can only reach those views.
|
|
294
294
|
|
|
295
|
-
The `db-query` / `db-exec` tools (and the extension SQL bridge, which shares the same path)
|
|
295
|
+
The `db-query` / `db-exec` / `db-patch` tools (and the extension SQL bridge, which shares the same path) read each statement the way Postgres does and refuse anything that could reach data around the temp views:
|
|
296
|
+
|
|
297
|
+
- schema- or database-qualified names like `public.<table>`, which resolve to the base table;
|
|
298
|
+
- names that resolve to anything other than the current user's temp views, such as materialized views or tables the scoping does not cover;
|
|
299
|
+
- app-defined SQL or PL/pgSQL functions and operators, whose bodies read tables without the views;
|
|
300
|
+
- built-ins that run SQL text, change session settings, or reach outside the database (`query_to_xml`, `set_config`, `dblink`, most `pg_*` functions).
|
|
301
|
+
|
|
302
|
+
`db-query` runs in a read-only transaction, and an `INSERT` must list its columns when the table has access-control columns. Use bare table names and plain expressions; scoping is applied automatically. When the agent needs data the views do not expose, add an app action with its own access checks.
|
|
296
303
|
|
|
297
304
|
### Per-User Scoping (`owner_email`)
|
|
298
305
|
|