@agent-native/core 0.79.21 → 0.79.22
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/corpus/README.md +2 -2
- package/corpus/core/CHANGELOG.md +10 -0
- package/corpus/core/docs/content/deployment.md +82 -82
- package/corpus/core/docs/content/faq.md +1 -1
- package/corpus/core/docs/content/tracking.md +3 -3
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/agent/engine/openai-compatible-endpoint.ts +25 -0
- package/corpus/core/src/agent/engine/provider-env-vars.ts +2 -0
- package/corpus/core/src/agent/engine/registry.ts +59 -11
- package/corpus/core/src/client/FeedbackButton.tsx +11 -1
- package/corpus/core/src/client/agent-engine-key.ts +57 -10
- package/corpus/core/src/client/analytics.ts +78 -27
- package/corpus/core/src/client/blocks/library/HighlightedCode.tsx +1 -1
- package/corpus/core/src/client/index.ts +2 -0
- package/corpus/core/src/client/session-replay.ts +159 -17
- package/corpus/core/src/client/settings/SettingsPanel.tsx +119 -4
- package/corpus/core/src/scripts/agent-engines/manage-agent-engine.ts +5 -0
- package/corpus/core/src/scripts/agent-engines/set-agent-engine.ts +8 -3
- package/corpus/core/src/scripts/agent-engines/test-agent-engine.ts +54 -6
- package/corpus/core/src/server/agent-engine-api-key-route.ts +83 -12
- package/corpus/core/src/server/core-routes-plugin.ts +26 -2
- package/corpus/core/src/styles/blocks.css +23 -7
- package/corpus/templates/analytics/actions/list-session-recordings.ts +1 -1
- package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +22 -4
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/SqlChartCard.tsx +64 -50
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/dashboard-layout.ts +38 -0
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/dashboard-sync.ts +89 -0
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +138 -59
- package/corpus/templates/analytics/changelog/2026-06-27-dashboard-charts-drag-smoothly-when-rearranging-panels.md +6 -0
- package/corpus/templates/analytics/changelog/2026-06-27-dashboard-email-reports-still-send-when-the-live-screenshot-.md +6 -0
- package/corpus/templates/analytics/changelog/2026-06-27-fixed-dashboard-edits-so-charts-no-longer-briefly-snap-back-.md +6 -0
- package/corpus/templates/analytics/changelog/2026-06-27-mobile-navigation-chrome-and-motion.md +1 -0
- package/corpus/templates/analytics/changelog/2026-06-27-session-replay-lists-now-show-only-signed-in-recordings-with.md +6 -0
- package/corpus/templates/analytics/changelog/2026-06-27-sidebar-loading-placeholders-are-visible-in-light-mode.md +6 -0
- package/corpus/templates/analytics/netlify.toml +4 -0
- package/corpus/templates/analytics/scripts/seed-session-replay.ts +1 -0
- package/corpus/templates/analytics/server/jobs/dashboard-report.ts +1 -0
- package/corpus/templates/analytics/server/lib/dashboard-report.ts +120 -29
- package/corpus/templates/analytics/server/lib/first-party-metric-catalog.ts +1 -1
- package/corpus/templates/analytics/server/lib/session-replay.ts +158 -46
- package/corpus/templates/assets/changelog/2026-06-27-mobile-navigation-chrome-and-motion.md +1 -0
- package/corpus/templates/clips/app/components/capture-install-options.tsx +0 -9
- package/corpus/templates/clips/changelog/2026-06-27-clips-no-longer-shows-desktop-app-prompts-on-mobile-screens.md +1 -0
- package/corpus/templates/clips/changelog/2026-06-27-recorder-download-options-now-show-the-chrome-extension-and-.md +6 -0
- package/corpus/templates/clips/changelog/2026-06-27-recorder-setup-mobile-capture-options.md +1 -0
- package/corpus/templates/clips/chrome-extension/package.json +1 -1
- package/corpus/templates/clips/chrome-extension/src/sentry.ts +17 -1
- package/corpus/templates/clips/desktop/package.json +1 -0
- package/corpus/templates/clips/desktop/scripts/check-tauri-prereqs.mjs +45 -0
- package/corpus/templates/clips/desktop/src/lib/sentry.ts +71 -0
- package/corpus/templates/clips/desktop/src/main.tsx +2 -0
- package/corpus/templates/clips/desktop/src-tauri/Cargo.toml +2 -1
- package/corpus/templates/clips/desktop/src-tauri/build.rs +29 -0
- package/corpus/templates/clips/desktop/src-tauri/src/lib.rs +3 -0
- package/corpus/templates/clips/desktop/src-tauri/src/logfile.rs +1 -0
- package/corpus/templates/clips/desktop/src-tauri/src/sentry_report.rs +142 -0
- package/corpus/templates/clips/desktop/vite.config.ts +66 -0
- package/corpus/templates/design/changelog/2026-06-27-mobile-navigation-chrome-and-motion.md +1 -0
- package/corpus/templates/forms/actions/export-responses.ts +3 -2
- package/corpus/templates/forms/actions/list-responses.ts +2 -1
- package/corpus/templates/forms/actions/response-insights.ts +13 -4
- package/corpus/templates/forms/changelog/2026-06-27-anonymous-feedback-no-longer-shows-internal-agent-native-ano.md +6 -0
- package/corpus/templates/forms/server/handlers/submissions.ts +5 -8
- package/corpus/templates/forms/server/lib/integrations.ts +9 -6
- package/corpus/templates/forms/shared/submitter-email.ts +20 -0
- package/corpus/templates/forms/shared/types.ts +1 -1
- package/corpus/templates/plan/app/components/plan/wireframe/html-artboard.css +49 -10
- package/corpus/templates/slides/changelog/2026-06-27-mobile-navigation-chrome-and-motion.md +1 -0
- package/dist/agent/engine/openai-compatible-endpoint.d.ts +3 -0
- package/dist/agent/engine/openai-compatible-endpoint.d.ts.map +1 -0
- package/dist/agent/engine/openai-compatible-endpoint.js +23 -0
- package/dist/agent/engine/openai-compatible-endpoint.js.map +1 -0
- package/dist/agent/engine/provider-env-vars.d.ts +1 -0
- package/dist/agent/engine/provider-env-vars.d.ts.map +1 -1
- package/dist/agent/engine/provider-env-vars.js +1 -0
- package/dist/agent/engine/provider-env-vars.js.map +1 -1
- package/dist/agent/engine/registry.d.ts.map +1 -1
- package/dist/agent/engine/registry.js +39 -12
- package/dist/agent/engine/registry.js.map +1 -1
- package/dist/client/FeedbackButton.d.ts.map +1 -1
- package/dist/client/FeedbackButton.js +6 -1
- package/dist/client/FeedbackButton.js.map +1 -1
- package/dist/client/agent-engine-key.d.ts +14 -0
- package/dist/client/agent-engine-key.d.ts.map +1 -1
- package/dist/client/agent-engine-key.js +35 -10
- package/dist/client/agent-engine-key.js.map +1 -1
- package/dist/client/analytics.d.ts.map +1 -1
- package/dist/client/analytics.js +71 -24
- package/dist/client/analytics.js.map +1 -1
- package/dist/client/blocks/library/HighlightedCode.d.ts +1 -1
- package/dist/client/blocks/library/HighlightedCode.js +1 -1
- package/dist/client/blocks/library/HighlightedCode.js.map +1 -1
- package/dist/client/index.d.ts +1 -1
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +1 -1
- package/dist/client/index.js.map +1 -1
- package/dist/client/session-replay.d.ts +1 -1
- package/dist/client/session-replay.d.ts.map +1 -1
- package/dist/client/session-replay.js +115 -17
- package/dist/client/session-replay.js.map +1 -1
- package/dist/client/settings/SettingsPanel.d.ts.map +1 -1
- package/dist/client/settings/SettingsPanel.js +42 -6
- package/dist/client/settings/SettingsPanel.js.map +1 -1
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/awareness.d.ts.map +1 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/file-upload/actions/upload-image.d.ts +2 -2
- package/dist/notifications/routes.d.ts +2 -2
- package/dist/observability/routes.d.ts +7 -7
- package/dist/progress/routes.d.ts +1 -1
- package/dist/scripts/agent-engines/manage-agent-engine.d.ts.map +1 -1
- package/dist/scripts/agent-engines/manage-agent-engine.js +4 -0
- package/dist/scripts/agent-engines/manage-agent-engine.js.map +1 -1
- package/dist/scripts/agent-engines/set-agent-engine.d.ts.map +1 -1
- package/dist/scripts/agent-engines/set-agent-engine.js +5 -4
- package/dist/scripts/agent-engines/set-agent-engine.js.map +1 -1
- package/dist/scripts/agent-engines/test-agent-engine.d.ts.map +1 -1
- package/dist/scripts/agent-engines/test-agent-engine.js +37 -5
- package/dist/scripts/agent-engines/test-agent-engine.js.map +1 -1
- package/dist/server/agent-engine-api-key-route.d.ts +4 -4
- package/dist/server/agent-engine-api-key-route.d.ts.map +1 -1
- package/dist/server/agent-engine-api-key-route.js +71 -11
- package/dist/server/agent-engine-api-key-route.js.map +1 -1
- package/dist/server/core-routes-plugin.d.ts.map +1 -1
- package/dist/server/core-routes-plugin.js +20 -3
- package/dist/server/core-routes-plugin.js.map +1 -1
- package/dist/styles/blocks.css +23 -7
- package/docs/content/deployment.md +82 -82
- package/docs/content/faq.md +1 -1
- package/docs/content/tracking.md +3 -3
- package/package.json +1 -1
package/corpus/README.md
CHANGED
package/corpus/core/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# @agent-native/core
|
|
2
2
|
|
|
3
|
+
## 0.79.22
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- cdf41db: Require signed-in email identity for browser session replay by default across templates and send replay timing/event-count metadata with each upload. Apps that intentionally record anonymous replay sessions can opt out with `sessionReplay.requireSignedInUser: false` or `VITE_AGENT_NATIVE_SESSION_REPLAY_REQUIRE_AUTH=false`.
|
|
8
|
+
- cdf41db: Keep diagram primitive borders visible in sketchy Plan diagrams and stop the shared feedback button from sending synthetic anonymous Agent Native emails.
|
|
9
|
+
- cdf41db: Add an advanced OpenAI-compatible endpoint URL setting for custom gateways like LiteLLM.
|
|
10
|
+
- cdf41db: Default shared expandable code surfaces to 30 visible lines before the reader
|
|
11
|
+
expands them.
|
|
12
|
+
|
|
3
13
|
## 0.79.21
|
|
4
14
|
|
|
5
15
|
### Patch Changes
|
|
@@ -66,6 +66,85 @@ background processors. Local `--build-only` artifact checks still run without it
|
|
|
66
66
|
|
|
67
67
|
Per-app independent deploy is still supported — just `cd apps/<name> && npx @agent-native/core@latest build` like a standalone scaffold.
|
|
68
68
|
|
|
69
|
+
## How It Works {#how-it-works}
|
|
70
|
+
|
|
71
|
+
When you run `npx @agent-native/core@latest build`, Nitro builds both the client SPA and the server API into `.output/`:
|
|
72
|
+
|
|
73
|
+
```an-file-tree title="Build output"
|
|
74
|
+
{
|
|
75
|
+
"entries": [
|
|
76
|
+
{ "path": ".output/", "note": "self-contained — copy to any environment and run" },
|
|
77
|
+
{ "path": ".output/public/", "note": "built SPA (static assets)" },
|
|
78
|
+
{ "path": ".output/server/index.mjs", "note": "server entry point" },
|
|
79
|
+
{ "path": ".output/server/chunks/", "note": "server code chunks" }
|
|
80
|
+
]
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
The output is self-contained — copy `.output/` to any environment and run it.
|
|
85
|
+
|
|
86
|
+
```an-diagram title="Build to deploy" summary="One source tree builds to a Nitro preset; the same self-contained output runs on Node, Vercel, Netlify, Cloudflare, AWS, or Deno. Every instance points at the same persistent DATABASE_URL."
|
|
87
|
+
{
|
|
88
|
+
"html": "<div class=\"diagram-deploy\"><div class=\"diagram-box\" data-rough>App source</div><div class=\"diagram-arrow diagram-muted\" aria-hidden=\"true\">→</div><div class=\"diagram-panel center\" data-rough><span class=\"diagram-pill accent\">build</span><small class=\"diagram-muted\">Nitro preset</small></div><div class=\"diagram-arrow diagram-muted\" aria-hidden=\"true\">→</div><div class=\"diagram-grid\"><span class=\"diagram-pill\">Node.js</span><span class=\"diagram-pill\">Vercel</span><span class=\"diagram-pill\">Netlify</span><span class=\"diagram-pill\">Cloudflare</span><span class=\"diagram-pill\">AWS Lambda</span><span class=\"diagram-pill\">Deno</span></div><div class=\"diagram-arrow diagram-muted\" aria-hidden=\"true\">→</div><div class=\"diagram-box\" data-rough>Persistent DATABASE_URL<br><small class=\"diagram-muted\">shared by every instance</small></div></div>",
|
|
89
|
+
"css": ".diagram-deploy{display:flex;align-items:center;gap:12px;flex-wrap:wrap}.diagram-deploy .center{display:flex;flex-direction:column;align-items:center;gap:4px;padding:14px 16px}.diagram-deploy .diagram-arrow{font-size:22px;line-height:1}.diagram-deploy .diagram-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:8px}"
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Setting the Preset {#setting-the-preset}
|
|
94
|
+
|
|
95
|
+
By default, Nitro builds for Node.js. To target a different platform, set the preset in your `vite.config.ts`:
|
|
96
|
+
|
|
97
|
+
```ts
|
|
98
|
+
import { agentNative } from "@agent-native/core/vite";
|
|
99
|
+
import { defineConfig } from "vite";
|
|
100
|
+
|
|
101
|
+
export default defineConfig({
|
|
102
|
+
plugins: [agentNative({ nitro: { preset: "vercel" } })],
|
|
103
|
+
});
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Or use the `NITRO_PRESET` environment variable at build time:
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
NITRO_PRESET=netlify npx @agent-native/core@latest build
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## Node.js (Default) {#nodejs}
|
|
113
|
+
|
|
114
|
+
The default preset. Build and run:
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
npx @agent-native/core@latest build
|
|
118
|
+
node .output/server/index.mjs
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Set `PORT` to configure the listen port (default: `3000`).
|
|
122
|
+
|
|
123
|
+
Use the current Node.js LTS line for production deploys. As of May 2026, that
|
|
124
|
+
is Node.js 24; Node.js 20 reached end-of-life on April 30, 2026 and no longer
|
|
125
|
+
receives upstream security updates.
|
|
126
|
+
|
|
127
|
+
### Docker {#docker}
|
|
128
|
+
|
|
129
|
+
```dockerfile
|
|
130
|
+
FROM node:24-slim AS build
|
|
131
|
+
WORKDIR /app
|
|
132
|
+
COPY package.json pnpm-lock.yaml ./
|
|
133
|
+
RUN corepack enable && pnpm install --frozen-lockfile
|
|
134
|
+
COPY . .
|
|
135
|
+
RUN pnpm build
|
|
136
|
+
|
|
137
|
+
FROM node:24-slim
|
|
138
|
+
WORKDIR /app
|
|
139
|
+
COPY --from=build /app/.output .output
|
|
140
|
+
# data/ is a runtime-created SQLite directory — do not copy a dev DB into prod.
|
|
141
|
+
# For production, set DATABASE_URL to a hosted Postgres or Turso instance.
|
|
142
|
+
RUN mkdir -p /app/data
|
|
143
|
+
ENV PORT=3000
|
|
144
|
+
EXPOSE 3000
|
|
145
|
+
CMD ["node", ".output/server/index.mjs"]
|
|
146
|
+
```
|
|
147
|
+
|
|
69
148
|
### Self-hosted workspace with Docker Compose {#workspace-docker-compose}
|
|
70
149
|
|
|
71
150
|
The Dockerfile above is for one standalone app. A workspace is not one Nitro
|
|
@@ -79,7 +158,7 @@ Build each app with the same base path that the proxy will use at runtime. The
|
|
|
79
158
|
base path is a build-time input for the client bundle and a runtime input for
|
|
80
159
|
the server:
|
|
81
160
|
|
|
82
|
-
```bash
|
|
161
|
+
```bash maxLines=8
|
|
83
162
|
APP_BASE_PATH=/mail VITE_APP_BASE_PATH=/mail npx @agent-native/core@latest build
|
|
84
163
|
node .output/server/index.mjs
|
|
85
164
|
```
|
|
@@ -87,7 +166,7 @@ node .output/server/index.mjs
|
|
|
87
166
|
A reusable workspace Dockerfile can take the app name and path prefix as build
|
|
88
167
|
arguments:
|
|
89
168
|
|
|
90
|
-
```dockerfile
|
|
169
|
+
```dockerfile maxLines=12
|
|
91
170
|
FROM node:24-slim AS build
|
|
92
171
|
WORKDIR /workspace
|
|
93
172
|
RUN corepack enable
|
|
@@ -117,7 +196,7 @@ Then compose Postgres, the app containers, and your proxy. This example uses
|
|
|
117
196
|
Caddy because it can terminate HTTP locally or sit behind Cloudflare's SSL
|
|
118
197
|
proxy, but the important part is the path-prefix routing:
|
|
119
198
|
|
|
120
|
-
```yaml
|
|
199
|
+
```yaml maxLines=30
|
|
121
200
|
services:
|
|
122
201
|
postgres:
|
|
123
202
|
image: postgres:17
|
|
@@ -199,85 +278,6 @@ Notes for this shape:
|
|
|
199
278
|
normal `X-Forwarded-Proto` / `X-Forwarded-Host` headers and route the public
|
|
200
279
|
host to the proxy container.
|
|
201
280
|
|
|
202
|
-
## How It Works {#how-it-works}
|
|
203
|
-
|
|
204
|
-
When you run `npx @agent-native/core@latest build`, Nitro builds both the client SPA and the server API into `.output/`:
|
|
205
|
-
|
|
206
|
-
```an-file-tree title="Build output"
|
|
207
|
-
{
|
|
208
|
-
"entries": [
|
|
209
|
-
{ "path": ".output/", "note": "self-contained — copy to any environment and run" },
|
|
210
|
-
{ "path": ".output/public/", "note": "built SPA (static assets)" },
|
|
211
|
-
{ "path": ".output/server/index.mjs", "note": "server entry point" },
|
|
212
|
-
{ "path": ".output/server/chunks/", "note": "server code chunks" }
|
|
213
|
-
]
|
|
214
|
-
}
|
|
215
|
-
```
|
|
216
|
-
|
|
217
|
-
The output is self-contained — copy `.output/` to any environment and run it.
|
|
218
|
-
|
|
219
|
-
```an-diagram title="Build to deploy" summary="One source tree builds to a Nitro preset; the same self-contained output runs on Node, Vercel, Netlify, Cloudflare, AWS, or Deno. Every instance points at the same persistent DATABASE_URL."
|
|
220
|
-
{
|
|
221
|
-
"html": "<div class=\"diagram-deploy\"><div class=\"diagram-box\" data-rough>App source</div><div class=\"diagram-arrow diagram-muted\" aria-hidden=\"true\">→</div><div class=\"diagram-panel center\" data-rough><span class=\"diagram-pill accent\">build</span><small class=\"diagram-muted\">Nitro preset</small></div><div class=\"diagram-arrow diagram-muted\" aria-hidden=\"true\">→</div><div class=\"diagram-grid\"><span class=\"diagram-pill\">Node.js</span><span class=\"diagram-pill\">Vercel</span><span class=\"diagram-pill\">Netlify</span><span class=\"diagram-pill\">Cloudflare</span><span class=\"diagram-pill\">AWS Lambda</span><span class=\"diagram-pill\">Deno</span></div><div class=\"diagram-arrow diagram-muted\" aria-hidden=\"true\">→</div><div class=\"diagram-box\" data-rough>Persistent DATABASE_URL<br><small class=\"diagram-muted\">shared by every instance</small></div></div>",
|
|
222
|
-
"css": ".diagram-deploy{display:flex;align-items:center;gap:12px;flex-wrap:wrap}.diagram-deploy .center{display:flex;flex-direction:column;align-items:center;gap:4px;padding:14px 16px}.diagram-deploy .diagram-arrow{font-size:22px;line-height:1}.diagram-deploy .diagram-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:8px}"
|
|
223
|
-
}
|
|
224
|
-
```
|
|
225
|
-
|
|
226
|
-
## Setting the Preset {#setting-the-preset}
|
|
227
|
-
|
|
228
|
-
By default, Nitro builds for Node.js. To target a different platform, set the preset in your `vite.config.ts`:
|
|
229
|
-
|
|
230
|
-
```ts
|
|
231
|
-
import { agentNative } from "@agent-native/core/vite";
|
|
232
|
-
import { defineConfig } from "vite";
|
|
233
|
-
|
|
234
|
-
export default defineConfig({
|
|
235
|
-
plugins: [agentNative({ nitro: { preset: "vercel" } })],
|
|
236
|
-
});
|
|
237
|
-
```
|
|
238
|
-
|
|
239
|
-
Or use the `NITRO_PRESET` environment variable at build time:
|
|
240
|
-
|
|
241
|
-
```bash
|
|
242
|
-
NITRO_PRESET=netlify npx @agent-native/core@latest build
|
|
243
|
-
```
|
|
244
|
-
|
|
245
|
-
## Node.js (Default) {#nodejs}
|
|
246
|
-
|
|
247
|
-
The default preset. Build and run:
|
|
248
|
-
|
|
249
|
-
```bash
|
|
250
|
-
npx @agent-native/core@latest build
|
|
251
|
-
node .output/server/index.mjs
|
|
252
|
-
```
|
|
253
|
-
|
|
254
|
-
Set `PORT` to configure the listen port (default: `3000`).
|
|
255
|
-
|
|
256
|
-
Use the current Node.js LTS line for production deploys. As of May 2026, that
|
|
257
|
-
is Node.js 24; Node.js 20 reached end-of-life on April 30, 2026 and no longer
|
|
258
|
-
receives upstream security updates.
|
|
259
|
-
|
|
260
|
-
### Docker {#docker}
|
|
261
|
-
|
|
262
|
-
```dockerfile
|
|
263
|
-
FROM node:24-slim AS build
|
|
264
|
-
WORKDIR /app
|
|
265
|
-
COPY package.json pnpm-lock.yaml ./
|
|
266
|
-
RUN corepack enable && pnpm install --frozen-lockfile
|
|
267
|
-
COPY . .
|
|
268
|
-
RUN pnpm build
|
|
269
|
-
|
|
270
|
-
FROM node:24-slim
|
|
271
|
-
WORKDIR /app
|
|
272
|
-
COPY --from=build /app/.output .output
|
|
273
|
-
# data/ is a runtime-created SQLite directory — do not copy a dev DB into prod.
|
|
274
|
-
# For production, set DATABASE_URL to a hosted Postgres or Turso instance.
|
|
275
|
-
RUN mkdir -p /app/data
|
|
276
|
-
ENV PORT=3000
|
|
277
|
-
EXPOSE 3000
|
|
278
|
-
CMD ["node", ".output/server/index.mjs"]
|
|
279
|
-
```
|
|
280
|
-
|
|
281
281
|
## Vercel {#vercel}
|
|
282
282
|
|
|
283
283
|
```ts
|
|
@@ -54,7 +54,7 @@ Yes. Pick any host that runs Node — Netlify, Vercel, Cloudflare, AWS, Deno Dep
|
|
|
54
54
|
|
|
55
55
|
### What AI models does it support? {#what-models}
|
|
56
56
|
|
|
57
|
-
Anthropic Claude, OpenAI (GPT-5 family), Google Gemini, and any provider that speaks the OpenAI API shape
|
|
57
|
+
Anthropic Claude, OpenAI (GPT-5 family), Google Gemini, and any provider that speaks the OpenAI API shape. For OpenAI-compatible gateways like LiteLLM, choose OpenAI in Settings and add the gateway URL under Advanced. You configure the model in settings; switching is a config change, not a code rewrite. The framework's heaviest tested path is Claude, so that's the default recommendation.
|
|
58
58
|
|
|
59
59
|
### Do I need to know AI/ML? {#do-i-need-to-know-ai}
|
|
60
60
|
|
|
@@ -144,7 +144,6 @@ configureTracking({
|
|
|
144
144
|
endpoint: "https://analytics.example.com/api/analytics/track",
|
|
145
145
|
sessionReplay: {
|
|
146
146
|
enabled: true,
|
|
147
|
-
requireSignedInUser: true,
|
|
148
147
|
sampleRate: 0.1,
|
|
149
148
|
},
|
|
150
149
|
getDefaultProps: (_event, props) => ({
|
|
@@ -163,11 +162,12 @@ Agent Native template roots already call `configureTracking()`. Hosted template
|
|
|
163
162
|
VITE_AGENT_NATIVE_ANALYTICS_PUBLIC_KEY=anpk_...
|
|
164
163
|
VITE_AGENT_NATIVE_ANALYTICS_ENDPOINT=https://analytics.example.com/api/analytics/track
|
|
165
164
|
VITE_AGENT_NATIVE_SESSION_REPLAY_ENABLED=true
|
|
166
|
-
VITE_AGENT_NATIVE_SESSION_REPLAY_REQUIRE_AUTH=true
|
|
167
165
|
VITE_AGENT_NATIVE_SESSION_REPLAY_SAMPLE_RATE=0.1
|
|
168
166
|
```
|
|
169
167
|
|
|
170
|
-
The browser helper also performs a best-effort, non-blocking read of the current Agent Native auth session.
|
|
168
|
+
The browser helper also performs a best-effort, non-blocking read of the current Agent Native auth session. Replay is signed-in-only by default: when `sessionReplay` is enabled, recording does not start unless the session resolves to a user email address. Signed-in replays include email-backed `userId`/`userEmail` plus `orgId`.
|
|
169
|
+
|
|
170
|
+
Set `sessionReplay.requireSignedInUser: false` or `VITE_AGENT_NATIVE_SESSION_REPLAY_REQUIRE_AUTH=false` only for an intentional anonymous replay deployment. When auth gating is disabled, anonymous recordings remain queryable by anonymous visitor, session, app/template, hostname, and path.
|
|
171
171
|
|
|
172
172
|
Session replay is sampled deterministically per browser session. A `sampleRate` of `0.1` records about 10% of eligible sessions; use `1` when the eligible population is intentionally small, such as logged-in-only dogfooding.
|
|
173
173
|
|
package/corpus/core/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agent-native/core",
|
|
3
|
-
"version": "0.79.
|
|
3
|
+
"version": "0.79.22",
|
|
4
4
|
"description": "Framework for agent-native application development — where AI agents and UI share SQL state, actions, and context",
|
|
5
5
|
"homepage": "https://github.com/BuilderIO/agent-native#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export const OPENAI_BASE_URL_ENV_VAR = "OPENAI_BASE_URL";
|
|
2
|
+
|
|
3
|
+
export function normalizeOpenAiBaseUrl(value: string): string {
|
|
4
|
+
const trimmed = value.trim();
|
|
5
|
+
if (!trimmed) {
|
|
6
|
+
throw new Error("Endpoint URL is required.");
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
let url: URL;
|
|
10
|
+
try {
|
|
11
|
+
url = new URL(trimmed);
|
|
12
|
+
} catch {
|
|
13
|
+
throw new Error("Endpoint URL must be a valid URL.");
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
if (url.protocol !== "https:" && url.protocol !== "http:") {
|
|
17
|
+
throw new Error("Endpoint URL must start with http:// or https://.");
|
|
18
|
+
}
|
|
19
|
+
if (url.username || url.password) {
|
|
20
|
+
throw new Error("Endpoint URL must not include credentials.");
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
url.hash = "";
|
|
24
|
+
return url.toString().replace(/\/+$/, "");
|
|
25
|
+
}
|
|
@@ -16,6 +16,8 @@ export interface ProviderEnvMeta {
|
|
|
16
16
|
placeholder: string;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
+
export { OPENAI_BASE_URL_ENV_VAR } from "./openai-compatible-endpoint.js";
|
|
20
|
+
|
|
19
21
|
export const PROVIDER_ENV_META: Record<string, ProviderEnvMeta> = {
|
|
20
22
|
anthropic: {
|
|
21
23
|
envVar: "ANTHROPIC_API_KEY",
|
|
@@ -18,6 +18,10 @@ import {
|
|
|
18
18
|
} from "../../server/credential-provider.js";
|
|
19
19
|
import { getSetting } from "../../settings/store.js";
|
|
20
20
|
import { getAgentAppModelDefaultForCurrentRequest } from "../app-model-defaults.js";
|
|
21
|
+
import {
|
|
22
|
+
normalizeOpenAiBaseUrl,
|
|
23
|
+
OPENAI_BASE_URL_ENV_VAR,
|
|
24
|
+
} from "./openai-compatible-endpoint.js";
|
|
21
25
|
import type { AgentEngine, EngineCapabilities } from "./types.js";
|
|
22
26
|
|
|
23
27
|
const require = createRequire(import.meta.url);
|
|
@@ -324,6 +328,39 @@ function engineCreateConfig(
|
|
|
324
328
|
};
|
|
325
329
|
}
|
|
326
330
|
|
|
331
|
+
async function resolveOpenAiBaseUrl(): Promise<string | undefined> {
|
|
332
|
+
let raw: string | null | undefined = null;
|
|
333
|
+
try {
|
|
334
|
+
raw = await resolveSecret(OPENAI_BASE_URL_ENV_VAR);
|
|
335
|
+
} catch {
|
|
336
|
+
raw = null;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
if (!raw && canUseDeployCredentialFallbackForRequest()) {
|
|
340
|
+
raw = readDeployCredentialEnv(OPENAI_BASE_URL_ENV_VAR);
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
return raw ? normalizeOpenAiBaseUrl(raw) : undefined;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
async function engineCreateConfigForEntry(
|
|
347
|
+
entry: AgentEngineEntry,
|
|
348
|
+
apiKey: string | undefined,
|
|
349
|
+
extra?: Record<string, unknown>,
|
|
350
|
+
): Promise<Record<string, unknown>> {
|
|
351
|
+
const safeExtra = { ...(extra ?? {}) };
|
|
352
|
+
if (entry.name === "ai-sdk:openai") {
|
|
353
|
+
if (typeof safeExtra.baseURL === "string" && safeExtra.baseUrl == null) {
|
|
354
|
+
safeExtra.baseUrl = normalizeOpenAiBaseUrl(safeExtra.baseURL);
|
|
355
|
+
}
|
|
356
|
+
if (safeExtra.baseUrl == null) {
|
|
357
|
+
const baseUrl = await resolveOpenAiBaseUrl();
|
|
358
|
+
if (baseUrl) safeExtra.baseUrl = baseUrl;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
return engineCreateConfig(apiKey, safeExtra);
|
|
362
|
+
}
|
|
363
|
+
|
|
327
364
|
/**
|
|
328
365
|
* True when the stored `agent-engine` row points at a registered engine
|
|
329
366
|
* AND an API key for it is reachable via the engine's required env vars.
|
|
@@ -432,7 +469,9 @@ export async function resolveEngine(
|
|
|
432
469
|
`[agent-engine] Unknown engine: "${name}". Registered: ${[..._registry.keys()].join(", ")}`,
|
|
433
470
|
);
|
|
434
471
|
assertAgentEnginePackageInstalled(entry);
|
|
435
|
-
return entry.create(
|
|
472
|
+
return entry.create(
|
|
473
|
+
await engineCreateConfigForEntry(entry, apiKey, engineConfig),
|
|
474
|
+
);
|
|
436
475
|
}
|
|
437
476
|
|
|
438
477
|
// 3. Explicit string name from options
|
|
@@ -443,7 +482,7 @@ export async function resolveEngine(
|
|
|
443
482
|
`[agent-engine] Unknown engine: "${engineOption}". Registered: ${[..._registry.keys()].join(", ")}`,
|
|
444
483
|
);
|
|
445
484
|
assertAgentEnginePackageInstalled(entry);
|
|
446
|
-
return entry.create(
|
|
485
|
+
return entry.create(await engineCreateConfigForEntry(entry, apiKey));
|
|
447
486
|
}
|
|
448
487
|
|
|
449
488
|
// 4. Env var — explicit engine name override
|
|
@@ -452,7 +491,7 @@ export async function resolveEngine(
|
|
|
452
491
|
const entry = _registry.get(envEngine);
|
|
453
492
|
if (entry) {
|
|
454
493
|
assertAgentEnginePackageInstalled(entry);
|
|
455
|
-
return entry.create(
|
|
494
|
+
return entry.create(await engineCreateConfigForEntry(entry, apiKey));
|
|
456
495
|
}
|
|
457
496
|
}
|
|
458
497
|
|
|
@@ -460,7 +499,7 @@ export async function resolveEngine(
|
|
|
460
499
|
if (appDefault?.engine) {
|
|
461
500
|
const entry = _registry.get(appDefault.engine);
|
|
462
501
|
if (entry && (await isStoredEngineUsableForRequest(appDefault, entry))) {
|
|
463
|
-
return entry.create(
|
|
502
|
+
return entry.create(await engineCreateConfigForEntry(entry, apiKey));
|
|
464
503
|
}
|
|
465
504
|
}
|
|
466
505
|
|
|
@@ -477,7 +516,9 @@ export async function resolveEngine(
|
|
|
477
516
|
// Builder connection wins over a stale deploy-level/provider key.
|
|
478
517
|
const detectedFromUser = await detectEngineFromUserSecrets();
|
|
479
518
|
if (detectedFromUser?.name === "builder") {
|
|
480
|
-
return detectedFromUser.create(
|
|
519
|
+
return detectedFromUser.create(
|
|
520
|
+
await engineCreateConfigForEntry(detectedFromUser, apiKey),
|
|
521
|
+
);
|
|
481
522
|
}
|
|
482
523
|
|
|
483
524
|
// 6. Settings store — only when the stored row's API key is reachable.
|
|
@@ -490,19 +531,22 @@ export async function resolveEngine(
|
|
|
490
531
|
if (storedRaw && typeof storedEngine === "string") {
|
|
491
532
|
const entry = _registry.get(storedEngine);
|
|
492
533
|
if (entry && (await isStoredEngineUsableForRequest(storedRaw, entry))) {
|
|
493
|
-
return entry.create(
|
|
494
|
-
|
|
534
|
+
return entry.create(
|
|
535
|
+
await engineCreateConfigForEntry(
|
|
536
|
+
entry,
|
|
495
537
|
apiKey,
|
|
496
538
|
stripInlineApiKeyConfig(
|
|
497
539
|
storedConfig as Record<string, unknown> | undefined,
|
|
498
540
|
),
|
|
499
541
|
),
|
|
500
|
-
|
|
542
|
+
);
|
|
501
543
|
}
|
|
502
544
|
}
|
|
503
545
|
|
|
504
546
|
if (detectedFromUser) {
|
|
505
|
-
return detectedFromUser.create(
|
|
547
|
+
return detectedFromUser.create(
|
|
548
|
+
await engineCreateConfigForEntry(detectedFromUser, apiKey),
|
|
549
|
+
);
|
|
506
550
|
}
|
|
507
551
|
|
|
508
552
|
// 8. Auto-detect from any provider env var — so just dropping a key in
|
|
@@ -510,7 +554,9 @@ export async function resolveEngine(
|
|
|
510
554
|
const detected = canUseDeployCredentialFallbackForRequest()
|
|
511
555
|
? detectEngineFromEnv()
|
|
512
556
|
: null;
|
|
513
|
-
if (detected)
|
|
557
|
+
if (detected) {
|
|
558
|
+
return detected.create(await engineCreateConfigForEntry(detected, apiKey));
|
|
559
|
+
}
|
|
514
560
|
|
|
515
561
|
// 9. Default: anthropic
|
|
516
562
|
const anthropicEntry = _registry.get("anthropic");
|
|
@@ -519,7 +565,9 @@ export async function resolveEngine(
|
|
|
519
565
|
"[agent-engine] Default Anthropic engine is not registered. Did builtin.ts fail to load?",
|
|
520
566
|
);
|
|
521
567
|
}
|
|
522
|
-
return anthropicEntry.create(
|
|
568
|
+
return anthropicEntry.create(
|
|
569
|
+
await engineCreateConfigForEntry(anthropicEntry, apiKey),
|
|
570
|
+
);
|
|
523
571
|
}
|
|
524
572
|
|
|
525
573
|
/**
|
|
@@ -20,6 +20,12 @@ import { cn } from "./utils.js";
|
|
|
20
20
|
const DEFAULT_FEEDBACK_URL =
|
|
21
21
|
"https://forms.agent-native.com/f/agent-native-feedback/_16ewV";
|
|
22
22
|
|
|
23
|
+
function isSyntheticAgentNativeAnonymousEmail(
|
|
24
|
+
value: string | null | undefined,
|
|
25
|
+
): boolean {
|
|
26
|
+
return /^anon-[^\s@]+@agent-native\.com$/i.test(value ?? "");
|
|
27
|
+
}
|
|
28
|
+
|
|
23
29
|
interface ParsedTarget {
|
|
24
30
|
endpoint: string;
|
|
25
31
|
slug: string;
|
|
@@ -342,7 +348,11 @@ export function FeedbackButton({
|
|
|
342
348
|
try {
|
|
343
349
|
const resolvedSchema = schema ?? (await loadSchema(target));
|
|
344
350
|
if (!schema) setSchema(resolvedSchema);
|
|
345
|
-
const submitterEmail =
|
|
351
|
+
const submitterEmail = isSyntheticAgentNativeAnonymousEmail(
|
|
352
|
+
session?.email,
|
|
353
|
+
)
|
|
354
|
+
? null
|
|
355
|
+
: session?.email;
|
|
346
356
|
const feedbackContext = getFeedbackClientContext({
|
|
347
357
|
chatSessionId,
|
|
348
358
|
storageKey: chatStorageKey,
|
|
@@ -29,6 +29,32 @@ export interface SaveAgentEngineApiKeyOptions {
|
|
|
29
29
|
scope?: "user" | "org";
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
+
export interface SaveAgentEngineProviderSettingsOptions {
|
|
33
|
+
provider?: AgentEngineProvider;
|
|
34
|
+
key?: string;
|
|
35
|
+
apiKey?: string;
|
|
36
|
+
baseUrl?: string;
|
|
37
|
+
clearBaseUrl?: boolean;
|
|
38
|
+
scope?: "user" | "org";
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function resolveProviderEnvVar(
|
|
42
|
+
provider: AgentEngineProvider | undefined,
|
|
43
|
+
key: string | undefined,
|
|
44
|
+
): string {
|
|
45
|
+
const envVar = key?.trim() || (provider ? PROVIDER_ENV_VAR[provider] : "");
|
|
46
|
+
if (!envVar) {
|
|
47
|
+
throw new Error("Choose an API key provider first.");
|
|
48
|
+
}
|
|
49
|
+
return envVar;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function dispatchConfiguredChanged(): void {
|
|
53
|
+
if (typeof window !== "undefined") {
|
|
54
|
+
window.dispatchEvent(new CustomEvent(CONFIGURED_CHANGED_EVENT));
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
32
58
|
/**
|
|
33
59
|
* Persist a provider API key for the current owner. Resolves on success.
|
|
34
60
|
* Throws an Error with a readable message on failure. On success it also
|
|
@@ -41,20 +67,43 @@ export async function saveAgentEngineApiKey({
|
|
|
41
67
|
apiKey,
|
|
42
68
|
scope,
|
|
43
69
|
}: SaveAgentEngineApiKeyOptions): Promise<void> {
|
|
44
|
-
|
|
45
|
-
if (!trimmed) {
|
|
70
|
+
if (!apiKey.trim()) {
|
|
46
71
|
throw new Error("Enter an API key first.");
|
|
47
72
|
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
73
|
+
await saveAgentEngineProviderSettings({ provider, key, apiKey, scope });
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Persist provider-specific settings for the current owner. This intentionally
|
|
78
|
+
* stays narrow: API keys for built-in BYOK providers, plus OpenAI's optional
|
|
79
|
+
* compatible endpoint URL. Values are stored server-side in scoped secrets.
|
|
80
|
+
*/
|
|
81
|
+
export async function saveAgentEngineProviderSettings({
|
|
82
|
+
provider,
|
|
83
|
+
key,
|
|
84
|
+
apiKey,
|
|
85
|
+
baseUrl,
|
|
86
|
+
clearBaseUrl,
|
|
87
|
+
scope,
|
|
88
|
+
}: SaveAgentEngineProviderSettingsOptions): Promise<void> {
|
|
89
|
+
const trimmed = apiKey?.trim() ?? "";
|
|
90
|
+
const endpoint = baseUrl?.trim() ?? "";
|
|
91
|
+
if (!trimmed && !endpoint && !clearBaseUrl) {
|
|
92
|
+
throw new Error("Enter an API key or endpoint URL first.");
|
|
51
93
|
}
|
|
94
|
+
const envVar = resolveProviderEnvVar(provider, key);
|
|
52
95
|
const res = await fetch(
|
|
53
96
|
agentNativePath("/_agent-native/agent-engine/api-key"),
|
|
54
97
|
{
|
|
55
98
|
method: "POST",
|
|
56
99
|
headers: { "Content-Type": "application/json" },
|
|
57
|
-
body: JSON.stringify({
|
|
100
|
+
body: JSON.stringify({
|
|
101
|
+
key: envVar,
|
|
102
|
+
...(trimmed ? { value: trimmed } : {}),
|
|
103
|
+
...(endpoint ? { baseUrl: endpoint } : {}),
|
|
104
|
+
...(clearBaseUrl ? { clearBaseUrl: true } : {}),
|
|
105
|
+
scope,
|
|
106
|
+
}),
|
|
58
107
|
},
|
|
59
108
|
);
|
|
60
109
|
if (!res.ok) {
|
|
@@ -66,10 +115,8 @@ export async function saveAgentEngineApiKey({
|
|
|
66
115
|
message ??
|
|
67
116
|
(res.status === 401
|
|
68
117
|
? "Sign in to save a key, or connect Builder instead."
|
|
69
|
-
: `Could not save
|
|
118
|
+
: `Could not save provider settings (HTTP ${res.status}).`),
|
|
70
119
|
);
|
|
71
120
|
}
|
|
72
|
-
|
|
73
|
-
window.dispatchEvent(new CustomEvent(CONFIGURED_CHANGED_EVENT));
|
|
74
|
-
}
|
|
121
|
+
dispatchConfiguredChanged();
|
|
75
122
|
}
|