Tags: dkedar7/langstage
Tags
Make /api/files/upload path the full destination (gh #75) (#76) `upload` alone interpreted `path` as a parent directory and appended the multipart filename, while read/preview/download/delete/mkdir treat `path` as the full target. So a `path`-symmetric client's `POST upload?path=P` then `GET read?path=P` didn't round-trip: the upload silently landed at `P/<multipart-filename>` (creating a stray directory `P`), returned 200, and the read of `P` then 400'd. `path` is now the full destination path by default, so `upload?path=P` stores the file AT `P` and round-trips. The directory-drop mode is kept EXPLICITLY: a trailing `/` or an existing-directory `path` appends the multipart filename — which is exactly what the file-browser UI does (uploads into the directory being viewed), so the shipped frontend is unchanged, no rebuild needed. OpenAPI description + README document it. Adds tests: the upload->read round-trip, directory-drop into an existing dir (UI path), trailing-slash drop, and the traversal 400. Claude-Session: https://claude.ai/code/session_012Rojryf2SHxCM87NgsDSi2 Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Add --json to `check` and `config` for machine-readable CI gating (gh #… …73) (#74) The README pitches `langstage check --live` as a CI readiness gate, but `check` emitted only human lines and a coarse exit code — only a load failure or a --live runtime error set exit 1; every static finding was a warning that left exit 0. So a team wanting CI to fail if Canvas isn't wired, or to surface WHICH check failed, had to regex-scrape [ok]/[warn]/[fail] text. `check --json` now emits a stable object — {spec, loads, agent_name, checks:{checkpointer, canvas, write_todos, async_tasks, schedules}, live, ok} — built alongside the human lines (so they can't diverge) and preserving the exit-code contract. This unlocks the advertised gate: `... --json | jq -e '.loads and .checks.canvas.ok'`. `config --json` emits each field's value + source (plus the TOML files read) so a deploy step can assert how a container resolved its env / langstage.toml. Human default output is unchanged. README documents both. Claude-Session: https://claude.ai/code/session_012Rojryf2SHxCM87NgsDSi2 Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
feat: advertise the built-in OpenAPI/Swagger docs + report the real v… …ersion (#71) (#72) FastAPI already serves a complete, in-sync schema at /openapi.json, /docs, /redoc, but it was undocumented. Add a README "REST API" section pointing at all three, print the docs URL on `langstage run` startup, and replace the hardcoded FastAPI version="2.0.0" with the real package version (+ a titled/described schema) so the docs are accurate. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
fix: readiness checks the agent is runnable, not just non-None (#69) (#… …70) /api/health?ready=1 used `agent is not None` — vacuous (a failed load aborts startup) and blind to an uncompiled StateGraph, which loads (server starts, readiness says 200 ok) but dies every turn with no astream. Gate readiness on runnability (callable(agent.astream)), the same check `langstage check` uses (gh #39); return 503 not_runnable otherwise. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
feat: add a real /api/health liveness + readiness endpoint (#67) (#68) /health (and every non-/api/* path) returned the SPA index.html — 200 regardless of backend state, and 401 once auth was on — so an LB/k8s/uptime probe had no usable signal. Add a dedicated JSON GET /api/health under /api/* (can't collide with the SPA catch-all), exempt from Basic Auth (probes can't carry credentials): liveness (default) -> 200 {status:ok, version}; readiness (?ready=1) -> 200 only if the agent loaded AND the task store is reachable, else 503 with the failing checks — reflecting real backend state, not the always-served shell. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
release: 0.13.8 — relative-workspace doubling fix via core 1.0.9 (#66) Bumps the langstage-core[agui] pin to >=1.0.9 for the #66 relative-workspace idempotency fix (run()'s _enter_workspace chdir doubled a relative root pre-1.0.9). Also carries the already-merged lifespan migration (#61) and E702 lint (#65). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
fix: don't use a graph's default "LangGraph" name as the app title + … …refresh header (dogfood F3) (#64) A bare CompiledStateGraph's default .name is "LangGraph", which the app used as its header title/agent name for a BYO agent — a confusing brand. Generic names (LangGraph/agent/graph) are now ignored, keeping the LangStage default; a real .name still becomes the title. Also refreshed the README header to a langstage SVG banner (was cover.png labelled "Cowork Dash"). Claude-Session: https://claude.ai/code/session_012Rojryf2SHxCM87NgsDSi2 Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
fix: run() operates the agent from the workspace cwd so BYO files lan… …d there (ADR 0006, F7) (#63) A bring-your-own agent that writes Path("out.txt") (raw cwd-relative) wrote to the server's launch dir — invisible in the file browser (rooted at the workspace) — so it could say "saved to the workspace" while the browser showed empty. run() now chdirs to the resolved workspace AFTER the agent spec is resolved and create_server() has wired the file browser (both use the absolute path, unaffected), matching cli. chdir is in run(), not __init__, so embedding CoworkApp has no cwd side effect. Found by fresh-user dogfood. Claude-Session: https://claude.ai/code/session_012Rojryf2SHxCM87NgsDSi2 Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
fix: report the real workspace as [Working directory], not the fronte… …nd's virtual / (dogfood) (#62) The chat prepends a [Working directory: {cwd}] context line, using the file browser's current folder (a virtual path). At the browser root the agent was told "Working directory: /" — misleading, and wrong for a BYO agent that resolves paths against it. context_parts now reports core.workspace_root() with the browsed subfolder applied (<workspace>/sub), so the agent hears the real filesystem dir it operates in. Found by fresh-user dogfood: a BYO note-taking agent reported "/" while its files actually landed elsewhere. Claude-Session: https://claude.ai/code/session_012Rojryf2SHxCM87NgsDSi2 Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
feat: workspace is one source of truth, not a hand-synced mirror (ADR… … 0005, 0.13.4) (#58) CoworkApp.__init__ used to reconcile the #44 split-brain imperatively — resolve the workspace, then assign config.WORKSPACE_ROOT + two env vars so the agent's tools agreed with the file browser. It now calls core.apply_workspace(self.config.workspace_root) once, and config.WORKSPACE_ROOT is a live view of core.workspace_root() (module __getattr__) — so the file browser and the agent tools read the same value by construction, no mirror to drift. Fifth and final surface migration for ADR 0005. The full #44 regression suite passes unchanged. Bumps the core floor to >=1.0.7. Claude-Session: https://claude.ai/code/session_012Rojryf2SHxCM87NgsDSi2 Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
PreviousNext