create-atlas-agent 0.2.5
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 +69 -0
- package/index.ts +526 -0
- package/package.json +33 -0
- package/template/.env.example +49 -0
- package/template/Dockerfile +31 -0
- package/template/bin/atlas.ts +1092 -0
- package/template/bin/enrich.ts +551 -0
- package/template/data/.gitkeep +0 -0
- package/template/data/demo-sqlite.sql +372 -0
- package/template/data/demo.sql +371 -0
- package/template/docker-compose.yml +23 -0
- package/template/docs/deploy.md +341 -0
- package/template/eslint.config.mjs +18 -0
- package/template/fly.toml +46 -0
- package/template/gitignore +5 -0
- package/template/next.config.ts +8 -0
- package/template/package.json +55 -0
- package/template/postcss.config.mjs +8 -0
- package/template/public/.gitkeep +0 -0
- package/template/railway.json +13 -0
- package/template/render.yaml +19 -0
- package/template/semantic/catalog.yml +5 -0
- package/template/semantic/entities/.gitkeep +0 -0
- package/template/semantic/glossary.yml +6 -0
- package/template/semantic/metrics/.gitkeep +0 -0
- package/template/src/app/api/chat/route.ts +107 -0
- package/template/src/app/api/health/route.ts +97 -0
- package/template/src/app/error.tsx +24 -0
- package/template/src/app/globals.css +1 -0
- package/template/src/app/layout.tsx +19 -0
- package/template/src/app/page.tsx +650 -0
- package/template/src/global.d.ts +1 -0
- package/template/src/lib/agent.ts +112 -0
- package/template/src/lib/db/connection.ts +150 -0
- package/template/src/lib/providers.ts +63 -0
- package/template/src/lib/semantic.ts +53 -0
- package/template/src/lib/startup.ts +211 -0
- package/template/src/lib/tools/__tests__/sql.test.ts +538 -0
- package/template/src/lib/tools/explore-sandbox.ts +189 -0
- package/template/src/lib/tools/explore.ts +164 -0
- package/template/src/lib/tools/report.ts +33 -0
- package/template/src/lib/tools/sql.ts +202 -0
- package/template/src/types/vercel-sandbox.d.ts +54 -0
- package/template/tsconfig.json +41 -0
- package/template/vercel.json +3 -0
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
# Deploy Guides
|
|
2
|
+
|
|
3
|
+
Atlas ships a multi-stage `Dockerfile` that produces a standalone Next.js build. It runs on any Docker-capable platform. This guide covers Docker, Railway, Fly.io, Render, and Vercel.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Quick Deploy: Vercel
|
|
8
|
+
|
|
9
|
+
Go from zero to production in 5 minutes.
|
|
10
|
+
|
|
11
|
+
1. **Scaffold your project:**
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
bun create atlas-agent my-app
|
|
15
|
+
cd my-app
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
2. **Push to GitHub:**
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
git init && git add -A && git commit -m "Initial commit"
|
|
22
|
+
gh repo create my-app --public --source=. --push
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
3. **Import in Vercel:** Open the [Vercel Dashboard](https://vercel.com/), click **Add New > Project**, and import your repo. Vercel auto-detects Next.js via `vercel.json`.
|
|
26
|
+
|
|
27
|
+
4. **Set environment variables** in the Vercel project settings:
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
ATLAS_PROVIDER=anthropic
|
|
31
|
+
ANTHROPIC_API_KEY=sk-ant-...
|
|
32
|
+
DATABASE_URL=postgresql://user:pass@host:5432/dbname
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
5. **Deploy.** Vercel builds and deploys automatically.
|
|
36
|
+
|
|
37
|
+
6. **Verify:** `https://<your-app>.vercel.app/api/health` -- should return `{"status":"ok"}`
|
|
38
|
+
|
|
39
|
+
**What happens automatically on Vercel:**
|
|
40
|
+
|
|
41
|
+
- The explore tool uses `@vercel/sandbox` instead of `just-bash` when the `VERCEL` env var is present (no config needed)
|
|
42
|
+
- `output: "standalone"` is auto-skipped on Vercel (see `next.config.ts` -- the `VERCEL` env var check)
|
|
43
|
+
- `maxDuration` is already set to 60s in the chat API route
|
|
44
|
+
- `pg` and `just-bash` are in `serverExternalPackages` for serverless compatibility
|
|
45
|
+
|
|
46
|
+
For more details, see the [full Vercel section](#vercel) below.
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## Quick Deploy: Railway
|
|
51
|
+
|
|
52
|
+
Go from zero to production with managed Postgres included.
|
|
53
|
+
|
|
54
|
+
1. **Scaffold your project:**
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
bun create atlas-agent my-app
|
|
58
|
+
cd my-app
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
2. **Push to GitHub:**
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
git init && git add -A && git commit -m "Initial commit"
|
|
65
|
+
gh repo create my-app --public --source=. --push
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
3. **Create a Railway project:** Go to the [Railway Dashboard](https://railway.app/) and click **New Project**.
|
|
69
|
+
|
|
70
|
+
4. **Add a Postgres plugin:** Click **+ New** inside the project and add **Database > PostgreSQL**. Link it to your web service -- Railway injects `DATABASE_URL` automatically.
|
|
71
|
+
|
|
72
|
+
5. **Connect your repo:** Click **+ New > GitHub Repo** and select your repo. Railway detects `railway.json` and builds from the Dockerfile.
|
|
73
|
+
|
|
74
|
+
6. **Set environment variables** in the Railway service settings (only 2 -- `DATABASE_URL` is already set):
|
|
75
|
+
|
|
76
|
+
```
|
|
77
|
+
ATLAS_PROVIDER=anthropic
|
|
78
|
+
ANTHROPIC_API_KEY=sk-ant-...
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
7. **Seed your data.** Either seed the demo dataset or generate a semantic layer from your own tables:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
# Option A: Demo data
|
|
85
|
+
psql "$RAILWAY_DATABASE_URL" < data/demo.sql
|
|
86
|
+
|
|
87
|
+
# Option B: Your own data
|
|
88
|
+
DATABASE_URL="$RAILWAY_DATABASE_URL" bun run atlas -- init
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
8. **Deploy.** Railway builds and starts the container automatically.
|
|
92
|
+
|
|
93
|
+
9. **Verify:** `https://<your-app>.up.railway.app/api/health` -- should return `{"status":"ok"}`
|
|
94
|
+
|
|
95
|
+
**What happens automatically on Railway:**
|
|
96
|
+
|
|
97
|
+
- `DATABASE_URL` is injected by the Postgres plugin -- no manual config needed
|
|
98
|
+
- `railway.json` configures Dockerfile builds, health checks, and restart policy
|
|
99
|
+
- The Docker `HEALTHCHECK` polls `/api/health` every 30 seconds
|
|
100
|
+
|
|
101
|
+
For more details, see the [full Railway section](#railway) below.
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## Required environment variables
|
|
106
|
+
|
|
107
|
+
Every deployment needs these three:
|
|
108
|
+
|
|
109
|
+
| Variable | Example |
|
|
110
|
+
|----------|---------|
|
|
111
|
+
| `ATLAS_PROVIDER` | `anthropic` |
|
|
112
|
+
| Provider API key | `ANTHROPIC_API_KEY=sk-ant-...` |
|
|
113
|
+
| `DATABASE_URL` | `postgresql://user:pass@host:5432/dbname` |
|
|
114
|
+
|
|
115
|
+
Optional variables (safe defaults for most deployments):
|
|
116
|
+
|
|
117
|
+
| Variable | Default | Description |
|
|
118
|
+
|----------|---------|-------------|
|
|
119
|
+
| `ATLAS_MODEL` | Provider default | Override the LLM model |
|
|
120
|
+
| `ATLAS_ROW_LIMIT` | `1000` | Max rows returned per query |
|
|
121
|
+
| `ATLAS_QUERY_TIMEOUT` | `30000` | Query timeout in ms |
|
|
122
|
+
| `PORT` | `3000` | Set automatically by most platforms |
|
|
123
|
+
|
|
124
|
+
## Health check
|
|
125
|
+
|
|
126
|
+
All deployments should verify with the health endpoint:
|
|
127
|
+
|
|
128
|
+
```
|
|
129
|
+
GET /api/health
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Returns JSON with status `"ok"`, `"degraded"`, or `"error"` and sub-checks for database connectivity, provider configuration, and semantic layer presence. Returns HTTP 200 when status is `"ok"` or `"degraded"`, and HTTP 503 when status is `"error"` (database unreachable).
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
## Docker
|
|
137
|
+
|
|
138
|
+
The `Dockerfile` uses a three-stage build: install deps, build Next.js standalone output, then run with a minimal image.
|
|
139
|
+
|
|
140
|
+
### Build and run
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
docker build -t atlas .
|
|
144
|
+
docker run -p 3000:3000 \
|
|
145
|
+
-e ATLAS_PROVIDER=anthropic \
|
|
146
|
+
-e ANTHROPIC_API_KEY=sk-ant-... \
|
|
147
|
+
-e DATABASE_URL=postgresql://user:pass@host:5432/dbname \
|
|
148
|
+
atlas
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### Verify
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
curl http://localhost:3000/api/health
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
The Dockerfile includes a built-in `HEALTHCHECK` that polls `/api/health` every 30 seconds.
|
|
158
|
+
|
|
159
|
+
### Notes
|
|
160
|
+
|
|
161
|
+
- The image is based on `oven/bun:1.3`
|
|
162
|
+
- Standalone output copies only what's needed: `.next/standalone`, `.next/static`, `public/`, and `semantic/`
|
|
163
|
+
- The semantic layer (`semantic/`) is baked into the image at build time. If you update YAMLs, rebuild the image
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
## Railway
|
|
168
|
+
|
|
169
|
+
Railway auto-detects the `Dockerfile` via `railway.json` at the repo root.
|
|
170
|
+
|
|
171
|
+
### Steps
|
|
172
|
+
|
|
173
|
+
1. Create a new Railway project
|
|
174
|
+
2. Add a **Postgres** plugin (or use an external database)
|
|
175
|
+
3. Connect your GitHub repo -- Railway detects `railway.json` and builds from the Dockerfile
|
|
176
|
+
4. Set environment variables in the Railway dashboard:
|
|
177
|
+
|
|
178
|
+
```
|
|
179
|
+
ATLAS_PROVIDER=anthropic
|
|
180
|
+
ANTHROPIC_API_KEY=sk-ant-...
|
|
181
|
+
DATABASE_URL=<Railway-provided Postgres URL>
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
5. If using the demo dataset, seed the database:
|
|
185
|
+
|
|
186
|
+
```bash
|
|
187
|
+
# Connect to the Railway Postgres and run the seed file
|
|
188
|
+
psql "$RAILWAY_DATABASE_URL" < data/demo.sql
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
Or generate a semantic layer from your own data:
|
|
192
|
+
|
|
193
|
+
```bash
|
|
194
|
+
DATABASE_URL="$RAILWAY_DATABASE_URL" bun run atlas -- init
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
6. Deploy -- Railway builds and starts the container automatically
|
|
198
|
+
|
|
199
|
+
### Configuration
|
|
200
|
+
|
|
201
|
+
The `railway.json` config sets:
|
|
202
|
+
|
|
203
|
+
- Dockerfile-based builds
|
|
204
|
+
- Health check at `/api/health` with a 60-second timeout
|
|
205
|
+
- Restart on failure (max 10 retries)
|
|
206
|
+
|
|
207
|
+
### Verify
|
|
208
|
+
|
|
209
|
+
Railway exposes a public URL. Check health at `https://<your-app>.up.railway.app/api/health`.
|
|
210
|
+
|
|
211
|
+
---
|
|
212
|
+
|
|
213
|
+
## Fly.io
|
|
214
|
+
|
|
215
|
+
Atlas includes a `fly.toml` at the repo root.
|
|
216
|
+
|
|
217
|
+
### Steps
|
|
218
|
+
|
|
219
|
+
1. Install the [Fly CLI](https://fly.io/docs/flyctl/install/)
|
|
220
|
+
|
|
221
|
+
2. Launch the app (without deploying yet):
|
|
222
|
+
|
|
223
|
+
```bash
|
|
224
|
+
fly launch --no-deploy
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
3. Set secrets:
|
|
228
|
+
|
|
229
|
+
```bash
|
|
230
|
+
fly secrets set \
|
|
231
|
+
DATABASE_URL="postgresql://user:pass@host:5432/dbname" \
|
|
232
|
+
ANTHROPIC_API_KEY="sk-ant-..."
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
4. Deploy:
|
|
236
|
+
|
|
237
|
+
```bash
|
|
238
|
+
fly deploy
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
### Using Fly Postgres
|
|
242
|
+
|
|
243
|
+
To use Fly's managed Postgres instead of an external database:
|
|
244
|
+
|
|
245
|
+
```bash
|
|
246
|
+
fly postgres create --name atlas-db
|
|
247
|
+
fly postgres attach atlas-db
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
Fly automatically sets `DATABASE_URL` when you attach. Seed the demo data:
|
|
251
|
+
|
|
252
|
+
```bash
|
|
253
|
+
fly postgres connect --app atlas-db
|
|
254
|
+
# Then in the psql shell, paste contents of data/demo.sql
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
### Configuration
|
|
258
|
+
|
|
259
|
+
The `fly.toml` configures:
|
|
260
|
+
|
|
261
|
+
- Region: `iad` (US East) -- change `primary_region` for your location
|
|
262
|
+
- Health check: `GET /api/health` every 30 seconds
|
|
263
|
+
- Auto-stop/start machines (scales to zero when idle)
|
|
264
|
+
- VM: `shared-cpu-1x` with 512 MB memory
|
|
265
|
+
|
|
266
|
+
### Verify
|
|
267
|
+
|
|
268
|
+
```bash
|
|
269
|
+
fly status
|
|
270
|
+
curl https://<your-app>.fly.dev/api/health
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
---
|
|
274
|
+
|
|
275
|
+
## Render
|
|
276
|
+
|
|
277
|
+
Atlas includes a `render.yaml` Blueprint at the repo root.
|
|
278
|
+
|
|
279
|
+
### Steps
|
|
280
|
+
|
|
281
|
+
1. Go to the [Render Dashboard](https://dashboard.render.com/) and click **New > Blueprint**
|
|
282
|
+
2. Connect your GitHub repo -- Render reads `render.yaml`
|
|
283
|
+
3. Set the prompted environment variables:
|
|
284
|
+
- `DATABASE_URL` -- your Postgres connection string
|
|
285
|
+
- `ANTHROPIC_API_KEY` -- your API key
|
|
286
|
+
4. Deploy
|
|
287
|
+
|
|
288
|
+
### Using Render Postgres
|
|
289
|
+
|
|
290
|
+
1. Create a Render Postgres instance from the dashboard
|
|
291
|
+
2. Copy the **Internal Connection String**
|
|
292
|
+
3. Set it as `DATABASE_URL` in the Atlas service environment
|
|
293
|
+
|
|
294
|
+
### Configuration
|
|
295
|
+
|
|
296
|
+
The `render.yaml` configures:
|
|
297
|
+
|
|
298
|
+
- Docker-based deployment using the repo's `Dockerfile`
|
|
299
|
+
- Health check at `/api/health`
|
|
300
|
+
- Starter plan
|
|
301
|
+
- `ATLAS_PROVIDER` defaults to `anthropic`
|
|
302
|
+
- `autoDeploy` is disabled -- trigger deploys manually from the Render dashboard, or set `autoDeploy: true` in `render.yaml` to deploy on every push
|
|
303
|
+
|
|
304
|
+
### Verify
|
|
305
|
+
|
|
306
|
+
```bash
|
|
307
|
+
curl https://<your-app>.onrender.com/api/health
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
---
|
|
311
|
+
|
|
312
|
+
## Vercel
|
|
313
|
+
|
|
314
|
+
Atlas supports Vercel-native deployment. On Vercel, the explore tool uses `@vercel/sandbox` instead of `just-bash` for shell operations.
|
|
315
|
+
|
|
316
|
+
### Steps
|
|
317
|
+
|
|
318
|
+
1. Import your repo in the [Vercel Dashboard](https://vercel.com/)
|
|
319
|
+
2. Vercel auto-detects Next.js via `vercel.json` (framework: `nextjs`)
|
|
320
|
+
3. Set environment variables:
|
|
321
|
+
|
|
322
|
+
```
|
|
323
|
+
ATLAS_PROVIDER=anthropic
|
|
324
|
+
ANTHROPIC_API_KEY=sk-ant-...
|
|
325
|
+
DATABASE_URL=postgresql://user:pass@host:5432/dbname
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
4. Deploy
|
|
329
|
+
|
|
330
|
+
### Notes
|
|
331
|
+
|
|
332
|
+
- Vercel is auto-detected via the `VERCEL` environment variable -- no manual `ATLAS_RUNTIME` setting needed
|
|
333
|
+
- The `output: "standalone"` build option is skipped on Vercel (Vercel uses its own build pipeline)
|
|
334
|
+
- `@vercel/sandbox` is an optional dependency and only loaded when running on Vercel
|
|
335
|
+
- `pg` and `just-bash` are listed in `serverExternalPackages` in `next.config.ts` for compatibility with serverless functions
|
|
336
|
+
|
|
337
|
+
### Verify
|
|
338
|
+
|
|
339
|
+
```bash
|
|
340
|
+
curl https://<your-app>.vercel.app/api/health
|
|
341
|
+
```
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import js from "@eslint/js";
|
|
2
|
+
import tseslint from "typescript-eslint";
|
|
3
|
+
import nextPlugin from "@next/eslint-plugin-next";
|
|
4
|
+
|
|
5
|
+
export default tseslint.config(
|
|
6
|
+
js.configs.recommended,
|
|
7
|
+
tseslint.configs.recommended,
|
|
8
|
+
{
|
|
9
|
+
plugins: { "@next/next": nextPlugin },
|
|
10
|
+
rules: {
|
|
11
|
+
...nextPlugin.configs.recommended.rules,
|
|
12
|
+
...nextPlugin.configs["core-web-vitals"].rules,
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
ignores: [".next/", "node_modules/"],
|
|
17
|
+
}
|
|
18
|
+
);
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Deploy Atlas on Fly.io
|
|
2
|
+
#
|
|
3
|
+
# Quick start:
|
|
4
|
+
# fly launch --no-deploy
|
|
5
|
+
# fly secrets set DATABASE_URL="postgresql://..." ANTHROPIC_API_KEY="sk-ant-..."
|
|
6
|
+
# fly deploy
|
|
7
|
+
#
|
|
8
|
+
# Attach Fly Postgres instead of an external DB (name is a suggestion):
|
|
9
|
+
# fly postgres create --name %PROJECT_NAME%-db
|
|
10
|
+
# fly postgres attach %PROJECT_NAME%-db
|
|
11
|
+
|
|
12
|
+
app = "%PROJECT_NAME%"
|
|
13
|
+
primary_region = "iad"
|
|
14
|
+
|
|
15
|
+
[build]
|
|
16
|
+
dockerfile = "Dockerfile"
|
|
17
|
+
|
|
18
|
+
[env]
|
|
19
|
+
HOSTNAME = "0.0.0.0"
|
|
20
|
+
ATLAS_PROVIDER = "anthropic"
|
|
21
|
+
# Secrets (set via `fly secrets set`):
|
|
22
|
+
# DATABASE_URL
|
|
23
|
+
# ANTHROPIC_API_KEY (or OPENAI_API_KEY, etc.)
|
|
24
|
+
|
|
25
|
+
[http_service]
|
|
26
|
+
internal_port = 3000
|
|
27
|
+
force_https = true
|
|
28
|
+
auto_stop_machines = "stop"
|
|
29
|
+
auto_start_machines = true
|
|
30
|
+
min_machines_running = 0
|
|
31
|
+
|
|
32
|
+
[http_service.concurrency]
|
|
33
|
+
type = "requests"
|
|
34
|
+
hard_limit = 250
|
|
35
|
+
soft_limit = 200
|
|
36
|
+
|
|
37
|
+
[[http_service.checks]]
|
|
38
|
+
grace_period = "30s"
|
|
39
|
+
interval = "30s"
|
|
40
|
+
method = "GET"
|
|
41
|
+
timeout = "5s"
|
|
42
|
+
path = "/api/health"
|
|
43
|
+
|
|
44
|
+
[[vm]]
|
|
45
|
+
size = "shared-cpu-1x"
|
|
46
|
+
memory = "512mb"
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "%PROJECT_NAME%",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"description": "Atlas text-to-SQL data analyst agent",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "next dev --turbopack",
|
|
8
|
+
"build": "next build",
|
|
9
|
+
"start": "next start",
|
|
10
|
+
"lint": "eslint src/",
|
|
11
|
+
"type": "tsgo --noEmit",
|
|
12
|
+
"atlas": "bun bin/atlas.ts",
|
|
13
|
+
"db:up": "docker compose up -d postgres",
|
|
14
|
+
"db:down": "docker compose down",
|
|
15
|
+
"db:reset": "docker compose down -v && docker compose up -d postgres",
|
|
16
|
+
"test": "bun test"
|
|
17
|
+
},
|
|
18
|
+
"dependencies": {
|
|
19
|
+
"@ai-sdk/amazon-bedrock": "^4.0.63",
|
|
20
|
+
"@ai-sdk/anthropic": "^3.0.46",
|
|
21
|
+
"@ai-sdk/openai": "^3.0.31",
|
|
22
|
+
"@ai-sdk/react": "^3.0.99",
|
|
23
|
+
"ai": "^6.0.97",
|
|
24
|
+
"js-yaml": "^4.1.1",
|
|
25
|
+
"just-bash": "^2.10.2",
|
|
26
|
+
"next": "^16.1.6",
|
|
27
|
+
"node-sql-parser": "^5.4.0",
|
|
28
|
+
"pg": "^8.18.0",
|
|
29
|
+
"react": "^19.2.4",
|
|
30
|
+
"react-dom": "^19.2.4",
|
|
31
|
+
"react-markdown": "^10.1.0",
|
|
32
|
+
"react-syntax-highlighter": "^16.1.0",
|
|
33
|
+
"recharts": "^3.7.0",
|
|
34
|
+
"zod": "^4.3.6"
|
|
35
|
+
},
|
|
36
|
+
"optionalDependencies": {
|
|
37
|
+
"@vercel/sandbox": "^1"
|
|
38
|
+
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"@eslint/js": "^10.0.1",
|
|
41
|
+
"@next/eslint-plugin-next": "^16.1.6",
|
|
42
|
+
"@tailwindcss/postcss": "^4.2.1",
|
|
43
|
+
"@types/js-yaml": "^4.0.9",
|
|
44
|
+
"@types/node": "^25.3.0",
|
|
45
|
+
"@types/pg": "^8.16.0",
|
|
46
|
+
"@types/react": "^19.2.14",
|
|
47
|
+
"@types/react-dom": "^19.2.3",
|
|
48
|
+
"@types/react-syntax-highlighter": "^15.5.13",
|
|
49
|
+
"@typescript/native-preview": "^7.0.0-dev.20260223.1",
|
|
50
|
+
"eslint": "^10.0.2",
|
|
51
|
+
"tailwindcss": "^4.2.1",
|
|
52
|
+
"typescript": "^5.7.0",
|
|
53
|
+
"typescript-eslint": "^8.56.1"
|
|
54
|
+
}
|
|
55
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://railway.com/railway.schema.json",
|
|
3
|
+
"build": {
|
|
4
|
+
"builder": "DOCKERFILE",
|
|
5
|
+
"dockerfilePath": "Dockerfile"
|
|
6
|
+
},
|
|
7
|
+
"deploy": {
|
|
8
|
+
"restartPolicyType": "ON_FAILURE",
|
|
9
|
+
"restartPolicyMaxRetries": 10,
|
|
10
|
+
"healthcheckPath": "/api/health",
|
|
11
|
+
"healthcheckTimeout": 60
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Render Blueprint — deploy Atlas with "New > Blueprint" pointing at this repo.
|
|
2
|
+
# https://render.com/docs/infrastructure-as-code
|
|
3
|
+
|
|
4
|
+
services:
|
|
5
|
+
- type: web
|
|
6
|
+
name: %PROJECT_NAME%
|
|
7
|
+
runtime: docker
|
|
8
|
+
dockerfilePath: ./Dockerfile
|
|
9
|
+
plan: starter
|
|
10
|
+
autoDeploy: false
|
|
11
|
+
healthCheckPath: /api/health
|
|
12
|
+
healthCheckTimeout: 15
|
|
13
|
+
envVars:
|
|
14
|
+
- key: DATABASE_URL
|
|
15
|
+
sync: false
|
|
16
|
+
- key: ATLAS_PROVIDER
|
|
17
|
+
value: anthropic
|
|
18
|
+
- key: ANTHROPIC_API_KEY
|
|
19
|
+
sync: false
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { type UIMessage } from "ai";
|
|
2
|
+
import { runAgent } from "@/lib/agent";
|
|
3
|
+
import { validateEnvironment } from "@/lib/startup";
|
|
4
|
+
import { GatewayModelNotFoundError } from "@ai-sdk/gateway";
|
|
5
|
+
|
|
6
|
+
export const maxDuration = 60;
|
|
7
|
+
|
|
8
|
+
export async function POST(req: Request) {
|
|
9
|
+
// Startup diagnostics — fast-fail with actionable errors
|
|
10
|
+
const diagnostics = await validateEnvironment();
|
|
11
|
+
if (diagnostics.length > 0) {
|
|
12
|
+
return Response.json(
|
|
13
|
+
{
|
|
14
|
+
error: "configuration_error",
|
|
15
|
+
message: diagnostics.map((d) => d.message).join("\n\n"),
|
|
16
|
+
diagnostics,
|
|
17
|
+
},
|
|
18
|
+
{ status: 400 }
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Parse request body separately so malformed JSON gets a 400, not 500
|
|
23
|
+
let messages: UIMessage[];
|
|
24
|
+
try {
|
|
25
|
+
({ messages } = await req.json());
|
|
26
|
+
} catch {
|
|
27
|
+
return Response.json(
|
|
28
|
+
{
|
|
29
|
+
error: "invalid_request",
|
|
30
|
+
message: "Invalid request body. Expected JSON with a 'messages' array.",
|
|
31
|
+
},
|
|
32
|
+
{ status: 400 }
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
try {
|
|
37
|
+
const result = await runAgent({ messages });
|
|
38
|
+
return result.toUIMessageStreamResponse();
|
|
39
|
+
} catch (err) {
|
|
40
|
+
const message = err instanceof Error ? err.message : "";
|
|
41
|
+
|
|
42
|
+
// Gateway-specific errors (structured types, checked before regex fallbacks)
|
|
43
|
+
if (GatewayModelNotFoundError.isInstance(err)) {
|
|
44
|
+
console.error("[atlas] Gateway model not found in /api/chat:", message);
|
|
45
|
+
return Response.json(
|
|
46
|
+
{
|
|
47
|
+
error: "provider_model_not_found",
|
|
48
|
+
message:
|
|
49
|
+
"Model not found on the AI Gateway. Check that your ATLAS_MODEL uses the correct provider/model format (e.g., anthropic/claude-sonnet-4.6).",
|
|
50
|
+
},
|
|
51
|
+
{ status: 400 }
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// LLM provider auth errors (invalid or expired API key)
|
|
56
|
+
if (
|
|
57
|
+
/401|403|unauthorized|authentication|invalid.*key/i.test(message)
|
|
58
|
+
) {
|
|
59
|
+
console.error("[atlas] Provider auth error in /api/chat:", message);
|
|
60
|
+
return Response.json(
|
|
61
|
+
{
|
|
62
|
+
error: "provider_auth_error",
|
|
63
|
+
message:
|
|
64
|
+
"LLM provider authentication failed. Check that your API key is valid and has not expired.",
|
|
65
|
+
},
|
|
66
|
+
{ status: 503 }
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// LLM provider rate limit errors
|
|
71
|
+
if (/429|rate.?limit|too many requests|overloaded/i.test(message)) {
|
|
72
|
+
console.error("[atlas] Provider rate limit in /api/chat:", message);
|
|
73
|
+
return Response.json(
|
|
74
|
+
{
|
|
75
|
+
error: "provider_rate_limit",
|
|
76
|
+
message:
|
|
77
|
+
"LLM provider rate limit reached. Wait a moment and try again.",
|
|
78
|
+
},
|
|
79
|
+
{ status: 503 }
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Provider network errors (e.g., network failure to LLM API)
|
|
84
|
+
if (/fetch failed|ECONNREFUSED|ENOTFOUND/i.test(message)) {
|
|
85
|
+
console.error("[atlas] Provider unreachable in /api/chat:", message);
|
|
86
|
+
return Response.json(
|
|
87
|
+
{
|
|
88
|
+
error: "provider_unreachable",
|
|
89
|
+
message:
|
|
90
|
+
"Could not reach the LLM provider. Check your network connection and provider status.",
|
|
91
|
+
},
|
|
92
|
+
{ status: 503 }
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Fallback — safe 500 with correlation ID for debugging
|
|
97
|
+
const errorId = crypto.randomUUID().slice(0, 8);
|
|
98
|
+
console.error(`[atlas] Unexpected error in /api/chat [${errorId}]:`, err);
|
|
99
|
+
return Response.json(
|
|
100
|
+
{
|
|
101
|
+
error: "internal_error",
|
|
102
|
+
message: `An unexpected error occurred (ref: ${errorId}). If this persists, check the server logs.`,
|
|
103
|
+
},
|
|
104
|
+
{ status: 500 }
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
}
|