mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-29 21:07:40 +01:00
8049fbf51d0701ca6b242e4b1198e5449f7661b2
2
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
39279aa34f |
feat(ui): shared error, connectivity and query foundation for disconnects (#15754)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - The board reads API data and keeps the current task on screen. > - A restart or temporary network failure can interrupt those reads. > - Separate page error handlers can hide cached data or expose raw server codes. > - The app needs one connection state, readable error copy and a consistent read policy. > - This change provides that foundation and moves affected read surfaces onto it. > - The dependent write layer in #17960 preserves edits and submissions across the same failures. ## Linked Issues or Issue Description **What happened?** Temporary API failures could replace loaded content with errors. Different surfaces handled the same outage differently. Some showed raw server codes. A successful query to an unrelated service could also falsely report that Paperclip had recovered. **Expected behavior** Keep cached content visible. Show one connection banner during sustained trouble. Confirm recovery through the Paperclip health probe or its WebSocket. Retry transient reads and show readable errors for permanent failures. **Steps to reproduce** 1. Open a populated task or workspace page. 2. Interrupt API requests with a 503 or a dropped connection. 3. Keep an unrelated external request in flight. 4. Confirm that cached content remains and that the external result cannot clear the outage. 5. Restore the API and check that reads refresh. The write layer first merged into this feature branch in #15769 now has its own dependent PR, #17960. This PR contains the shared foundation and read changes. Merge this PR first. ## What Changed - Classify API errors and provide readable error copy, including non-JSON proxy responses and Retry-After handling. - Use one connection store and health probe with bounded backoff. Confirm recovery from the server health probe or live-updates WebSocket. - Pause reads while disconnected, retry transient errors, and refresh active reads after recovery. - Keep cached data visible through shared query views and affected page, panel and plugin read surfaces. - Add one app-level connection banner and support the pending-write count consumed by the dependent write layer. - Add a query-error rendering guard. Call it directly from the existing CI step. Update development documentation. ## Verification - Historical-chat lookup now follows the same ready/stale roster state as rendering. Three regressions fail before the fix; the six new cases pass after it, including working Retry, fresh data, no-cache error, permanent 403 and company isolation. All six focused query/recovery suites pass 200 tests. Final-commit CI passes and Apex is 5/5 with no unresolved findings. Canary Dry Run initially refused a preview version that was already on npm. It passed after one rerun with fresh registry metadata; no check was disabled. - Integrated current master and retained both transcript interest registration and connectivity reporting on socket open. The seven focused recovery/query suites pass 288 tests, and UI typecheck and production build pass. All 9,451 UI tests across 799 files pass on the merge commit. Final-commit CI passes and Apex is 5/5 with no unresolved findings. - Current head `70d9335d732219352ef0f98414439766bbcb33df`: all hosted CI checks pass. Apex is **5/5** on that head with no unresolved findings. The branch has no merge conflict. GitHub still requires code-owner approval. - The foundation passes 9,430 UI tests in 804 files. After integrating current master page paths, 190 focused page tests pass. - Two unrelated-success regressions fail before the latest fix. With the fix, 62 focused UI tests, all six guard tests and UI TypeScript pass. - The composed foundation and write layer pass **9,505 UI tests in 808 files**, UI TypeScript, a production UI build, and query-error, token and map guards. - A real Chromium journey on the composed source injects a 503 during title save. The loaded task stays visible; one reconnect banner appears; the edit saves after recovery; another task stays unchanged; the saved title survives reload. - Full recursive local checks were not repeated because Runner compilation exhausted local disk during another repair. Hosted checks must pass before merge. No new staging deployment is claimed. - Latest review follow-up: a cached CaseDetail now survives a failed HTTP 429 refresh. Its page regression fails before the fix and passes after it. Eighty focused foundation tests, UI TypeScript, build and guards pass after that change. - Earlier CI evidence is retained: several foundation jobs received a runner shutdown signal together. The write-layer head also failed an unchanged Runner descriptor close test with `provider_transport_failed`. The same Runner source passed that suite in the foundation run. New CI runs cover the updated heads; no check or assertion was weakened. ## Risks - Shared retry defaults change the time before transient read errors appear. Permanent errors still fail promptly. - ApiError.message now contains readable copy. Callers that compare raw codes must use ApiError.code. - Cache success can come from another service or local data. It must not confirm Paperclip recovery. - Durable writes are reviewed separately in #17960. This PR does not change database or mutation contracts. ## Model Used Anthropic Claude Opus 5.5 (`claude-opus-5-5`) produced the original work with tool use. OpenAI Codex, GPT-6 family, assisted with restoration, integration, tests and review fixes. The Codex session does not expose its exact serving model ID or context window size. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] All Paperclip CI gates are green - [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge --------- Co-authored-by: devinfoley <139239+devinfoley@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Paperclip <noreply@paperclip.ing> Co-authored-by: Amy (Opus) <claude@users.noreply.github.com> |
||
|
|
7b91fe9ea7 |
Hide host-path and execution-engine surfaces in managed-sandbox-only mode (#12293)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - An instance can turn on the `enableManagedSandboxOnly` feature, which hides the local environment and runs every agent in the platform-managed environment > - That feature already gated the environment pickers, the onboarding wizard, and the server-side run selection, but many other screens still showed absolute paths on the execution host and still let the user pick an execution engine > - On such an instance those controls name a filesystem the user cannot reach; a path written there is stored and then ignored, which reads as a broken control > - This pull request hides the remaining host-path and execution-engine surfaces behind the same feature, adds a server rule that refuses a project-workspace path write while the feature is on, and closes a related route gap in the isolated-workspace pages > - The benefit is that a managed instance shows no host path and no folder picker anywhere, and a write that carries a path now fails with a clear message instead of being silently discarded ## Linked Issues or Issue Description No public issue exists. The description below follows `.github/ISSUE_TEMPLATE/enhancement.yml`. **What existing behavior does this improve?** The `enableManagedSandboxOnly` instance feature, and the UI surfaces that show a host filesystem path: project properties, the new-project dialog, the project workspace and execution workspace detail pages, the workspace and task cards, plugin local folders, and the agent configuration form with its per-adapter fields. It also improves route gating for `enableIsolatedWorkspaces`. **Subsystem affected** Cross-cutting (`ui/` and `server/`). **Current behavior** When `enableManagedSandboxOnly` is on, the local environment disappears from the environment pickers and the server refuses to run an agent on the local host. Everything else stays visible. A user still sees: - the project "Local folder" row, its absolute path, and the Set/Change/Clear buttons - the "Local folder" field and its "Choose" folder picker in the new-project dialog - the "Local path" field and fact row on a project workspace - the "Paths" and "Lifecycle commands" groups on an execution workspace - the working directory on workspace cards, task properties, and runtime service rows - the plugin "Local folders" section - "Working directory (deprecated)", "Command", "Execution engine", "ACP server command", "ACP state directory", and "Agent instructions file" in the agent configuration form A path typed into any of these names a filesystem no agent on the instance uses. The project workspace API also accepts a `cwd` write and stores it. Separately, `/workspaces`, `/execution-workspaces/*`, and `/projects/:projectId/workspaces/:workspaceId` render for anyone who types or bookmarks the URL, even with `enableIsolatedWorkspaces` off. Only the sidebar entry reads that flag. **Proposed behavior** With `enableManagedSandboxOnly` on, none of those surfaces render. A project whose codebase came from a managed checkout keeps its one-line "Paperclip-managed folder." label and shows no path. The non-path controls stay: repo URL, branch, service URL, port, command output, ACP session mode, ACP non-interactive permissions, Codex fast mode, and the sandbox toggles. The project-workspace create and patch routes, and the nested workspace on project create, answer `422` with "This instance runs agents only in the platform-managed environment; local folders are not configurable." when the payload carries a non-null `cwd`. A `cwd: null` write still passes, so an instance that just turned the feature on can clear a stale path. With `enableIsolatedWorkspaces` off, the three workspace route groups redirect to the dashboard. **Reason and benefit** A control that cannot do anything is worse than a missing control: the user fills it in, saves, and gets no error and no effect. The server rule turns that silent no-op into a clear refusal. The route gate stops a feature that an instance has turned off from staying reachable by URL, which is the same standard the Cases, Pipelines, and hidden-settings pages already meet. **Breaking changes** None for a default instance: both flags are off by default for self-hosted and managed instances, so nothing changes unless an operator turns them on. Stored `adapterConfig` values are never cleared, so turning the feature off restores every previous value. ## What Changed - Add `ui/src/hooks/useManagedSandboxOnly.ts`, modelled on `useAppsEnabled`, for components that do not already read the experimental settings. It exposes `hideHostPaths`, which fails closed while the settings query is in flight, so a cold cache never flashes a host path before the policy resolves. Components that keep their own settings read compute the same gate from `isFetched`. - Add `managedSandboxOnly` to `AdapterConfigFieldsProps` and populate it where `AgentConfigForm` builds the adapter field props. Resolve the effective instructions-file gate once as `hideInstructionsFile || hideHostPaths`, so every adapter hides that path field with no per-adapter edit. - Hide under the flag: the project "Local folder" block and its absolute-path edit panel (a managed checkout keeps its label, without the path); the new-project "Local folder" field; the project-workspace "Local path" field and fact row; the execution-workspace "Paths" and "Lifecycle commands" groups; the working directory on the workspace summary card, the task workspace card, the task properties "Folder" row, and the runtime service rows; the plugin "Local folders" section; "Working directory (deprecated)" and "Command" in the agent form; and the per-adapter "Execution engine", "ACP server command", and "ACP state directory" for `claude_local`, `codex_local`, and `gemini_local`. - Drop two working-directory fallbacks that had no gate to read: the close-workspace dialog now falls back to "No additional details", and the reuse-existing workspace label and picker subtitle fall back to a neutral phrase. - Refuse a non-null `cwd` with `422` on `POST /projects/:id/workspaces`, `PATCH /projects/:id/workspaces/:workspaceId`, and the nested workspace on `POST /companies/:companyId/projects`, following the `assertNoAgentHostWorkspaceCommandMutation` precedent on those routes. - Add `IsolatedWorkspacesRouteGate` and wrap the `/workspaces`, `/execution-workspaces/*`, and `/projects/:projectId/workspaces/:workspaceId` routes with it. - Leave the SSH "Remote workspace path" and the workspace file browser alone, with a comment explaining why. ## Verification Automated: - `pnpm --filter @paperclipai/ui exec vitest run` — 479 of 480 files pass (4455 of 4456 tests). The one failure is `OnboardingWizard.test.tsx > renders instead of throwing when the browser denies storage access`, which also fails on `origin/master` and is unrelated to this change. - `pnpm --filter @paperclipai/server exec vitest run project workspace instance-settings` — 45 of 50 files pass. Four files fail on macOS for reasons unrelated to this change: `workspace-instance-cleanup`, `workspace-runtime`, `execution-workspace-runtime-control-conflict`, and `workspace-runtime-exposure` compare `/var/...` against the resolved `/private/var/...` or bind real ports. The same files fail on a clean `master` checkout on the same machine. - `pnpm --filter @paperclipai/ui typecheck` - `tsc --noEmit` in `server/` (after `pnpm --filter @paperclipai/plugin-sdk ensure-build-deps`). The package `typecheck` script also builds the Rust runner, which needs `cargo`; it is not installed on the machine that ran this. New and extended tests: - `ui/src/adapters/managed-sandbox-only-config-fields.test.tsx` — the three adapters drop the execution engine, the ACP paths, the instructions-file path, and every "Choose" button when the flag is on, and keep the non-path controls. - `ui/src/components/AgentConfigForm.render.test.tsx` — flag-on and flag-off renders for the working directory, the command, the engine, the ACP paths, and the resolved adapter field props. - `ui/src/components/ProjectProperties.managed-sandbox.test.tsx`, `ui/src/components/NewProjectDialog.managed-sandbox.test.tsx`, `ui/src/pages/ProjectWorkspaceDetail.test.tsx`, `ui/src/components/ProjectWorkspaceSummaryCard.test.tsx`, `ui/src/components/WorkspaceRuntimeControls.test.tsx`. - `ui/src/components/IsolatedWorkspacesRouteGate.test.tsx` — redirect when off, render when on, and render nothing while the flag query is in flight. - "Still loading" cases for the project properties, the new-project dialog, the workspace summary card, the runtime service rows, and the agent configuration form, each asserting that no host path renders before the policy resolves. - `server/src/__tests__/project-workspace-managed-sandbox-routes.test.ts` — the `422` on all three write paths, the `cwd: null` pass-through, and the flag-off pass-through. Manual check to reproduce: turn on Managed Environment Only in instance experimental settings, then open a project, the new-project dialog, an agent's configuration, and a workspace page. No path, folder icon, or "Choose" button appears. Turn the setting off and each control returns with its stored value. No documentation change was needed. The operator-facing text for both settings lives in the feature catalog entry, which already states the contract this pull request now enforces across the UI. ## Risks - Low. Both flags default to off, so a default instance is unchanged. - The hidden fields are presentation only. No stored `adapterConfig` value is cleared, because an import carries adapter configuration written on another instance and clearing it would break that flow. Turning the setting off shows every previous value again. - The `422` is the one behavior change for an API caller, and only while the setting is on. `cwd: null` still passes so a stale path can be cleared. - The route gate renders nothing until the flag query settles, so an instance with isolated workspaces on never flashes a redirect. An instance with the feature off now redirects a bookmarked workspace URL to the dashboard. - Every host-path guard fails closed while the settings query is in flight, so a default instance shows those controls a moment later than before on a cold load. That is the safe direction: the alternative flashes a path a managed instance must never show. - Two path surfaces stay on purpose, each with a comment: the SSH "Remote workspace path" is a path on the user's own remote host, and the workspace file browser shows workspace-relative paths. The instance Adapters page also keeps its "Local path" install option, since that page is an instance-admin surface the hosting operator can already hide through the hidden-settings mechanism. ## Model Used Claude (Anthropic), Claude Opus, 1M context window, extended thinking, agentic tool use through Claude Code. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] All Paperclip CI gates are green - [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge |