release: v0.0.5 — consolidation of 59 PRs + changelog + evidence review - #176
Open
lucastononro wants to merge 218 commits into
Open
release: v0.0.5 — consolidation of 59 PRs + changelog + evidence review#176lucastononro wants to merge 218 commits into
lucastononro wants to merge 218 commits into
Conversation
Bumps [docker/login-action](https://github.com/docker/login-action) from 3 to 4. - [Release notes](https://github.com/docker/login-action/releases) - [Commits](docker/login-action@v3...v4) --- updated-dependencies: - dependency-name: docker/login-action dependency-version: '4' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com>
Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 4 to 8. - [Release notes](https://github.com/actions/download-artifact/releases) - [Commits](actions/download-artifact@v4...v8) --- updated-dependencies: - dependency-name: actions/download-artifact dependency-version: '8' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com>
Bumps [docker/setup-buildx-action](https://github.com/docker/setup-buildx-action) from 3 to 4. - [Release notes](https://github.com/docker/setup-buildx-action/releases) - [Commits](docker/setup-buildx-action@v3...v4) --- updated-dependencies: - dependency-name: docker/setup-buildx-action dependency-version: '4' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com>
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 5 to 7. - [Release notes](https://github.com/docker/build-push-action/releases) - [Commits](docker/build-push-action@v5...v7) --- updated-dependencies: - dependency-name: docker/build-push-action dependency-version: '7' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com>
Bumps [sse-starlette](https://github.com/sysid/sse-starlette) from 2.1.0 to 3.3.4. - [Release notes](https://github.com/sysid/sse-starlette/releases) - [Commits](sysid/sse-starlette@v2.1.0...v3.3.4) --- updated-dependencies: - dependency-name: sse-starlette dependency-version: 3.3.4 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com>
Bumps [python-dotenv](https://github.com/theskumar/python-dotenv) from 1.0.1 to 1.2.2. - [Release notes](https://github.com/theskumar/python-dotenv/releases) - [Changelog](https://github.com/theskumar/python-dotenv/blob/main/CHANGELOG.md) - [Commits](theskumar/python-dotenv@v1.0.1...v1.2.2) --- updated-dependencies: - dependency-name: python-dotenv dependency-version: 1.2.2 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com>
Bumps [prettier](https://github.com/prettier/prettier) from 3.8.1 to 3.8.3. - [Release notes](https://github.com/prettier/prettier/releases) - [Changelog](https://github.com/prettier/prettier/blob/main/CHANGELOG.md) - [Commits](prettier/prettier@3.8.1...3.8.3) --- updated-dependencies: - dependency-name: prettier dependency-version: 3.8.3 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com>
Bumps [fastapi](https://github.com/fastapi/fastapi) from 0.115.0 to 0.136.1. - [Release notes](https://github.com/fastapi/fastapi/releases) - [Commits](fastapi/fastapi@0.115.0...0.136.1) --- updated-dependencies: - dependency-name: fastapi dependency-version: 0.136.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com>
Bumps [python-multipart](https://github.com/Kludex/python-multipart) from 0.0.12 to 0.0.28. - [Release notes](https://github.com/Kludex/python-multipart/releases) - [Changelog](https://github.com/Kludex/python-multipart/blob/main/CHANGELOG.md) - [Commits](Kludex/python-multipart@0.0.12...0.0.28) --- updated-dependencies: - dependency-name: python-multipart dependency-version: 0.0.26 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com>
Bumps [postcss](https://github.com/postcss/postcss) from 8.5.8 to 8.5.14. - [Release notes](https://github.com/postcss/postcss/releases) - [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md) - [Commits](postcss/postcss@8.5.8...8.5.14) --- updated-dependencies: - dependency-name: postcss dependency-version: 8.5.12 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com>
Bumps [react-resizable-panels](https://github.com/bvaughn/react-resizable-panels) from 2.1.9 to 4.11.0. - [Release notes](https://github.com/bvaughn/react-resizable-panels/releases) - [Changelog](https://github.com/bvaughn/react-resizable-panels/blob/main/CHANGELOG.md) - [Commits](bvaughn/react-resizable-panels@2.1.9...4.11.0) --- updated-dependencies: - dependency-name: react-resizable-panels dependency-version: 4.10.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com>
Bumps [react-syntax-highlighter](https://github.com/react-syntax-highlighter/react-syntax-highlighter) from 15.6.6 to 16.1.1. - [Release notes](https://github.com/react-syntax-highlighter/react-syntax-highlighter/releases) - [Changelog](https://github.com/react-syntax-highlighter/react-syntax-highlighter/blob/master/CHANGELOG.MD) - [Commits](react-syntax-highlighter/react-syntax-highlighter@v15.6.6...v16.1.1) --- updated-dependencies: - dependency-name: react-syntax-highlighter dependency-version: 16.1.1 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com>
Bumps [react-markdown](https://github.com/remarkjs/react-markdown) from 9.1.0 to 10.1.0. - [Release notes](https://github.com/remarkjs/react-markdown/releases) - [Changelog](https://github.com/remarkjs/react-markdown/blob/main/changelog.md) - [Commits](remarkjs/react-markdown@9.1.0...10.1.0) --- updated-dependencies: - dependency-name: react-markdown dependency-version: 10.1.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com>
Bumps [sqlalchemy](https://github.com/sqlalchemy/sqlalchemy) from 2.0.35 to 2.0.49. - [Release notes](https://github.com/sqlalchemy/sqlalchemy/releases) - [Changelog](https://github.com/sqlalchemy/sqlalchemy/blob/main/CHANGES.rst) - [Commits](https://github.com/sqlalchemy/sqlalchemy/commits) --- updated-dependencies: - dependency-name: sqlalchemy dependency-version: 2.0.49 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com>
Adds `GET /api/sessions/{sid}/download` and `GET /api/projects/{pid}/download`
that stream a self-contained zip of the agent's workspace: every file under
`/sessions/{sid}/` plus a synthetic `trainable_local.py` shim, a filtered
`requirements.txt`, and a runbook README. The shim lets downloaded scripts
that import `from trainable import log, log_image, ...` run on a vanilla
Python install — calls land in `./trainable_out/` instead of the Modal
volume.
The zip is streamed via `StreamingResponse` over an in-memory buffer
drained per write, so multi-hundred-MB sessions don't materialize on
disk or in RAM. A 2 GB uncompressed cap with a trailing `__truncated.txt`
marker keeps a runaway walk bounded.
Frontend ships two entry points:
- Download icon in the WorkspaceSidebar header → session zip
- Download icon on every Project row in the sidebar → project zip
Closes #79.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The cli/README.md was stale against v0.0.4: it described a single-provider (Anthropic + Modal) setup, claimed the wizard downloaded the compose file from raw.githubusercontent.com, and omitted `trainable reconfigure`. Update it to match the current implementation: - multi-provider selection (Claude API key / subscription OAuth, OpenAI, Gemini, LiteLLM-routed backends) as a flat picker, with a Providers table - compose file bundled inside the wheel (offline installs) - version-pinned images on `trainable up` - `trainable reconfigure` command and the existing-config merge flow Assisted-by: Claude Code
…#123) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wp66uSq9saSpRq9Bbmjxj4
…t:8000 (#96) Replace getSSEBase()/getBackendUrl() (which returned http://host:8000) with relative /api paths at all EventSource and raw file/image/PDF fetch sites, routing through the existing Next rewrite proxy so HTTPS deploys no longer hit mixed-content blocking or an unexposed port. Both helpers are deleted. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wp66uSq9saSpRq9Bbmjxj4
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wp66uSq9saSpRq9Bbmjxj4
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wp66uSq9saSpRq9Bbmjxj4
…tores (#90) docker-compose.prod.yml shipped hardcoded default credentials (trainable/trainable, minioadmin/minioadmin) and published Postgres (5432), MinIO (9000/9001) and the auth-less Jaeger UI (16686) on 0.0.0.0 — direct data-store compromise with well-known creds on any networked host, and Jaeger traces leak prompts/paths/token counts. - Replace every hardcoded secret with required env-var interpolation that fails loudly if unset: POSTGRES_USER/PASSWORD/DB and MINIO_ROOT_USER/PASSWORD via `${VAR:?set VAR in .env}`. The backend's DATABASE_URL and AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY are now derived from those same vars, so app creds always match the datastores (var names match what backend/config.py reads). - Bind Postgres, MinIO API+console and the Jaeger UI to 127.0.0.1 so they are reachable only from the host / internal compose network, never from another machine. Drop the Jaeger OTLP host publishes (4317/4318) — the backend reaches them by service name internally. frontend (3000) and backend (8000) stay published as before. - Document the newly-required vars in .env.example with placeholders and a note that prod has no defaults. Validated: `docker compose -f docker-compose.prod.yml config` parses and interpolates with a filled .env, and fails fast with a clear message when the secrets are unset. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wp66uSq9saSpRq9Bbmjxj4
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wp66uSq9saSpRq9Bbmjxj4
…erving Introduce services/compute with per-concern interfaces (SandboxProvider, KernelTransport, StorageBackend, ServingBackend) selected by the new COMPUTE_PROVIDER setting. sandbox.py/volume.py/kernel_manager.py/deploy.py become facades that keep their public signatures; Modal mechanics move to services/compute/modal_provider/*. Billing rows now record the actual provider, sandbox.yml gains runpod rates, and deployments get provider/provider_endpoint_id columns. Refs #130 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012GrGFBtdZv7qtgn8KQEQEB
Add an opt-in shared-secret gate for the API. When API_AUTH_TOKEN is
unset (the default) nothing changes — every endpoint stays open, so
local dev and the frontend are unaffected. When set, all /api/*
requests must send `Authorization: Bearer <token>`.
- backend/auth.py: pure-ASGI BearerTokenAuthMiddleware (no
BaseHTTPMiddleware wrapping, so SSE streaming is untouched);
constant-time token comparison; 401 + WWW-Authenticate on failure.
- Exempt: /api/health, /api/readyz, CORS preflight (OPTIONS).
- SSE: EventSource cannot send headers, so the stream endpoint
(/api/sessions/{id}/stream) additionally accepts ?token=<token>;
the query param is stream-only and does not unlock other routes.
- config.py: api_auth_token setting (env API_AUTH_TOKEN, default None).
- Middleware added before CORSMiddleware so CORS stays outermost and
answers preflights before auth runs.
- .env.example: new "Optional — security" section documenting it.
- tests/test_api_auth.py: middleware unit tests (open-by-default,
401/200 matrix, exemptions, stream query token, preflight).
Closes #88
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wp66uSq9saSpRq9Bbmjxj4
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wp66uSq9saSpRq9Bbmjxj4
…edentials Replace the `cors_origins=["*"]` + `allow_credentials=True` default (any web page could script credentialed cross-origin requests against localhost:8000) with a safe, configurable policy: - config.py: default origins are the local frontend (http://localhost:3000, http://127.0.0.1:3000); overridable via CORS_ORIGINS as a comma-separated env var (NoDecode + validator so plain CSV works, not just JSON). - main.py: if `*` is configured it is honored but credentials are disabled (allow_credentials=False) with a startup warning — the wildcard+credentials combination is now impossible. - .env.example: document CORS_ORIGINS. No impact on the standard setup: the frontend proxies /api through Next.js rewrites (same-origin), so CORS is not involved there. Closes #89 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wp66uSq9saSpRq9Bbmjxj4
- Stream uploads to S3 in bounded 8 MB chunks (single put_object for small bodies, multipart upload for larger ones) instead of reading the whole body into RAM; abort the multipart upload on any failure. - Enforce the configured max_upload_size_bytes cap incrementally while reading (413 without buffering the oversize body). - Validate bucket against the app-provisioned allowlist (new settings.s3_allowed_buckets, also used by startup bucket init) and reject traversal/absolute/backslash keys; write endpoints (upload + put-presign) are scoped to the datasets/projects/ prefix. - Authentication is intentionally NOT added here — it lands globally via issue #88. Closes #91 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wp66uSq9saSpRq9Bbmjxj4
A stalled provider HTTP call had no wall-clock limit: the runner's outer asyncio.timeout was deliberately removed (the Modal sandbox timeout only bounds tool execution), and every provider accepted timeout_seconds but discarded it. A hung network call left the session's background task alive forever — spinner never cleared, task-registry entry never freed. Thread the existing timeout_seconds into each provider around the HTTP call only, so tool-execution time is never counted: - base.py: new enforce_wall_clock() helper — asyncio.wait_for around a single provider call, raising builtin TimeoutError on expiry. - openai: per-request SDK timeout via client.with_options(timeout=...) plus the hard wall-clock cap (SDK retries can't stretch past it). - gemini: hard cap around generate_content (google-genai has no default request timeout at all). - litellm: keep the existing per-attempt timeout= knob, add the hard cap so backend retries/fallbacks can't exceed the budget. - claude: query() runs the whole tool loop internally, so it must not be wrapped wholesale; bound each underlying API HTTP request via Claude Code's API_TIMEOUT_MS env instead (caller-supplied value wins). On expiry the providers let TimeoutError propagate: run_agent's existing TimeoutError handler publishes agent_timeout, moves the session to timed_out, and the finally block frees the task registry — the run ends cleanly instead of hanging. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wp66uSq9saSpRq9Bbmjxj4
…ostcss-8.5.12 # Conflicts: # frontend/package-lock.json # frontend/package.json
…eact-syntax-highlighter-16.1.1 # Conflicts: # frontend/package-lock.json
…er-16.1.1' into staging-v0.0.5
…eact-markdown-10.1.0
… into staging-v0.0.5
# Conflicts: # backend/requirements.txt
# Conflicts: # frontend/package-lock.json # frontend/package.json
…n /frontend # Conflicts: # frontend/package-lock.json # frontend/package.json
#128) requirements.txt stays the human-edited input; requirements.lock is generated via `uv pip compile requirements.txt -o requirements.lock --generate-hashes --universal` (149 pinned + hashed packages). The backend Dockerfile and the CI backend-test / backend-vuln-scan install steps now install with --require-hashes from the lock, so CI, the published image, and contributor venvs resolve identical versions.
cmd_up/cmd_down previously exec'd straight into `docker compose`, so an installed-but-stopped Docker daemon surfaced a raw connection error. _require_config now runs a `docker info` liveness preflight with friendly guidance, covering up/down/status/logs. New subcommands: `trainable status` (compose ps), `trainable logs` (compose logs), and `trainable --version`. Tests mock all docker subprocesses — no real Docker needed.
…/ edit-file / run-file + notebook cell edit/delete/rerun (closes #85) New skills (purely additive; no signature changes to execute-code or the existing notebook skills): - write-file(path, content, overwrite=true) — wraps volume.write_to_volume; emits file_created / file_updated; does NOT write into scripts/ (authoring is not an execution step). - edit-file(path, mode=replace|overwrite, old/new|content) — exact-anchor replace (must match exactly once) or whole-file overwrite; emits file_updated, never file_created. - run-file(path, heavy=false) — runpy.run_path(path, run_name='__main__') through services.sandbox.run_code under the existing preamble (src/ on sys.path, session cwd); auto-saves a one-line runpy audit entry to scripts/step_NN_run_<name>.py; heavy picks the training sandbox profile with the owner max_timeout cap (same as execute-code post-#160). - edit-notebook-cell / delete-notebook-cell — wrap new notebook_store.edit_cell / delete_cell helpers (outputs preserved on edit, same as apply_source_update; both persist under the existing _lock + save path); broadcast notebook.structure.changed for live UI. - rerun-notebook-cell — looks a cell up by cell_id, re-executes its current source against the persistent kernel via kernel_manager.execute_and_wait (kernel cell_started clears outputs; earlier-cell variables stay in scope); same result envelope as run-notebook-cell. Shared resolve_session_path() helper in services/skills/state.py (session-relative, volume-absolute, and /data/-prefixed paths; rejects escapes). All six skills registered in chat, eda, data_prep, feature_eng, trainer, orchestrator YAMLs, whose 'Workspace is a real Python repo' blocks are replaced by the prescriptive 'Authoring vs running' block (rule of three; edit don't repaste; import from src/ works in kernel cells) keeping the per-agent example bullets. execute-code SKILL.md now documents its one-shot contract. Frontend: file_updated added to the typed SSE union + handled in useSessionStream (tree update, no auto-open). Tests: 48 new (skill handlers happy/failure paths incl. invalid path, non-matching/ambiguous anchor, missing file, cell_id not found, markdown rerun, kernel timeout; notebook_store edit_cell output preservation + delete_cell volume persistence; path resolution). Full backend suite: 647 passed, 8 skipped. ruff 0.15.22 check + format clean. Frontend: vitest 20/20, tsc, next lint, prettier clean.
…it/delete/rerun (closes #85)
Owner
Author
|
@greptile-apps review |
Comment on lines
+50
to
+67
| async def __call__(self, scope, receive, send): | ||
| if scope["type"] not in ("http", "websocket"): | ||
| await self.app(scope, receive, send) | ||
| return | ||
|
|
||
| path = scope["path"] | ||
| if ( | ||
| not path.startswith("/api/") | ||
| # WebSocket scopes have no "method" key. | ||
| or path in EXEMPT_PATHS | ||
| or scope.get("method") == "OPTIONS" | ||
| ): | ||
| await self.app(scope, receive, send) | ||
| return | ||
|
|
||
| if self._authorized(scope): | ||
| await self.app(scope, receive, send) | ||
| return |
There was a problem hiding this comment.
Bearer gate blocks the frontend
When API_AUTH_TOKEN is configured, this middleware requires credentials on every non-exempt /api request, but the bundled API client and session EventSource provide no token, causing normal UI requests and session streaming to fail with 401 responses.
Context Used: AGENTS.md (source)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Promotion of
release/v0.0.5tomain: consolidation of 59 merged PRs/issues on top of the v0.0.4 line, plusCHANGELOG.mdand a fresh evidence review (docs/evidence/v0.0.5-review.md). Per-PR merge detail (Greptile follow-ups, conflict resolutions, per-wave test counts) is inSTAGING-v0.0.5.mdon this branch.Product features
budget_exceededSSE (Enforce per-project cost budgets with a hard-stop guardrail #165)Compute: RunPod provider (#145); per-project GPU allowance (#160)
Frontend: session-scoped SSE bus (#148), chat memoization (#150), autoscroll pinning (#152), typed SSE union (#157), error boundaries (#159),
page.tsxsplit (#166), react-resizable-panels v4 migration (#24)Security: opt-in bearer auth (#138), CORS fail-fast (#140), prod compose secrets + localhost binds (#136),
.env0600 (#134), S3 upload bounds + bucket allowlist (#141/#143/#147)Reliability: LLM timeout normalization (#142), concurrent readyz probes (#144), Sentry capture fix (#151), boto3/DuckDB event-loop offload (#143/#139)
Database: Alembic migration framework (#153) + revisions for
training_config(#164),budget_usd(#165), deployments provider columns (#145)CLI:
status/logs/--version+ Docker preflight (#126), first CLI test suite + env perms (#134), README refresh (#129)CI/tooling: pinned ruff (#137/#135), coverage gate (#149), Postgres CI (#154), advisory vuln scans (#156), actions major bumps (#7–#10), hashed requirements.lock (#173/#128)
Dependencies: fastapi 0.136.1, sqlalchemy 2.0.49, sse-starlette 3.3.4, python-multipart 0.0.28, python-dotenv 1.2.2, react-markdown 10, react-syntax-highlighter 16, postcss 8.5, prettier 3.9.6
Evidence (fresh runs on this branch, 2026-07-29)
ruff@0.15.22 check+format --check: clean (220 files)tsc --noEmitclean,next lintclean, prettier clean, productionnext buildOK (8 routes,/prerenders)upgrade headthrough 4 revisions, single headb7d3f5a91c02; migration tests 7/7docker compose config -q: dev + prod OK with dummy secrets (fails closed without)--version/--helpOK (note: wheel still reports 0.0.4 — version bump expected at release cut)/api/healthok;/api/readyzfail-closednot_readywithout S3; bearer gate 401 without / 200 with tokenNOT evidenced — honest gap list
docker/runpod-worker/, setRUNPOD_*, run one sandbox + kernel + serving deploy.trainable upsession with Modal tokens.upgrade head.Greptile Summary
This release consolidates the v0.0.5 feature set across backend compute, migrations, security, workspace tooling, frontend streaming and UI, CLI behavior, dependencies, and CI.
Confidence Score: 4/5
The authentication integration must be fixed before merging because setting the advertised API_AUTH_TOKEN makes the bundled frontend’s API requests and SSE connection fail with 401 responses.
The backend now requires a shared credential on all protected API traffic, but neither the frontend API client nor its EventSource construction can provide that credential.
Files Needing Attention: backend/auth.py, frontend/src/lib/api.ts, frontend/src/lib/useSessionStream.ts
Important Files Changed
Sequence Diagram
sequenceDiagram participant B as Browser frontend participant P as Next.js /api rewrite participant A as FastAPI auth middleware participant R as API/SSE route B->>P: GET /api/... (no bearer token) P->>A: Forward unchanged request alt API_AUTH_TOKEN configured A-->>B: 401 Unauthorized else API_AUTH_TOKEN unset A->>R: Forward request R-->>B: API response or SSE stream endReviews (1): Last reviewed commit: "docs(release): v0.0.5 changelog + eviden..." | Re-trigger Greptile
Context used: