mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-11-09 16:02:36 +01:00
c30a7c79bf034bc5286688ece0148b2ee31d7eff
2406
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
c30a7c79bf |
fix(ui): explain monitor waits during active runs
Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
eb5c24b61c |
perf(chat): speed up cached returns and preserve bottom follow (#19452)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - Agent Chat shows saved messages and native run output in one conversation. > - Reopening a chat rebuilt terminal transcripts and waited for network hydration. > - A queued scroll event could also disable bottom-follow after a cached editor increased the content height. > - This pull request reuses terminal history and preserves bottom-follow through that event order. > - The benefit is a faster cached return that opens at the latest reply. ## Linked Issues or Issue Description **What happened?** Returning to an agent chat could leave its latest reply below the viewport. Saved native transcripts also held the first reveal behind repeated network reads. **Expected behavior** A new chat navigation opens at the latest reply. A reader who scrolls up keeps their position. Back restores the earlier reading anchor. Saved history can render while the normal catch-up read runs. **Steps to reproduce** 1. Open an agent chat with saved native runs and task question cards. 2. Open Tasks, then reopen the same agent from Recents. 3. Observe the wait and the distance from the latest reply. **Paperclip version or commit** Reproduced on `523818ea9bf81f96abf4e6b73e81c2ce87518c07`. Rebased onto master `2f9d3d43c3`. **Deployment mode** Built from source with production UI assets and an isolated synthetic database. Related work: #18358 added recent-window chat loading. #18461 deferred completed transcripts for compact task opens. Open PR #14667 changes the reveal gate for task threads. This PR keeps that gate and caches hydrated terminal native history across visits. ## What Changed - Retain successful terminal native history in the application query cache. Keys include company, run, status and projection. - Render matching saved history immediately and continue the normal cursor-based catch-up read. - Preserve bottom-follow when content grows before a queued scroll event is delivered. Upward gestures and Back anchors retain priority. - Add regression coverage for remounts, catch-up, cache clearing, projection changes, cached question editors and scroll event ordering. - Repair two browser assertions: use a final 422 failure for explicit history retry, and accept saved task-view query parameters. - Document the local before/after comparison, including unchanged paths. ## Verification - Focused transcript and scroll suites: 51 tests passed after the review fixes, including a 300-run cache stability case. - Full UI suite on the rebased head: 896 files passed; 11,257 tests passed and one skipped. - Final review-fixed production UI: all 24 desktop/mobile chat journeys passed. - Final head: `pnpm -r typecheck`, `pnpm build` and `pnpm check:token-gates` passed. The complete GitHub CI test matrix, E2E, build and release checks passed for `4429a9aab4`. - The local repo-wide test command was stopped before performance sampling. Local acceptance used the full UI suite and the chat browser rig; CI completed the full repository matrix. - A parallel local build initially read a partially regenerated runner module while typecheck was emitting files. After typecheck finished, the serial full build passed. No runner source change was required. - The first browser run exposed the retry fixture's synthetic 500 being retried by the shared query policy. A final 422 response now verifies explicit retry. The Back assertion also now accepts the task collection's saved view query. - Re-measured the final reviewed build against the original baseline in five alternating pairs. The same retained 600-message/300-run fixture, Chromium at 1440×900 and 150 ms simulated latency produced cached-return medians of 580 ms (568–594) before and 155 ms (130–161) after. Median paired saving: 433 ms. All five pairs improved. A separate loopback asset host kept the manual test-drive build unchanged. - The initial full comparison found no reliable change to loopback cached returns, cold opens or uncached in-app entry. These are local results, not deployed staging measurements. - Greptile identified cache-expiry row loss and missing older output after a cached projection switch. Regression cases reproduce those paths. Mounted history now retains restored rows, and each projection retains its confirmed snapshot. The fresh review on commit `4429a9aab4` is 5/5 with no open findings. - One browser run overlapped a local rebuild and received a root-page 500. The server log records the missing generated index at that time. The run also timed out waiting for wheel acknowledgement after older rows had loaded; that input-acknowledgement cause was not established. After the build completed, the full serial run passed all 24 cases. - Run the opt-in browser rig with `tests/perf/agent-chat/playwright.config.ts` against a disposable loopback instance. See `tests/perf/agent-chat/README.md`. ## Risks - Cached history must not cross company, status or projection boundaries. Regression tests cover those cache misses and cache clearing. - Terminal output can receive late events. Cached history still performs catch-up reads, and retry, reconnect and mode changes retain their reads. - Programmatic scroll events can race with a reader gesture. Tests cover upward intent, delayed media and Back restoration. - This change does not improve cold-start latency. No schema, server authorization or exported data changes. ## Model Used OpenAI Codex using GPT-6. The runtime does not expose a more specific model ID or context-window size. Used reasoning, shell execution, repository editing, tests and browser profiling. ## 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: Paperclip <noreply@paperclip.ing> |
||
|
|
83c6832ccb |
fix(build): typecheck package, Playwright, and e2e test files in CI (#18839)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - Runner, plugin, and Playwright tests verify how those agents run, connect, and appear in the board > - Most package tsconfigs exclude tests, and Vitest strips types, so a type error in those tests fails nothing > - The tests drifted to 803 real type errors, and some of those errors hid assertions that checked nothing > - paperclipai/paperclip#18739 and paperclipai/paperclip#18738 check the server test tree and four test projects, but not these files > - This pull request adds a required check for these test files, fixes every error, and fails CI if a test file is in no program > - The benefit is that a type error in any test file outside `server/src` now fails CI ## Linked Issues or Issue Description Refs #18739 Refs #18738 **What happened?** 517 test files were in no program that required CI checks. A type error in those files did not fail CI. **Expected behavior** CI fails on a type error in any test file. **Steps to reproduce** Add `export const value: number = "text";` to a test file under `packages/paperclip-runner/src` on master. CI stays green, because `tsconfig.json` excludes test files and Vitest strips types. **Measured gap** Each row is a program with its tests included, on one thread. File and error counts are for head `7d4b5e907a`. Memory peaks were measured before the two latest merges of master. | Group | Test files | Real errors | Peak | | --- | ---: | ---: | ---: | | `paperclip-runner` Node source | 290 | 644 | 1.09 GiB | | `paperclip-runner` surfaces | 9 | 12 | 0.42 GiB | | `paperclip-runner` devtools and examples | 14 | 0 | 0.68 GiB | | `sandbox-providers/kubernetes` | 21 | 65 | 0.44 GiB | | 8 other sandbox providers and `bridge-template` | 32 | 4 | 0.34 GiB | | `plugins/sdk` | 22 | 15 | 0.41 GiB | | `plugin-workspace-diff` | 5 | 0 | 0.37 GiB | | `plugin-orchestration-smoke-example` | 1 | 1 | 0.15 GiB | | `kv-demo-mcp-server` | 3 | 0 | 0.13 GiB | | `packages/db` scripts | 1 | 0 | 1.01 GiB | | 8 Playwright suites under `tests/` | 52 | 25 | 1.72 GiB | | `tests/runner-acceptance` | 3 | 0 | 0.58 GiB | | `tests/e2e`, through layer declarations | 63 | 37 | at most 1.59 GiB | | `ui` `AttentionInteractionResolver.test.tsx` | 1 | 0 | n/a | | **Total** | **517** | **803** | | 27 of the 803 errors came from master while this pull request was open. Each merge of master brought new test code that no check had read. Errors that were config errors, not real errors: - One TS2688 for each provider, because the root install does not install provider dependencies. - 9 in the Runner Node program (TS7016 and TS6059). - 2 in `tsconfig.browser.json`. TypeScript 7 removed `baseUrl`, so that config was invalid. - 213 in the Playwright suites (`@/*` aliases and Vite types). - About 60 in `tests/e2e` (import extensions and aliases). `packages/plugins/create-paperclip-plugin` has no gap. Its tsconfig excludes its test, but `cli/tsconfig.json` reaches that test through an import. `server/test-baselines` also has no gap, because `tests/lifecycle-baseline` reads it. ## What Changed - Added `scripts/typecheck-test-programs.mjs` and its tests. The `Typecheck + Release Registry` job runs it. It checks each program in `PROGRAMS` on one thread. - The script fails if a tracked `*.test.ts(x)` or `*.spec.ts(x)` file outside `server/src` is in no program. The compiler file list decides this, because `include` drops `foo.test.tsx` when `foo.test.ts` exists. - Added a `tsconfig.test.json` to each uncovered package, and `tests/tsconfig.playwright.json`. - Added `tests/e2e` to `PROJECTS` in `scripts/typecheck-test-projects.mjs`, with a `tsconfig.json` and a `tsconfig.layers.json`. - Added `scripts/typecheck-sandbox-providers`. It is a small workspace that installs provider SDKs from one lockfile. I did not add a lockfile inside each provider, because `scripts/build-standalone-public-packages.mjs` uses a frozen install when one exists, and that changes what a release resolves. - Corrected `packages/paperclip-runner/tsconfig.browser.json` for TypeScript 7. - Set `rootDir` to `..` in `packages/paperclip-runner/tsconfig.test.json`, because one Runner test imports from `packages/adapter-utils/src`. The program does not emit files, so this changes no build output. - Moved the Kubernetes provider from `vitest ^3.2.4` to `^4.1.8`, the version the other providers use. Vitest 3 requires `tinypool ^1.1.1`, which has two critical advisories (GHSA-85c8-ppgw-ccpr and GHSA-5gmw-xhrv-c9v3). The first patched version is 2.1.2. Its tests have the same result on both versions: 189 passed, and the same 12 `file-sync` tests failed. - Moved the Kubernetes provider from `zod ^3.24.2` to `^4.6.6`, and gave its two `z.record` calls a key schema. This is the only production change, and it stays in this pull request. See "Production change for review". - Renamed `AttentionInteractionResolver.test.ts` to `AttentionInteractionResolver.replace.test.ts`, so TypeScript reads the `.test.tsx` beside it. - Fixed all 803 errors, with changes to test files and test support only. The fix for `contracts/native-execution.test.ts` is the same as the fix in paperclipai/paperclip#18739, so those two changes merge cleanly. - Updated `doc/DEVELOPING.md`. This pull request does not edit `server/scripts/typecheck-layers.mjs`. paperclipai/paperclip#18739 and paperclipai/paperclip#18738 have both merged, and this branch includes them. ### Production change for review The new lockfile made dependency review flag `zod@3.25.76` as a high-severity advisory (GHSA-mrhx-c7xc-m3w5). The first patched version is 4.6.6, so 3.x has no fix. The published Kubernetes plugin uses zod to validate operator config. The zod 3 source does not compile against zod 4, so a typecheck-only override cannot fix this. The existing tests do not prove this change, because they also passed with the invalid one-argument `z.record`. So I parsed 45 inputs with the same schema on zod 3.25.76 and zod 4.6.7: | Result | Inputs | Detail | | --- | ---: | --- | | Identical | 23 | Includes defaults, valid config, and a `__proto__` key | | Same outcome, new error wording | 21 | For example, `Invalid url` is now `Invalid URL`. `validateConfig` shows this text to operators. | | Different outcome | 1 | `jobTtlSecondsAfterFinished: 2 ** 60` was valid and is now rejected. The new limit is `Number.MAX_SAFE_INTEGER`. | I did not test this against a real cluster. The decision is to keep this change in this pull request. Since then, paperclipai/paperclip#17364 has moved the rest of the repository to zod 4.6.x, so the Kubernetes plugin now matches it. ### Behavior change for review `reducedMotion` under `use` is not a Playwright option. It had no effect in 11 configs and 2 `test.use` calls, so those suites ran with `no-preference`. The options are now under `contextOptions`, so reduced motion now takes effect. `app-shell-design.spec.ts` asserts a real transition, so it now asks for `no-preference` itself. The baseline manifest has `snapshotCount: 0`, so this invalidates no published baseline. A frozen trial reference PNG can differ. ### Findings These are product questions. I did not change them, and I did not hide them with casts: 1. **`PrpEvent` and its schema disagree.** The TypeScript type in `src/protocol/replay-contract.ts` requires `normalizedSessionId`. The `required` list in `protocol/schemas/event.schema.json` does not include it. `validatePrpEvent` accepts events that the type forbids. 2. **`requestCheckboxConfirmation` is stricter than its runtime.** It uses the output type, so plugin authors must pass `continuationPolicy` and `allowDeclineReason`, although the schema gives them defaults. `z.input` would fix this. 3. **`RetainedRunnerdMaintenanceInput.backend.kind` is a free string.** The quarantine domain comes from `descriptor.kind`, but the release uses `proof.backend.kind`. If they differ, `completeRetainedNativeSessionCleanup` returns 0 and the quarantine stays. The production caller passes `"runner"` today, so this is not a live bug. 4. **`CodexHarnessSession.close(input?)` is optional, but the contract requires `{ reason }`.** These are tests that verified nothing. I corrected them, and they pass: - `backends/native-instruction-measurement.test.ts` filtered on `placement === "core"`, which is not a valid placement. It measured an empty tool list. It now measures 14 tools. - `drivers/acpx/codex-acpx-driver.test.ts` checked for `usage.updated`, which is not an event type. - The `hostFixture()` helper in `drivers/acpx/runtime-host.test.ts` ignored two overrides, so `expect(prepareSandbox).not.toHaveBeenCalled()` could not fail. - `live/live-session.test.ts` set `agent: "pi"` before a spread that overwrote it. - `native-distribution-integrity.test.ts` passed an AbortSignal where `openCommand` expects `{ signal }`. These are gaps that this pull request does not close: - **The root lockfile still has some old zod versions.** paperclipai/paperclip#17364 moved the direct zod dependencies to 4.6.x. `pnpm-lock.yaml` still resolves `zod@3.25.76`, `4.1.11`, and `4.4.3`, which are below the patched 4.6.6. `packages/paperclip-runner/scripts/pi-distribution/package.json` pins `zod` to `3.25.76`, and some agent SDKs resolve `4.4.3`. Dependency review does not flag them, because this pull request does not add them. - **Dead GitHub coverage.** `chat-adapters-ui-providers.spec.ts` returned early for GitHub, so four later `provider === "github"` branches never ran. I removed them. They included the private key file and paste match, and the reconnect flow. Nothing asserts those behaviors in that spec now. - **Provider tests do not run in CI.** The root `vitest.config.ts` lists only Daytona. The other 8 providers, `bridge-template` included, are typechecked now, but CI does not run their tests. - **One `packages/db` test never runs.** `scripts/clean-poisoned-claude-sessions.test.ts` is outside the `include` of `packages/db/vitest.config.ts`. - **`plugin-orchestration-smoke-example` does not collect.** `@paperclipai/shared` is not linked in its `node_modules`. It passes 3 of 3 with an alias. ## Verification Run these commands: ```sh node scripts/typecheck-test-programs.mjs --low-memory pnpm --filter @paperclipai/server typecheck node scripts/typecheck-test-projects.mjs --low-memory --reuse-declarations node --test scripts/typecheck-test-programs.test.mjs ``` Results on macOS (arm64), Node 26.12. CI uses Node 24, and its `Typecheck + Release Registry` job also passes. At head `7d4b5e907a`, the test programs, `tests/e2e`, and the script tests pass again with 0 errors. The times and peaks below come from the run before the two latest merges of master: | Check | Result | | --- | --- | | Test programs, `--low-memory` | Exit 0, 0 errors, 42 seconds, peak 1.78 GiB | | Server layers, low memory | Exit 0, 0 errors, 38 seconds, peak 3.41 GiB | | Test projects, including `tests/e2e` | Exit 0, 0 errors, 13 seconds, peak 1.59 GiB | | Script tests | 12 passed | | Injected type error in each of 23 places | Each one failed its program with TS2322 | | Coverage check | 0 unchecked files, 10 seconds | I did not run this in a 4 GiB container. The peaks above are `maximum resident set size` for the largest single process. **Runtime check of the fixes.** Types do not prove that a test still works, so I ran the suites before the two latest merges of master: | Suite | Result | | --- | --- | | Runner, full suite | 4,885 passed, 3 failed, 13 skipped | | Sandbox providers, 10 packages | 939 passed, 12 failed, 36 skipped | | Plugin SDK | 200 passed | | `kv-demo-mcp-server` | 12 passed | | Renamed UI test and its sibling | 4 passed | All 15 failures exist without these fixes or come from the local machine: - **3 Cursor Cloud timeouts.** `artifact-delivery.test.ts` has 1 and `cursor-cloud-driver.test.ts` has 2. They time out in a full local run, and all 133 tests in those files with `codex-security-config.test.ts` pass when run alone. They fail in the same way with those two files at their unedited versions. - **12 Kubernetes `file-sync.test.ts` failures.** They fail in the same way before and after the fixes. The first failure is that `/proc/self/fd` does not exist on macOS. After each of the two latest merges of master, I ran only the Runner test files that I changed: | Merge | Result | | --- | --- | | `885c249cb9`, 8 files | 534 passed | | `7d4b5e907a`, 7 files | 672 passed, 16 failed | The 16 failures are in the two `source-reconciliation` test files. They fail in the same way with master's unedited versions of those files. 15 of them fail with `ACPX sidecar exited at initialize`, so I think my local build of the Rust and sidecar binaries is out of date. I did not rebuild them to check. CI builds them from scratch, and all Runner jobs pass in CI at `7d4b5e907a`. **Not run:** - `tests/e2e` and the 8 Playwright suites need a server, so most of them have only compile checks. `playwright test --list` loads 308 tests from the main e2e config. - `packages/plugins/sandbox-providers/kubernetes/test/integration` needs a cluster, so it has only compile checks. - I did not run the full `pnpm test:run` or root `pnpm build`. Required CI runs them. **Reduced motion.** I ran 6 motion-sensitive Storybook specs in system Chrome with a temporary config, once with `reduce` and once with `no-preference`. Both runs had 45 passed and the same 5 failed. So reduced motion did not change those results. The 5 failures do not depend on motion. At least one comes from the browser, because system Chrome prints `oklch(55.6% 0 0)` where the test expects `oklch(0.556 0 0)`. I did not run the other Storybook specs. The `storybook-visual` label runs that workflow. ## Risks - **A new lockfile to maintain.** A change to a provider `package.json` now fails the typecheck job until someone refreshes `scripts/typecheck-sandbox-providers/pnpm-lock.yaml`. The failure message gives the command. - **The job has a new install.** The step downloads provider SDKs, so it depends on the npm registry. It uses `--frozen-lockfile` and `--ignore-scripts`. - **The local install replaces provider `node_modules`.** A contributor with a standalone provider install must reinstall that provider after running the script. - **Reduced motion can change Storybook results.** See "Behavior change for review". That workflow is not part of required CI. - **Kubernetes plugin validation changed.** A release of this plugin ships zod 4. Error wording changes, and very large integers are now rejected. See "Production change for review". - **Master moves fast.** Each merge of master brought new test code with type errors, 27 so far. After this merges, the check reports those errors in the pull request that adds them. ## Model Used - Provider: Anthropic Claude, through Claude Code - Model: Claude Opus 5.5 (`claude-opus-5-5`) - Capabilities: tool use, code execution, and subagents for the type fixes in separate files ## 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) - [ ] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details. The app generated the branch name. - [ ] I have run tests locally and they pass. See the failures explained in Verification. - [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 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
0b8578055a |
fix: restore trailing spaces in queued steering messages (#19456)
## Thinking Path > - Paperclip lets people manage AI agents and give them more instructions during work. > - The task composer sends those instructions through the shared Markdown editor. > - The editor writes a final text space as the HTML entity ` `. > - The composer trims spaces before it submits a message. An entity survives this step. > - Queued messages can therefore contain extra text that the person did not type. > - This pull request restores final prose spaces at the editor output boundary. > - The queue and the agent receive clean message text. Code and escaped examples keep their source. ## Linked Issues or Issue Description **What happened?** A message that ends with a space can contain a final ` ` when it enters the steering queue. The shared editor exports this entity, and normal message trimming does not remove it. **Expected behavior** The editor must return final prose spaces as spaces. Code samples and escaped literal entities must keep their exact text. **Steps to reproduce** 1. Open a task while its agent works. 2. Type a steering message with a space at the end. 3. Submit the message to the queue. 4. Inspect its stored Markdown. Before this fix, it can end with ` `. **Paperclip version or commit** Reproduced from `70d23612dd` with the installed Markdown serializer. The serializer writes `Steer the current turn ` as `Steer the current turn ` plus a newline. Searches for related trailing-space and steering-entity PRs found no duplicate. ## What Changed - Restore trailing space entities only in the final Markdown text node. - Apply this step before the editor removes its other transport escapes. - Keep code, raw HTML, escaped entities, links, internal entities, and hard breaks unchanged. - Limit the fix to an entity at the end of the message. Keep entities before internal newlines or closing emphasis markers. Replacing those entities with spaces can create hard breaks or remove bold and italic formatting. Add tests for these limits. - Add editor regression cases and focused Markdown cases. Keep the fix in the shared editor; no queue API change is needed. ## Verification - TDD: the new editor test failed in 3 cases before the fix. It received literal entities instead of spaces. All 6 cases pass after the fix. - All 353 focused editor, Markdown, composer, and queue tests pass. This includes 10 new cases for internal newlines, emphasis, and a final space after these cases. - `pnpm check:token-gates` and `git diff --check` pass. - UI typecheck and UI production build pass. - Repository typecheck and build could not complete locally because Cargo is not installed. The full test command was started, then stopped after confirming its native Runner cases also need Cargo. No complete local full-suite verdict is claimed. Current-head [CI](https://github.com/paperclipai/paperclip/actions/runs/42229743296) passes for `350af775850664226d6630072cb8e08732e2a218`. This includes typecheck, build, tests, and E2E checks. - [Greptile](https://github.com/paperclipai/paperclip/pull/19456#issuecomment-6686109030) and [Paperclip review](https://github.com/paperclipai/paperclip/pull/19456#issuecomment-6686063906) each score the current commit 5/5. No review threads remain open. - Checked the design-review dependency claim against the current commit. [ui/package.json already declares the parser](https://github.com/paperclipai/paperclip/blob/350af775850664226d6630072cb8e08732e2a218/ui/package.json#L71). The existing underscore helper uses the same parser. Six direct checks also pass for GFM strikethrough, task lists, URLs, and tables. - No visual style changed. No database or API contract changed. The helper comment documents the storage rule. ## Risks - Low risk. The change only restores encoded spaces at the end of the document. Internal line endings and spaces inside emphasis are out of scope. The tests keep these entities unchanged to preserve Markdown formatting. Parser source positions protect code and HTML. Escape pairs protect literal entity examples. - Existing stored messages are not rewritten. They use the corrected output after an editor change. ## Model Used - OpenAI Codex, GPT-6. GPT-6.1 Sol (`gpt-6.1-sol`) assisted with the review follow-up. The runtime does not expose the context-window size. Used reasoning, repository tools, code execution, and test execution. ## 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: Paperclip <noreply@paperclip.ing> |
||
|
|
b8e69c6dd0 |
fix(ui): prevent layout shift when usage limits load (#19463)
Reserve the usage-limit property row during the first runtime-state request and replace its skeleton in place. Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
4696ff4990 |
fix: reserve agent In Progress display for active runs (#19453)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - Task status must tell operators whether an agent is working or waiting. > - A task can retain its in-progress lifecycle status after its run stops. > - The shared read projection only handled scheduled monitoring waits. > - The UI also ignored other projected statuses for in-progress tasks. > - This pull request requires an active task run for the In Progress display. > - Operators can see waits without changing execution or recovery authority. ## Linked Issues or Issue Description **What happened?** An agent task still showed In Progress after its run ended with an access failure and left a pending connection request. Stale execution locks and saved lifecycle state could show the same false activity. **Expected behavior** An agent task shows In Progress only with a task-linked queued or running run. Otherwise, it shows Blocked for recovery, In Review for a pending response or review, Monitoring for a scheduled check, or Todo for remaining work. Human ownership keeps its selected status. **Steps to reproduce** 1. Create an agent-owned task with an in-progress lifecycle status. 2. End its run and retain a pending human request. 3. Read the task, its summary, and search results. Before this change, they still show In Progress. ## What Changed - Derive visible activity from company-scoped, task-linked runs in the existing shared SQL projection. - Project inactive tasks to existing waiting or todo states. Preserve lifecycle status, locks, admission, and recovery. - Make the shared UI resolver use the projection while preserving explicit and optimistic status changes. - Cover stopped runs, stale locks, human waits, company isolation, monitoring, filters, counts, search, and UI labels. - Document the presentation rule in the product and execution contracts. ## Verification - Red before the server fix: 7 new regression cases failed because they returned in_progress. The 10 existing cases passed. - Green after the server fix: 20 cases passed in issue-display-status.test.ts, using embedded Postgres and real task APIs/search. Seven nearby active-question cases also passed. - Review regression: dismissed requests, historical questions, and returned review work each failed before the follow-up fix. All three now pass using the existing active-interaction rule and pending review state. - Red before the UI fix: 4 label cases failed. Five additional safety cases caught stale projections hiding explicit transitions. - Green after the UI fix: 43 tests passed across task-status-presentation, issue-filters, and issue-detail-subissues. - pnpm -r typecheck passed. All UI token gates and synchronization checks passed. - pnpm build passed. Server typecheck and build passed again after the review fixes. - Full CI passed on |
||
|
|
70d23612dd |
fix: offer Interrupt when queued-message steering is unavailable (#19450)
## Thinking Path > - Paperclip lets people manage work performed by AI agents. > - Task chat saves follow-up messages while an agent runs. > - A native runner can accept Steer only after an active provider turn exists. > - During preparation, or with an unsupported provider, the queue showed a disabled Steer button and no delivery action. > - The server also rejected Interrupt for ordinary native queues. > - This change offers an explicit Interrupt fallback and uses the existing cancellation and admission path. > - People can send their saved messages while Stop confirmation, cleanup, and execution gates remain enforced. ## Linked Issues or Issue Description Related: #15865 covers mixed legacy queues. #15030 covers steering acknowledgements. This change covers native queues without available steering. **What happened?** A queued message had a disabled Steer button while the native runner was still preparing. Clicking it did nothing. The server returned HTTP 409 for an explicit Interrupt request against the same native queue. **Expected behavior** Offer Steer when the provider can accept same-turn input. Otherwise offer Interrupt, labeled with its actual effect. Preserve saved messages until the previous execution stops and normal admission accepts the successor. **Steps to reproduce** 1. Start a task with the Paperclip Runner adapter. 2. Submit a follow-up while the run is preparing, before its provider turn opens. 3. Observe the disabled Steer button above the composer. 4. With this change, click Interrupt. The existing Stop path cancels the previous execution and submits the saved queue through normal admission. **Paperclip version or commit** Reproduced locally on master at |
||
|
|
1cd1e8c598 |
fix(ui): place task message copy control left of the timestamp (#19451)
## Thinking Path > - Paperclip is the open source app people use to manage agents at work. > - Task threads show a time below each message. > - Own messages align with the right edge. > - The copy control added in #19442 sits to the right of the time. > - This shifts the time inward even when the control is hidden. > - This pull request moves the control to the left of the time. > - The time stays at the outside edge. ## Linked Issues or Issue Description Refs #19442. **What happened?** The copy control occupies space to the right of the time on own messages. **Expected behavior** The copy control sits to the left of the time. The time stays at the right edge. **Steps to reproduce** Open a task with your own sent message. Move the pointer over its footer. ## What Changed - Move TaskChatBubbleActions before the time in the own-message footer. - Keep the layout change inside TaskChatBubble. No shared contract change is needed. ## Verification - All 36 TaskChatBubble tests pass. - Design-token gates pass. - UI typecheck and production build pass. - Browser layout checks pass on desktop and touch: copy is left of the time, the time ends at the bubble edge, and the time does not move on hover. - Clipboard contents and copied feedback pass. - Screenshots cover idle, hover, copied feedback, and touch using the production component in the existing Storybook fixture. - Current-head CI passed: build, typecheck, selected general tests, all eight e2e shards, policy, security, and aggregate verification. - Greptile and Paperclip reviews score the current commit 5/5. No open findings or review threads remain. - The first Greptile review requested an order assertion. The existing copy test now checks that the control precedes the time and the time is the last footer element. All 36 component tests pass. The review thread is resolved. - Initial test and Storybook commands used the wrong working directory or argument form. Corrected commands run successfully. - Local typecheck and Storybook initially could not resolve mdast-util-from-markdown. A frozen dependency install restored the missing package. Typecheck, build, and browser checks then passed. An early browser retry reached the server before it was ready; the ready-server run passed. ## Risks - Low risk. This change only moves the existing control before the time. ## Model Used - OpenAI GPT-6 Codex. Exact deployed model ID and context window are not exposed in this runtime. The agent used reasoning, tools, and code execution. ## 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 - [x] My branch name describes the change and contains no internal ticket id or instance details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable (existing copy tests cover unchanged behavior; browser checks cover position) - [x] I have updated relevant documentation to reflect my changes (the behavior is described here) - [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 |
||
|
|
2f9d3d43c3 |
feat(ui): copy own task messages as Markdown (#19442)
## Thinking Path
> - Paperclip is the open source app people use to manage agents at
work.
> - The task thread shows human messages and agent replies.
> - Users can copy agent replies with an existing control.
> - Users need the same control for their own messages.
> - This pull request adds that control beside the message time.
> - Users can copy the original Markdown and attachment links.
## Linked Issues or Issue Description
**What existing behavior does this improve?**
Copy a message from the task thread.
**Subsystem affected**
ui/ — React board UI.
**Current behavior**
Your own messages have no copy control beside the time.
**Proposed behavior**
Move the pointer over the time to show a copy icon. Select it to copy
the original Markdown. Keyboard focus also shows the icon. Touch screens
show it at all times.
**Reason and benefit**
Users can reuse their message text without losing Markdown or attachment
links.
**Breaking changes**
None.
## What Changed
- Reuse TaskChatBubbleActions in the footer of your sent messages.
- Keep the timestamp and iMessage source label.
- Show the control on hover or keyboard focus. Keep it visible on touch
screens and small screens.
- Respect the reduced motion setting.
- Test original Markdown, attachment links, copy feedback, other
authors, and pending messages.
- Add the required membership role to the existing routine-user test
fixture so UI typecheck can pass.
- Keep this behavior in TaskChatBubble. No shared contract change is
needed.
## Verification
- 45 focused component, artifact, and clipboard tests pass after rebase
onto master.
- The routine-user fixture tests pass: 9 tests.
- UI typecheck, UI production build, design-token gates, and browser
checks pass.
- Five screenshots cover idle, hover, copied feedback, keyboard focus,
and touch states. The existing Storybook own-message story uses the
production component with sample content.
- Browser checks verify clipboard contents and reduced motion.
- GitHub PR CI passed for
|
||
|
|
e9999071f3 |
fix(ui): store intraword underscores as typed, without the editor's escapes (#19350)
## Thinking Path
> - Paperclip is the open source app people use to manage AI agents for
work
> - People write task requests in the Markdown editor, and the stored
text becomes the agent's prompt
> - MDXEditor exports every literal underscore as `\_`, even inside
words such as `E2E_ASK_12` or `snake_case`
> - Agents then see backslashes the person never typed, and sometimes
repeat them in their answers
> - This pull request removes only the intraword escape when the editor
hands text back, as is already done for `\>` and `\<`
> - The benefit is that identifiers, filenames and exact strings reach
agents exactly as typed
## Linked Issues or Issue Description
**What happened?**
In QA staging smoke (launch 3108, task QA-671), a person created a task
through the UI that asked for the exact reply
`E2E_ASK_12_journey_1793913565974_507b01b8`. The stored description, and
the agent's prompt, contained `E2E\_ASK\_12\_journey\_…`. The agent's
`paperclip_finish` summary was unescaped, but its final answer copied
the escaped form. The posted reply therefore did not equal the requested
text, though the rendered Markdown looks the same. Earlier attempts
passed only when the model happened to unescape.
**Expected behavior**
Text the person typed is stored as typed. An underscore inside a word
never needs an escape, because CommonMark never treats it as emphasis.
**Steps to reproduce**
1. Type `snake_case` in any Markdown editor field, such as a new task
description or the chat composer.
2. Read the stored value through the API.
3. Before this change it is `snake\_case`.
**Paperclip version or commit**
master at
|
||
|
|
832ede93ed |
fix(apps): stop the Connectors page from pegging the CPU on managed instances (#19380)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - The Connectors page (`/apps`) merges native connectors with about 1,600 apps from the Composio and Arcade catalogs > - #19328 made some native connectors yield to aggregator sign-in on managed instances. To decide, it checks whether any aggregator serves each native row > - That check scans the whole catalog. It runs once per native row for every catalog app, so one pass makes about 1,600 × 110 × 1,600 name comparisons > - The pass also re-runs on every render, because a memo dependency is a `Map` rebuilt in the component body. Aggregator polling keeps renders coming > - On a managed instance, the page pegs a CPU core and does not become usable. Self-hosted instances skip the branch, and the tests used one or two catalog entries, so nothing caught it > - This pull request makes the check a set lookup, keeps the memo inputs stable, and adds a test at shipped catalog scale plus a general review rule for rendering large collections > - The benefit is that `/apps` loads normally on managed instances again, and similar regressions fail a test or get flagged in review ## Linked Issues or Issue Description Refs #19328 Refs #19247 **What happened?** On a managed instance, opening `/apps` pegs the CPU at 100%, and the page is very slow or unresponsive. **Steps to reproduce** 1. Open a managed instance (`useCloudInstance()?.managed === true`). 2. Go to `/apps`. 3. The tab holds a CPU core at 100%. **Expected behavior** The Connectors page renders in well under a second, and it does not re-run catalog work on unrelated renders. **Root cause** In `ui/src/pages/apps/Browse.tsx`, `yieldsToAggregators()` calls `hasAggregatorRoute()`. That function scans every aggregator catalog entry with regex normalization. The `managedCatalog` loop calls `yieldsToAggregators()` for every native row, for each of about 1,600 catalog apps. A Node benchmark with the shipped catalog data measured about 214 s per pass on a managed instance and 40 ms self-hosted. The `rows` memo depended on `upstreamAppsBySlug` and `gallery`, which were rebuilt on every render, so the memo never reused its result. ## What Changed - Index every aggregator identity once (`managedCatalogIdentities`), so the aggregator route check is one `Set` lookup. - Cache each slug's yield decision for the pass. Rows hold their final connections and chat endpoints by then, so the answer cannot change. - Normalize native row identities once before matching them against catalog apps. - Memoize `gallery`, the aggregator snapshots, `upstreamAppsBySlug` and `managedCatalog`. A small `useShallowStableItems` helper keeps the per-gateway `useQueries` data stable, so the `rows` memo runs only when connector data changes. - Match catalog apps to native rows through an identity-to-row index instead of scanning the native rows for each catalog app. The earliest row among an app's alias lookups is the row the old ordered scan found. - Add a test that loads the shipped aggregator catalog and every native connector in managed-instance mode, with a saved Composio gateway and account. It counts `aggregatorAppIdentity` calls. The full load must stay under 20× the catalog name count (today about 5×). An unchanged refetch and a search must not rebuild the rows, and a changed account must still appear. Above the limit the counter throws, so a regression fails in milliseconds instead of blocking the test worker. - Add `rules/ui-render-cost.mdc`, a general rule for `ui/src/**` code that renders large collections: no nested scans, stable memo dependencies, and a realistic-size test with a deterministic work counter when a change touches such a path. Register it in `.greptile/files.json`. ## Verification - `cd ui && npx vitest run src/pages/apps/Browse.test.tsx`: 100 of 100 pass. - With the previous `Browse.tsx` and the new test, the new test fails in 70 ms with "Connector catalog work exceeded its budget". - Measured on the new code: a full managed-instance load makes 25,810 identity calls for 5,095 catalog names. A search makes 0. - `node scripts/run-tsc.mjs -b` in `ui/`: no new errors. The only errors are in `PluginOrganizationSwitcher`, because `@paperclipai/plugin-sdk` is not built in a fresh worktree. They are unrelated to this change. - `pnpm check:token-gates`: all gates clean. - I did not check this in a browser on a managed instance. A local self-hosted instance does not take that branch. ## Risks - Low. The row-building logic gives the same results. The existing managed-instance Slack, Asana and Google tests still pass. - `useShallowStableItems` writes a ref during render. In the worst case, a concurrent render does one extra memo pass. It cannot return stale data, because it compares every item by identity. - The new rule applies to all `ui/src/**` reviews. Its body limits it to large or unbounded collections, to keep review noise low. > For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and discuss it in `#dev` before opening the PR. Feature PRs that overlap with planned core work may need to be redirected — check the roadmap first. See `CONTRIBUTING.md`. ## Model Used - Anthropic Claude Opus 5.5 (`claude-opus-5-5`) in Claude Code, with tool use (shell, file editing, test execution). ## 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 - [ ] All Paperclip CI gates are green - [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
21d2a577bb |
feat: show and change routine responsible users (#19128)
## Thinking Path > - Paperclip helps people manage AI agents and their work. > - Routines create tasks for repeated work. > - Each routine has a responsible person. > - The Overview did not show this person or permit a change. > - People need to see who will be responsible for automatic tasks. > - This pull request adds a small name picker beside Default agent. > - Authorized people can adopt a routine or transfer it to an active company member. ## Linked Issues or Issue Description **What existing behavior does this improve?** The routine Overview and the routine update API. **Subsystem affected** UI, server, and shared contracts. **Current behavior** The routine stores a responsible user. The Overview does not show that person. The update API cannot change that person. **Proposed behavior** Show Responsible user beside Default agent. Click the name to search active company members. Save only the new person and the current revision ID. **Reason and benefit** People can see who owns future automatic tasks. An authorized person can adopt a routine without making a new routine. **Breaking changes** The detail response adds an optional actor-specific field. The update API adds an optional responsible user ID. Existing requests keep their current behavior. Related: #17368 covers local Board ownership migration. This change adds the routine control and explicit transfer. ## What Changed - Show a quiet, searchable person picker beside Default agent. - Explain that automatic tasks use this person. Manual runs use the person who starts them. - Permit human operators with `tasks:assign`, instance administrators, and local operators to transfer responsibility. - Check active company membership inside the update transaction. - Save a revision and record the old and new person in the activity log. - Keep existing task responsibility and ownership during revision restore. - Show errors for failed saves and stale revisions. - Add tests for permissions, company boundaries, transfers, inheritance, and picker states. - Keep the picker disabled until saved data is refreshed. Refresh the activity list after a transfer. - Capture the actual previous person under the update row lock for the activity record. - Use shared query error handling and retain cached people during a connection failure. ## Verification - Focused checks cover 145 tests in 5 files. The first post-fix run passed 144 tests. One existing Fireflies route test timed out during the first import while the UI typecheck also ran. The same test passed in the pre-fix run. The isolated route suite then passed all 21 tests with no source change. - The new tests reproduce slow detail refreshes, activity refresh, and two concurrent transfers without a base revision. The concurrency test uses PostgreSQL row locks. - UI and server TypeScript checks passed at commit `1df9587eb`. - The UI production build passed for the updated head. - The branch includes master through `26391707f`. - Design token gates, query-error policy, and Git whitespace checks passed. The query-error policy reports zero findings. - Local browser checks passed on desktop and mobile for the initial feature commit. Search, selection, reload persistence, and revision creation passed. No page errors or horizontal overflow were found. The follow-up does not change the normal layout. - Earlier full local checks could not finish: Cargo was absent, and concurrent full test/build checks exceeded the 8 GiB memory limit. These attempts are not passes. - The first CI run failed on two error-rendering policy findings. That failure is fixed locally. The three findings from the first Greptile review are fixed and their threads are resolved. - Greptile reviewed `1df9587eb2d3e034c2769b1f6955ac52323c95bb` and scored it 5/5. It confirms all three prior findings are addressed. There are no open review threads. - [CI attempt 1](https://github.com/paperclipai/paperclip/actions/runs/42046369415/attempts/1) passed 53 checks. The server 8/12 shard failed only because the existing `history-http` runtime fixture did not become ready within 10 seconds (99 refused connections). The fixture and runtime source are unchanged from the merged master. That case passed locally on the same PR head with no source change. Its full 75-test suite also passed locally. The cause of the CI failure remains unknown. - [CI attempt 2](https://github.com/paperclipai/paperclip/actions/runs/42046369415/attempts/2) passed on `1df9587eb`: 54 successful checks, 3 skipped, and 1 neutral. No failed or pending checks remained. The original fixture-readiness failure remains recorded above. - A later review found that viewers with an explicit `tasks:assign` grant could see an editable picker even though writes were denied. Commit `8b95ee707` now mirrors active-membership and viewer restrictions in the GET capability flag. Instance-admin and local-operator behavior is preserved. - Three membership regressions failed on the incorrect editable flag before the fix. After the fix, all 43 routine-route and company-access cases passed (`--testTimeout 60000` accommodated this sandbox's cold route imports; no repository timeout was changed). The first pre-fix run timed out during the cold import in one case; the second pre-fix run reproduced all three assertion failures. - Layered server typechecking and whitespace checks passed after the permission fix. - [Fresh CI](https://github.com/paperclipai/paperclip/actions/runs/42057752313) passed on `8b95ee7075417527687b4a86cbaf63ba87408364` without a retry. Greptile reviewed this exact head, scored it 5/5, and added no new findings. All four review threads are resolved. The security status is also successful. - The separate Paperclip Review check is still queued because its assigned review worker requires runtime recovery. This is the remaining check before completion; the CI workflow itself passed. ## Risks - A transfer changes the person used for future automatic tasks. Existing tasks keep their current person. - Only people can transfer responsibility. The server checks the permission again on every write. - A stale revision rejects the save. The user must reload before retrying. - No database migration is required. ## Model Used OpenAI Codex, based on GPT-6, with reasoning, tool use, and code execution. The exact runtime model ID and context window are not exposed to this session. ## 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 - [ ] All Paperclip CI gates are green (CI passed; separate Paperclip Review check pending) - [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: Paperclip <noreply@paperclip.ing> |
||
|
|
a4bb059f59 |
fix(heartbeat): retry transient sandbox provider lease refusals and explain the block (#19412)
## Thinking Path
> - Paperclip is the open source app people use to manage AI agents for
work
> - A task runs in an execution environment. A managed sandbox
environment gets a lease from a sandbox provider (for example Daytona)
before the agent starts.
> - When the provider answered sandbox create with a temporary error
(HTTP 502), the run failed as the generic `setup_failed`.
> - `setup_failed` is the fail-closed code for unknown setup errors. It
gets no automatic retry, so the task went to `blocked` at once. The task
showed only "Couldn't finish this attempt".
> - A user had to find and press Retry. The Retry then worked, which
shows that the failure was temporary.
> - This pull request classifies temporary provider refusals during
lease acquisition from structured fields. It retries them within the
existing bounded bootstrap budget, and it explains the block when the
retries are used up.
> - The benefit is that a short provider outage no longer stops a task.
When the outage continues, the task shows the cause and a Retry that
works.
## Linked Issues or Issue Description
**What happened?**
A task was assigned to an agent that uses a managed Daytona sandbox
environment. Sandbox creation returned `HTTP 502`, and the cleanup of
the provisional sandbox could not be confirmed. The run failed with
`setup_failed` and the error `Failed to acquire lease for environment
"Paperclip Sandbox" (sandbox): Daytona sandbox creation failed (HTTP
502); cleanup could not be confirmed for paperclip-create-…`. Three
seconds later the task was `blocked`. No automatic retry was scheduled.
The task showed no specific reason. A manual Retry started a new run
that completed normally.
**Expected behavior**
A temporary provider error (HTTP 5xx, 429, timeout) before the agent
starts must retry automatically with bounded backoff. The task must show
why it waits. If the retries are used up, the task must show the cause,
a next action, and a Retry that works on the first click.
**Steps to reproduce**
1. Configure an agent with a sandbox environment.
2. Make the provider return HTTP 502 on sandbox create.
3. Assign a task to the agent.
4. See that the run fails with `setup_failed` and the task goes to
`blocked` with no retry.
**Paperclip version or commit**
`master` at `612da1e8e0`.
## What Changed
- Plugin SDK: an `environmentAcquireLease` error now carries a closed
diagnostic envelope (HTTP status or a closed errno code) across the
worker RPC. It takes the status of the create call only, not of the
compensating cleanup lookup. The existing creation-cleanup ownership
envelope is unchanged. New module: `environment-acquire-error.ts`. The
resume diagnostic helpers are shared.
- Server: new `EnvironmentProviderUnavailableError` and code
`environment_provider_unavailable`. The environment run orchestrator
sets it as the cause of `lease_acquire_failed` only when structured
evidence shows a transient status (408, 425, 429, 500, 502, 503, 504, or
a closed connection errno). It never parses message text. Saved-sandbox
resume and stopped-worker refusals keep their own codes.
- Setup failure (`failRunSetup`): a fresh, pre-dispatch run records
`environment_provider_unavailable` with a `providerFailure` (phase
`startup`, retryability `transient`). The run uses the bounded bootstrap
retry (30 s, then 60 s). An accepted interaction continuation keeps its
own continuation retry, as for `plugin_worker_unavailable`.
- Recovery: the new code is registered with the other bootstrap codes.
It is not sent to the generic continuation retry. It does not create an
execution-reconciliation hold, because no provider work started. On
exhaustion the stranded notice has the title "Sandbox provider was
temporarily unavailable" and a specific next action.
- UI: `ProviderFailureNotice` labels the `sandbox` provider as "Sandbox
provider". The task notice shows the provider failure, "Paperclip will
retry automatically" while a retry is scheduled, and Retry after
exhaustion.
- Docs: `doc/execution-semantics.md` describes the policy and the
sandbox ownership rule.
## Verification
Red before the fix, green after the fix:
- `server/src/__tests__/heartbeat-process-recovery.test.ts` › "transient
sandbox provider refusal during lease acquisition":
- "retries automatically and runs exactly one successful successor
without user action": the real heartbeat. The lease runtime returns a
Daytona 502 once, then delegates. Before the fix: one `failed` run and
no successor. After the fix: one `scheduled_retry` successor with no
hold and a `retry_scheduled` presentation. After promotion, exactly one
successor succeeds.
- "explains the block with a working Retry once automatic retries are
used up": three refusals. The task is `blocked` with a "Sandbox provider
was temporarily unavailable" notice. The presentation is `{ state:
"failed", canRetry: true, providerFailure: { httpStatus: 502 } }`, and
no execution-reconciliation hold exists. One `requestTaskRetry` is
accepted, and its run succeeds.
- `server/src/services/heartbeat/run-completion.test.ts` › "routes a …
sandbox provider lease refusal through bounded bootstrap recovery": the
real orchestrator wrapping. Only the fresh, structured 502 is retried. A
message-only 502, a 400, a run after provider dispatch, and a retained
native run stay `setup_failed`.
- `packages/plugins/sdk/tests/environment-acquire-error.test.ts`: the
real worker RPC. The test checks the create status (not the 404 cleanup
lookup), the errno, no provider text, the unchanged cleanup envelope,
and that forged envelopes are rejected.
Commands:
```sh
pnpm --filter @paperclipai/plugin-sdk exec vitest run tests/environment-acquire-error.test.ts tests/environment-creation-cleanup.test.ts tests/environment-resume-error.test.ts
cd server && npx vitest run src/__tests__/heartbeat-process-recovery.test.ts src/services/recovery/ src/services/heartbeat/run-completion.test.ts src/services/heartbeat/retries.test.ts src/services/legacy-execution-recovery.test.ts src/services/task-interruption-presentation.test.ts src/services/task-retry.test.ts src/__tests__/environment-runtime.test.ts src/__tests__/heartbeat-retry-scheduling.test.ts
cd packages/plugins/sandbox-providers/daytona && npx vitest run
pnpm --filter @paperclipai/plugin-sdk typecheck && pnpm --filter @paperclipai/server typecheck
```
I did not run a live Daytona 502 on staging. Re-check on staging after
deploy (see Risks).
## Risks
- Sandbox leaks or double creation: each retry is a new run with a new
durable creation record and a new provider name
(`paperclip-create-<operationId>`). The failed attempt stays owned by
its own record, and the existing creation reconciler settles it. A retry
never reuses or abandons it. While a provisional sandbox waits for
reconciliation, up to two more sandboxes can be created for the same
task. This is the same as a manual Retry today.
- Plugins built with an older SDK do not send the envelope. Their
refusals stay `setup_failed`, which is the current behavior.
- An in-process error with `status`/`statusCode` 500–504 or a connection
errno during lease acquisition is now retried twice. The budget is
bounded and shared with the other bootstrap codes.
- An RPC timeout on the host side is not classified by this change.
> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.
## Model Used
- Claude Opus 5.5 (Anthropic), model ID `claude-opus-5-5`, used through
Claude Code as an agent with tool use (shell, file edits, test runs).
Extended reasoning was on.
## 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
- [ ] All Paperclip CI gates are green
- [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
|
||
|
|
6ca7b151f7 |
feat: compact an agent's context from the task Properties panel (#19378)
## Thinking Path
> - Paperclip is the open source app people use to manage AI agents for
work
> - A task's Properties panel shows the assignee agent's context window
(paperclipai/paperclip#19273)
> - The board can see that the context is nearly full, but it cannot act
on it
> - A full context makes the agent compact at an unplanned time, often
in the middle of work
> - This pull request adds "Compact now" to the Context hover card
> - The benefit is that the board can compact the agent's context
between runs, at a time it chooses
## Linked Issues or Issue Description
Refs paperclipai/paperclip#19273
**Problem**
The Context row shows how full the agent's context window is. The board
cannot ask the agent to compact it.
**Proposed solution**
A "Compact now" button in the Context hover card. It runs the harness's
own compaction: Codex `thread/compact/start`, and Claude's `/compact`
command through ACP.
**Alternatives considered**
A separate PRP `session.compact` command. Both harnesses run compaction
as a turn, so a compaction turn keeps the existing durable turn binding,
interruption, and recovery. A separate command needs a second turn
lifecycle.
## What Changed
- UI: the Context hover card shows Compact now with three states:
available, Compacting…, and unavailable with a reason (agent mid-run,
harness unsupported, task closed). The Storybook story shows each state.
- Server: `POST /api/issues/:id/context/compact` (board only,
`decideIssueAccess` `issue:mutate`, activity log
`issue.context_compaction_requested`). It queues a short run marked by
`contextSnapshot.contextCompactionRequestId`. `GET
/issues/:id/context-usage` returns the `compaction` state.
- Server: a compaction run does no task work. The native status arbiter
preserves the task status. The lifecycle skips handoff, liveness
continuation, review-path disposition and the issue comment, as it does
for goal-control runs.
- Runner TS: `startTurn({ compact: true })`. The Codex harness session
sends `thread/compact/start`. The runnerd transport maps it to PRP
`turn.start` with `compact: true` (Codex) or `text: "/compact"`
(Claude/ACPX). The native runtime option `sessionCompaction` requires a
resumed session and settles with a synthesized yielded result.
- Runner Rust: `turn.start` accepts `compact: true` for Codex.
`CodexProvider::start_compaction_turn` sends `thread/compact/start` and
binds the turn from the `turn/started` that follows the empty response.
- Fix (from #19273): Codex emitted `context.compacted` on both the start
and the end of one compaction item. It now emits it once, and the count
is distinct by `compactionId`.
- Fix (from #19273): the conversation event view dropped
`context.compacted`, so a finished run never showed the divider. The
view now keeps compactions, plus context readings for runs that
compacted. A finished run's compactions show as thread dividers.
- Fix: the Codex harness stamps before/after sizes on the compaction
event. Codex reports the compacted size before the compaction item ends,
so the old neighbour-based guess showed the wrong size.
## Verification
- `pnpm -r typecheck`, `pnpm build`, `pnpm check:token-gates`, `node
scripts/storybook-catalog.mjs`: pass.
- New tests: `server/src/__tests__/context-compaction.test.ts`,
`status-arbiter.test.ts`, `issue-context-usage.test.ts` (duplicate
compaction counts once), `ui/.../context-usage-row.test.tsx`,
`native-session-runtime.test.ts` (context compaction), Codex driver and
runnerd transport tests, Rust
`codex_compaction_turn_binds_the_turn_reported_after_its_empty_response`.
Rust `codex_provider` suite: 115 passed.
- `pnpm test:run` locally: one failure in
`chat-channels.integration.test.ts`. It reads
`.claude/skills/slack/SKILL.md` from the main checkout, which is not
present in this worktree. It is not related to this change.
- Live, local worktree instance, Codex agent on the Paperclip runner:
clicked Compact now. The run succeeded. Context went from 35k to 9.4k
tokens, and later 9.4k to 9.2k. The task stayed In Review. The thread
shows "Context compacted · 9.4k → 9.2k tokens" and the meter dropped.
- Live Claude proof: pending. The local Claude agent needs an Anthropic
API key. claude-agent-acp handles `/compact` as an echo-less turn, and
the runner already maps its "Compacting completed." notice to
`context.compacted`.
## Risks
- A compaction run resumes the agent's session. If the session cannot
resume, the run fails with `native_context_compaction_unavailable` and
the task is unchanged.
- Compact now is not available while the agent runs on the task, because
compaction interrupts the active turn.
- The conversation view now returns context readings for runs that
compacted. Runs that never compacted return the same events as before.
- An old runner binary ignores `compact` and rejects the `turn.start`
because it has no text. It does not start an ordinary turn.
## Model Used
- Claude Opus 5.5 (`claude-opus-5-5`), Anthropic, through Claude Code
with tool use and code execution.
## 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
- [ ] All Paperclip CI gates are green
- [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
|
||
|
|
f8cb4957dc |
fix(ui): default Tasks to All tasks with a neutral sort header (#19393)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - The Tasks page helps people inspect work across their company. > - A new viewer currently starts in Mine and can miss other company tasks. > - The task table also shows an active sort header before the viewer selects a sort. > - This pull request starts new viewers in All tasks and keeps the default sort header neutral. > - People see company work in newest-update order and keep their saved view choices. ## Linked Issues or Issue Description **What existing behavior does this improve?** The initial task view and the task table's default sort state. **Subsystem affected** ui/ — React board UI. **Current behavior** Tasks opens Mine when the viewer has no saved view. The table highlights Last updated even when the viewer has not selected a column sort. **Proposed behavior** Tasks opens All tasks when no saved view exists. The table keeps newest-updated tasks first without an active header or arrow. A column selection or an explicit sort URL activates the selected header. **Reason and benefit** New viewers can inspect company work immediately. The header distinguishes default ordering from an explicit sort choice. **Breaking changes** The first-visit view changes from Mine to All tasks. Saved views and explicit view URLs keep priority. Existing Inbox and Needs attention preferences retain their meaning. The change does not alter task access or database contracts. **Additional context** Refs #19363. This change builds on the grouped task menu from that merged pull request. It uses the existing menu and design tokens. ## What Changed - Default the Coordinator and combined task surfaces to All tasks. - Preserve saved personal views and migrate previous picker choices. - Keep implicit Last updated descending order separate from active header state. - Test default ordering, explicit sorting, reset behavior, view selection, and preference migration. - Update the product and implementation docs. ## Verification - Passed 118 focused tests across task routing, table sorting, views, and collection preferences. - Passed `pnpm check:token-gates`, `pnpm -r typecheck`, and `pnpm build`. - Full `pnpm test:run` is running. Its result will be updated here. - Greptile passed the current head with 5/5 and no findings or open review threads. - Browser check: All tasks uses the grouped My work and Organization menu. Last updated has no active highlight by default. Selecting the header adds the sort URL and active direction. Removing the explicit sort restores the neutral header. - Manual check: Open Tasks with no saved task view. Confirm All tasks opens. Select Mine, leave Tasks, and return. Confirm Mine remains selected. ## Risks - The new default shows more accessible company tasks on the first visit. Saved view choices remain intact. - Task tables share the sort-state change. Explicit sort links and column clicks retain active styling. Default row order stays newest-updated first. - No schema, API, permission, or execution changes. ## Model Used OpenAI Codex, GPT-6 family. This session does not expose the exact model ID or context-window size. Used reasoning, code editing, terminal commands, and browser verification. ## 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 - [ ] 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: Scott Tong <scott@scottsmbpm5max.lan> Co-authored-by: Paperclip <noreply@paperclip.ing> |
||
|
|
8f79a32898 |
fix(connections): keep agent access consistent through setup and permission changes (#19352)
Task-hosted tool setup kept requester-only defaults, and audience edits could leave runtime installations restricted after permission bindings were widened. Large provider catalogs could also fail before creating an access card. Use the normal agent audience defaults for new tool setup, preserve explicit selections through verified OAuth and draft resumption, and synchronize permission bindings and runtime installations atomically. Enforce agent-edit authority and preserve existing access during additive account reuse. Validation: 915 focused regression tests, typechecks, and builds passed. All 54 CI checks passed and Greptile Apex scored the reviewed head 5/5 with no unresolved threads. Broad local test failures, recoveries, and incomplete heartbeat coverage are documented in the PR. Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
434d224c3a |
fix(ui): retry stale chunk reloads while a deploy settles (#19361)
## Thinking Path
> - Paperclip is the open source app people use to manage AI agents for
work.
> - The board UI loads each page as a lazy chunk. After a deploy, an
open tab can ask for a chunk from its old build.
> - #17349 added a recovery: the app reloads the page one time when a
chunk fails to load. A loop guard permits only one reload in five
minutes.
> - Staging error monitoring still reports `Failed to fetch dynamically
imported module` from builds that include #17349. The events come 1–10
seconds after page load, and 1–10 minutes after page load.
> - During a deploy, the old server and the new server can both answer
for some seconds. The reloaded page can then miss a chunk again. Also, a
second deploy can occur inside the five-minute window. In both cases the
guard stops the recovery, and the user sees the error page. One more
reload a few seconds later would recover.
> - #18518 keeps old chunks available after a deploy, but only on
deployments that enable shared UI assets. Other deployments still depend
on the reload recovery.
> - This pull request permits up to three reloads in the guard window.
The reloads wait 0 s, 2 s and 5 s, so that the deploy can settle. After
the last reload, the error page shows and reports as before.
> - The benefit is that a stale tab recovers through a normal deploy
without an error page and without error-monitoring noise. A chunk that
stays broken still shows the error after a small, fixed number of
reloads.
## Linked Issues or Issue Description
Refs #17349
Refs #18518
**What happened?**
A browser tab stayed open during a staging deploy. A lazy page chunk
failed to load with `TypeError: Failed to fetch dynamically imported
module`. The route error boundary showed "This page hit an error" and
reported the error. The release included the one-time reload from
#17349. The reload did not occur because the loop guard had already used
its single reload in the last five minutes.
**Expected behavior**
The app reloads again after a short wait while the deploy settles, and
the page loads. The error page shows only when the chunk stays broken.
**Steps to reproduce**
1. Open a board page on a deployment without shared UI assets.
2. Deploy a new build. While the old and new servers both answer, go to
a page that was not loaded yet.
3. The chunk fails, and the page reloads one time.
4. The reloaded page gets its HTML from one server and a chunk request
goes to the other server. The chunk fails again.
5. The guard stops the recovery, and the route error page shows.
**Paperclip version or commit**
`master` at
|
||
|
|
4550253dc9 |
feat(ui): rename Needs you to Inbox and move Mine into Tasks (#19363)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - Coordinator gives people navigation for conversations, tasks, and decisions. > - The decision entry is called Needs you, while a separate Inbox remains under More. > - Coordinator's personal task filter does not retain the full behavior of the original Mine view. > - This pull request names the decision entry Inbox and hosts the original personal work views inside Tasks. > - People keep their triage tools and saved choices without moving between two task destinations. ## Linked Issues or Issue Description **What existing behavior does this improve?** Coordinator navigation and the personal Mine view in Tasks. **Subsystem affected** UI navigation, task view routing, task collection preferences, and browser coverage. **Current behavior** Needs you opens the decision feed. More contains another Inbox destination. The default Coordinator task filter matches task creators and assignees. It does not use the full personal participation rules, archive behavior, shortcuts, grouping, or saved columns of the original Mine view. The organization task table also resets its column choices on reload. **Proposed behavior** Inbox opens the same decision feed with the inbox icon. Tasks defaults to Mine and remembers a person's selected view per company. Mine uses the existing personal Inbox implementation and preferences. It retains read/unread title weights, keyboard navigation, read/unread shortcuts, archive and undo, mobile swipe-to-archive, grouping, and saved columns. Old Inbox links open the matching task view. The organization task table saves its columns and order per person and company. **Reason and benefit** People get Chat, Tasks, and Inbox as distinct navigation entries. Personal work remains a view within Tasks without losing the existing triage behavior. **Breaking changes** Coordinator no longer offers the previous Inbox destination under More. Old Inbox URLs redirect into Tasks and retain query parameters and fragments. The Needs you label becomes Inbox; its decision feed, count, history, and resolution paths stay in place. Classic retains its separate optional combined-list setting. **Additional context** Refs: #19360, the workspace-defaults PR now integrated from master. Refs: #10620, related Inbox attention ordering. Duplicate searches found no open PR for this navigation and Mine integration. Roadmap review found no separate new execution feature in this scope. ## What Changed - Rename Coordinator's desktop and mobile decision entry and page to Inbox. Use the inbox icon. Remove the old Inbox item under More. Clarify that the combined-list experiment applies only to Classic. - Add one Coordinator task-view router. Host Mine, Unread, Recent, Blocked, and Everything through the existing Inbox owner. Keep organization views in the task table and board. Normalize legacy filtered URLs before mounting a collection so clearing the last filter preserves the current layout and local filters. - Reuse the existing Mine API, participation, read state, archive cache, undo, keyboard, mobile gesture, grouping, and preference paths. Existing personal column choices carry over. - Save organization task-table columns and order per person and company. Keep controls usable if browser storage fails. - Update navigation tests, routing and persistence regressions, exact-run retry browser coverage for each workspace variant, product documentation, and the affected Storybook notes. Keep existing story IDs. ## Verification - Preference, routing, navigation, task table, and inherited Inbox regression tests pass in focused runs. After integrating master and addressing the review finding, all 187 focused tests, UI typecheck, and token gates pass. - Full build and repository typecheck pass after integrating master. The full UI suite previously passed: 894 files, 11,169 tests passed, and one skipped. All 14 desktop/mobile triage and exact-run retry browser cases, including a fresh production UI build, pass after integrating master. - The full repository test suite was not run locally for this UI-only change; full PR CI is running. - Browser checks use a fresh isolated local instance and a deterministic process agent for real run-attributed unread activity. They exercise legacy URLs, title weights, saved grouping and columns, read/unread shortcuts, archive/undo, and a real mobile touch gesture. - Earlier browser fixtures were corrected: own activity is read, agent comments need valid run attribution, and undo uses `u` after the archive refresh completes. The Inbox content heading is scoped separately from the layout heading. - The final settings wording correction passes all 63 settings tests. - The [next CI browser run](https://github.com/paperclipai/paperclip/actions/runs/42137377960/job/127629100535) caught an old URL assertion for denied run retries. The test now pins each workspace variant and covers Coordinator Tasks explicitly. The old expectation fails deterministically for Coordinator; all 12 retry cases pass with the corrected destination, preserving exact run identity and truthful queued, deferred, and denied feedback. - Token gates, map checks, and Storybook catalog checks pass. All 30 map/catalog script tests pass. Storybook play tests were not run. - Greptile reviewed [the final commit](https://github.com/paperclipai/paperclip/commit/5f2f3789b83af259f694f379afb769465688fb72) at **5/5** with no new actionable findings. Its sort-only link finding is fixed and resolved: three cases fail before the fix and pass after it. `sortField` and `sortDir` keep organization links on the organization table. [Current-head CI](https://github.com/paperclipai/paperclip/actions/runs/42139668774) is running. - [CI exposed a routing race](https://github.com/paperclipai/paperclip/actions/runs/42135293421/job/127621981587) when removing the last label from a legacy Everything link. Four deterministic regressions failed before the fix and now pass: collections only mount after URL normalization. The existing end-to-end component cases confirm local filters, board layout, fragments, and history survive the change. - The [initial server shard 4 run](https://github.com/paperclipai/paperclip/actions/runs/42131163087/job/127608751620) failed an unchanged monitor-drain idleness assertion: two active operations remained instead of zero. The complete scheduling suite passes locally (54 tests). One isolated CI retry passed, including its dependent verification gate. The original timing failure's root cause is not established. ## Risks - Mine includes the existing tasks, approvals, failed runs, and join requests, preserving the original personal participation and attention rules. - Shared URLs with organization filters or table sort parameters still open the organization task collection. Task back-links retain their original fragments. - Saved preferences are browser-local. Mine keeps its existing storage keys; the organization table and selected Coordinator view use person/company scopes. - No database or server API contract changes are included. Existing company access, personal participation, and decision permissions retain their owners. ## Model Used OpenAI Codex, based on GPT-6, with reasoning, repository tools, code execution, and browser automation. The exact serving revision and context-window size are not exposed in this session. ## 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 - [ ] 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: Scott Tong <scott@scottsmbpm5max.lan> Co-authored-by: Paperclip <noreply@paperclip.ing> |
||
|
|
f2593b7905 |
feat: make Coordinator and Agent Chat standard and speed up navigation (#19360)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - People enter that work through the workspace, agent conversations, and tasks. > - Coordinator and Agent Chat still require experimental enrollment. > - Task link prefetches do not warm the compact queries used by the default task view. Chat also waits for a request when its navigation list already holds the conversation. > - This pull request makes Coordinator and Agent Chat standard and reuses the reads needed for navigation. > - People can choose Classic workspace in Experimental settings. Cached work can appear while fresh data loads. ## Linked Issues or Issue Description **What existing behavior does this improve?** Workspace selection, Agent Chat availability, and navigation between Chat, Tasks, and task details. **Subsystem affected** Cross-cutting: UI, workspace preferences, instance settings, and the database migration. **Current behavior** People must enable Coordinator and Agent Chat in Experimental settings. Opening a task can repeat requests because prefetch warms the full detail and comment queries, while the default view reads compact task data and a recent comment window. Opening Chat waits for a detail request even when the current person's conversation list contains it. **Proposed behavior** Coordinator is the standard workspace for everyone. Experimental settings offer Classic workspace, off by default. Old Coordinator experiment values do not select Classic. Agent Chat is available to everyone, including instances with an old saved or managed off value. Task link intent warms the queries used by the mounted view. Chat can use the current person's company-scoped conversation list during refresh. **Reason and benefit** People can use the standard workspace without setup. Repeat navigation can show cached content while the server refreshes it. **Breaking changes** Existing Coordinator experiment and Agent Chat off values no longer disable these surfaces. Classic requires an explicit new opt-in. The workspace API keeps its existing response shape and audit checks. The migration retains legacy values and adds a separate Classic preference. Execution permissions, company access, and chat privacy checks still apply. **Additional context** Roadmap check: this graduates existing surfaces and improves their navigation. It does not add a new agent execution capability. Duplicate searches found no open Coordinator workspace PR. Related server cache work, Refs: #17828, addresses compact issue-list invalidation; this PR addresses client navigation queries. ## What Changed - Add a default-off Classic workspace preference. Derive the existing workspace API response from that choice. Keep personal persistence, account isolation, and audited writes in the workspace preference service. - Replace the Coordinator experiment control with Classic workspace. Use Coordinator while preferences load. Update the existing settings examples and navigation recipe. - Retire the Agent Chat experiment control. Ignore old stored and managed off values. Retain the compatibility key and the existing execution and access checks. - Reuse account- and company-scoped chat list data with its original freshness timestamp. - Share compact task and recent-comment query options between prefetch and the task view. Keep full-history prefetch for Classic tasks and expanded history. - Add upgrade, replay, cache, account isolation, and browser switching regressions. Update product, database, development, and roadmap documentation. ## Verification - Targeted preference, settings, migration, cache, and UI regression tests passed during implementation. The cache tests hold refresh requests pending and check that content still renders. They also check account isolation and stale refresh behavior. - A real browser test verified fresh Coordinator defaults, Classic opt-in persistence, and return to Coordinator. It used an isolated source checkout with fresh data on macOS. - Token, migration numbering and safety, map, and Storybook catalog checks pass after the rebase. - Repository typecheck and build pass. Typecheck and token gates also pass after review repairs. The broad local run passed all six chat integration shards (1,931 tests). It then found the host-CLI-dependent recovery fixture described below. Its remaining duplicate work was stopped after the full current-head CI matrix passed; this is not a claim that the broad local command completed green. - Review repairs passed 419 UI/migration fixture tests, 19 Coordinator navigation tests, and all 214 tests in the five affected server suites. The 24 Chat/workspace browser tests pass, including standard Coordinator switching and explicit Classic persistence. - The broader browser repair run passed 85 tests. It retained two failed assertions and skipped five later serial cases. The affected files then passed all 11 tests after the fixes: reopen the desktop panel after reload and open More for Audit and Connectors. This includes the five serial cases that had not run. - The broad local suite exposed a recovery fixture that executed the host Codex CLI during a simulated remote probe. On a host with Codex 0.154.0, model fallback broke its fixed-model assertion. The fake sandbox now reports Codex 0.160.0. All 20 selected recovery/provider compatibility cases pass after the repair. - A CLI company import/export suite timed out during server startup in the second CI run. The port fallback is intentional in that fixture. No root cause was established. That suite passes on the final commit in CI. This records recovery, not a claimed product fix for the earlier timeout. - The first CI run exposed remaining assumptions about the retired flags and Classic UI. The repair commit updates those fixtures and navigation steps. It also restores the missing enabled Cases destination in Coordinator. Earlier local recovery attempts used the wrong fixture notification and advanced fake time during live execution; the corrected tests use the subscribed recovery queue and wall time during execution. - Greptile reviewed commit `98972b030d4505d838427a2fca6b196b8cad6d47` at **5/5** with no new comments. The original finding is resolved. - Current-head CI is green: **56 successful checks**, with three checks skipped by workflow filters. This includes typecheck, build, the complete Vitest matrix, all eight browser shards, Runner verification, release checks, and security checks. [Final CI run](https://github.com/paperclipai/paperclip/actions/runs/42132651414). - Typecheck caught missing `pid` and `startedAt` fields in the simulated command result. The fixture now returns the complete process contract, and the server test-layer typecheck passes. - Storybook catalog alignment was checked. Storybook play tests were not run. Hosted latency and cold bundle loading were not measured. ## Risks - The new default changes the workspace for people who previously left the Coordinator experiment off. They can opt into Classic in Experimental settings. - The additive migration must run before the new server code. It is safe to replay and preserves explicit Classic choices. - Cached content can be stale during background refresh. Existing query invalidation and source timestamps still control freshness. - These changes reduce avoidable loading waits. They do not establish a measured improvement in hosted request latency or initial bundle download time. ## Model Used OpenAI Codex, based on GPT-6, with reasoning, repository tools, code execution, and browser automation. The exact serving revision and context-window size are not exposed in this session. ## 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: Scott Tong <scott@scottsmbpm5max.lan> Co-authored-by: Paperclip <noreply@paperclip.ing> |
||
|
|
5ac05871b5 |
fix(onboarding): unify sign-in actions and recover failed logins (#19336)
## Thinking Path
> - Paperclip lets people create agents and connect their AI accounts.
> - Onboarding uses the shared login panel to connect Claude and OpenAI
accounts.
> - The sign-in link did not update the footer, so the footer could open
sign-in again.
> - A failed or expired sign-in also left onboarding without a retry
action.
> - This pull request gives both sign-in controls one action and makes
failed attempts recoverable.
> - Users can return with a code or start a fresh attempt while keeping
their setup.
## Linked Issues or Issue Description
**What happened?**
The onboarding instruction link opens Claude but leaves the footer
offering Sign in to Claude. If a code is entered without a paste event,
the footer opens provider sign-in again. A failed code, expired session,
or failed sandbox request can also leave an error with no retry control.
Component tests reproduce these failures.
This PR addresses that explicit footer action. It does not establish a
fix for unsolicited navigation of the original Paperclip tab to Claude
before code entry. That reported hosted-Cloud behavior remains under
investigation and needs browser-level evidence.
**Expected behavior**
The link and footer should use the same sign-in action. Both should open
one provider tab and put the footer into a disabled Waiting for code…
state. The code field should stay available. Failed or expired attempts
should show a clear message and an enabled Retry sign-in button.
**Steps to reproduce**
1. Choose Claude during onboarding with no saved subscription login.
2. Open Sign in to Claude from the instruction link.
3. Return and enter the authorization code without a paste event, such
as by typing it.
4. Press the footer action. Before this fix, it opens Claude again.
**Paperclip version or commit**
Reproduced in component tests against master at
|
||
|
|
bf10bc695a |
feat(task): show the agent's context window in task properties (#19273)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - Agents run through a harness (Codex app-server, or Claude through ACPX), and the runner turns harness events into Paperclip events > - Both harnesses report how full the model's context window is. Codex sends `modelContextWindow` with its token usage. Claude sends `used` and `size` in ACP `usage_update` > - Paperclip dropped both values. The task view could not show how close an agent is to compaction, and a compaction left no visible mark in the task chat > - This pull request carries the context-window occupancy through the runner, stores it with the existing usage events, and shows it as a "Context" row in the task Properties panel > - It also shows a "Context compacted · 230k → 38k tokens" divider in the task chat when the agent compacts its context > - The benefit is that operators can see when a long task is near its context limit and when the agent lost detail to a compaction ## Linked Issues or Issue Description Refs #19252 (same pattern: a canonical harness event turned into task-chat UI). Refs #19267 (status notices; it turns Claude's compaction banner into a notice, and this PR reads that notice too). **What existing behavior does this improve?** The task view shows no context-window information, and a compaction is invisible in the task chat. **Subsystem affected** Runner usage normalization (Rust and TypeScript transport), the PRP usage schema, a read-only issue API, the task Properties panel and the task-chat transcript. **Current behavior** Codex `modelContextWindow` and ACP `used`/`size` are dropped in the runner. `context.compacted` always has null sizes, Claude compactions emit no `context.compacted` event at all, and the live runner turn hides every marker except "interrupted". **Proposed behavior** `usage.reported` carries an optional `context {usedTokens, windowTokens}`. The task Properties panel shows a Context row ("10% of 258k") with a hover breakdown (tokens used, input and cached input, output, cost, compactions). The transcript shows a compaction divider, with sizes from the usage before and after the compaction. **Reason and benefit** Operators can see when a long task is close to its context limit, and they can see where the agent's earlier context was summarized. **Breaking changes** None. The new schema field is optional, and the new endpoint is read-only. ## What Changed - PRP `usage.schema.json`: add an optional `context {usedTokens, windowTokens}` object. Regenerate the schema bundle and the protocol manifest. - Rust `provider_events.rs`: add `codex_context_usage` (last request `totalTokens` and `modelContextWindow`) and `acpx_context_usage` (ACP `used`/`size`). ACPX `usage_update` now sets `context`. - Rust `provider_backend.rs`: Codex `thread/tokenUsage/updated` sets `context` on live (non-historical) usage. - Rust `provider_events.rs`: emit `context.compacted` for the completed `context_compaction` provider notice that #19267 produces from Claude's compaction banner. Only this path marks a Claude compaction, so the server counts each compaction once. - `runnerd-codex-transport.ts`: `rehydrateRunnerdUsageNotification` keeps a valid `context` on `tokenUsage`, so it reaches the stored `item.completed` usage item. - Server: new `GET /api/issues/:id/context-usage` (issue read access is required) and `issueContextUsage` service. It reads only the assignee's current session (the session of its newest usage report), and returns that session's latest context reading, non-zero totals, cost, and the count of compactions across all of the session's runs. Added to OpenAPI. Shared type `IssueContextUsage`. - DB: migration 0432 adds two partial indexes on `heartbeat_run_events`, built concurrently. One indexes usage items by run and time. The other indexes `context.compacted` events by company and session. `EXPLAIN` shows that both lookups use them. - UI: new `ContextUsageMeter` (bar, percentage, hover card) and `IssueContextUsageRow` in the Execution section of Properties. The row refreshes every 8 s while a run is active, and once more when the run ends. - UI transcript: `native-run-events.ts` maps `context.compacted` to a `context` activity entry with pre/post sizes from neighbouring usage items. `transcript-adapter.ts` turns it into a new `context_compacted` marker variant. The live runner turn keeps that marker as its own timeline row. - Storybook: `task-context-window.stories.tsx` (Properties panel in a task, all states, hover breakdowns, divider). ## Verification - `cargo test -p paperclip-runner-core --lib provider_events` (new tests: ACPX context, Codex context, banner compaction, notice compaction) - `pnpm --filter @paperclipai/paperclip-runner exec vitest run src/live/runnerd-codex-transport.test.ts` - `cd ui && npx vitest run src/components/ContextUsageMeter.test.tsx src/components/transcript src/components/task-chat src/components/issue-properties` - `cd server && npx vitest run src/__tests__/issue-context-usage.test.ts` (embedded Postgres) - `node scripts/typecheck-low-memory.mjs`, `pnpm check:token-gates`, `pnpm --filter @paperclipai/paperclip-runner run check:protocol-types` - Live check on a local worktree instance through the runnerd path: - A Codex `gpt-5.5` task showed "10% of 258k" (27k of 258k, input 77k with 49k cached, output 1.1k). - A Claude Sonnet 4.6 task showed "17% of 200k" (34k of 200k). - Storybook: Tasks and conversations / … / Task chat / Context window. - Not verified live: a real compaction. The divider is covered by unit tests through the same projector path the task chat uses. ## Risks - The schema field is optional, and older runners omit it. The UI renders nothing until a harness reports a window. - Migration 0432 builds two partial indexes concurrently on `heartbeat_run_events`, which is a large table. The indexes cover only usage items and compaction events, so they stay small. They add a little write overhead to those events. - Claude in-progress usage rows still record zero tokens with `requests: 1`. The final turn usage is correct. This PR does not change accounting. - A "Compact now" action is out of scope. It needs a compaction-only run that does not produce a run result. It will come in a follow-up. ## Model Used - Claude Opus 5.5 (`claude-opus-5-5`), Anthropic, used through Claude Code with tool use (shell, file edits, in-app browser for Storybook and the live instance). ## 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 - [ ] All Paperclip CI gates are green - [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
4ece2107b8 |
fix(connections): offer aggregator Slack sign-in on Cloud instead of a customer OAuth app (#19328)
## Thinking Path
> - Paperclip is the open source app people use to manage AI agents for
work
> - Connectors let people give agents tools, such as Slack, from the
Connectors catalog or from an agent's inline "Connect" card
> - On Paperclip Cloud, the only Slack path is "Slack needs its own
OAuth app". The user must create a Slack app, paste a callback URL, and
enter a Client ID and secret
> - Managed Slack chat setup exists, but it is behind the experimental
Chat connectors setting, which is off on Cloud. Composio's and Arcade's
managed Slack sign-in exists, but the native Slack row hides it
> - In an onboarding test on Cloud, a tester got this card from the
onboarding agent, spent 7 minutes on it, and declined it. No Slack
connection was made
> - This pull request follows the existing Google Workspace pattern: on
Cloud, a native connector whose every setup path needs a
customer-created OAuth app yields new setup to the aggregators' managed
sign-in, in the catalog and in agent connection discovery
> - The benefit is that Cloud users can connect Slack with a sign-in
instead of creating a Slack app
## Linked Issues or Issue Description
**What happened?**
On a Paperclip Cloud instance, the onboarding agent asked the user to
connect Slack. Connectors > Slack > Connect showed "Slack needs its own
OAuth app. Slack does not let Paperclip register itself automatically,
so this connector needs an OAuth app you create." The form asks for a
callback URL, a Client ID and a Client secret. It has no link to Slack
app settings. The method description said "Use the provider-hosted
connection for the quickest setup." The tester gave up. The original
notes said that the cloud connector asked for an HTTPS server. That is
not correct: no HTTPS or deployment-mode check is in this path. The real
blocker is the customer OAuth app requirement.
**Expected behavior**
Slack can be connected from the supported Cloud flow without setup steps
that only an operator can do.
**Steps to reproduce**
1. On a Cloud instance with Chat connectors off (the Cloud default),
open Connectors and search for "Slack".
2. Click Connect on Slack. The "needs its own OAuth app" form opens.
3. Or, let an agent call `connections_search("Slack")`. It returns
native `slack` first, and its card opens the same form.
**Additional context**
Evidence: the Slack gallery entry on the Cloud instance had
`ownershipAvailability` `platform_shared: false`, `platform_provisioned:
false`, `customer: true`. `GET
/api/companies/:id/chat-slack/setup-options` returned 403 "Chat
connectors are disabled".
## What Changed
- `packages/shared`: add `nativeConnectorRequiresCustomerOAuthApp(app,
settings)`. It is true when every available setup path of a native
connector needs a customer-created OAuth app: no Paperclip-managed
client, no dynamic client registration, and no enabled chat setup.
- `ui/src/pages/apps/Browse.tsx`: on Cloud, such a connector yields to
aggregators, the same as the built-in Google connectors. The catalog
shows the "Connect through Composio or Arcade" row, and its Connect
button opens the provider choice. A saved native connection, a chat
endpoint, Chat connectors on, a self-hosted instance, or no aggregator
route keeps the native row.
- `server/src/services/connection-intents.ts` and new
`connection-native-yield.ts`: agent `connections_search` uses the same
rule. On Cloud, it does not prefer native Slack for new setup, so the
agent asks the provider-choice question (Composio, Arcade or Zapier).
The rule applies the advertised Paperclip Cloud connector profiles, so
apps with a managed Cloud client (for example Asana) do not yield. If
the profiles cannot be read, the native connector stays.
- `slack.json`: correct the Slack tool method copy, which said "quickest
setup". Add a "register" console link to `https://api.slack.com/apps`,
so the form now shows "Open Slack app settings".
- Tests in all three layers.
## Verification
Red/green. I committed the tests first (`2386fd83df`) and ran them
against unchanged source code.
**Red (before the fix):**
```
server › aggregator connection fallback › Slack on Paperclip Cloud
× offers aggregator Slack routes while native Slack only supports a customer-created OAuth app
AssertionError: expected [ 'slack', 'google-calendar', …(7) ] to deeply equal [ 'via:composio:slack', …(2) ]
+ "slack", "google-calendar", "google-docs", ...
Tests 1 failed | 3 passed | 45 skipped (49)
ui › Connectors landing page
× offers aggregator Slack sign-in on Cloud while the built-in Slack connector needs a customer OAuth app
AssertionError: expected 'SlackSend and read messages in your t…' to contain 'Connect through Composio or Arcade.'
Received: "SlackSend and read messages in your team's channels.Connect"
Tests 1 failed | 5 passed | 92 skipped (98)
shared › Slack tool connection guidance
× describes the customer-created Slack app honestly and links to Slack app settings
AssertionError: expected 'Use the provider-hosted connection fo…' not to match /quickest/i
Tests 1 failed | 3 passed (4)
```
**Green (after the fix):**
```
✓ server › Slack on Paperclip Cloud › offers aggregator Slack routes while native Slack only supports a customer-created OAuth app
✓ server › Slack on Paperclip Cloud › keeps native Slack when Chat connectors provide its own setup path
✓ server › Slack on Paperclip Cloud › keeps native Slack for a company that already saved a Slack connection
✓ server › keeps native Slack on self-hosted instances, where operators register their own Slack app
✓ ui › offers aggregator Slack sign-in on Cloud while the built-in Slack connector needs a customer OAuth app
✓ ui › keeps the built-in Slack connector when Chat connectors offer its setup path
✓ ui › keeps the built-in Slack connector when the instance is self-hosted
✓ ui › keeps a saved built-in Slack connection on its native row on Cloud
✓ shared › describes the customer-created Slack app honestly and links to Slack app settings
✓ shared › flags Slack only while its chat setup is unavailable
✓ shared › does not flag connectors with a managed, dynamic-registration, or credential path
```
Neighbouring suites:
- `packages/shared` (all): 98 files, 1060 tests passed
- `ui` `src/pages/apps` + `src/features/connections`: 54 files, 980
tests passed
- `server` `connection-aggregator-fallback` 49/49,
`connection-intents-service`, `native-connection-baseline-fixture`,
`runner-connection-eval-fixtures` passed. `satisfied-connection-intents`
52/52 passed when run alone. It had a suite-setup error only when three
embedded-Postgres runs went in parallel.
- `pnpm check:token-gates`: clean. `tsc --noEmit` shows no errors in
changed files. Local runs show unrelated errors because the
`paperclip-runner` workspace package is not built. CI runs the full
typecheck.
Still needs a live Slack workspace to prove:
- Complete Slack sign-in through Composio or Arcade on a Cloud instance,
and an agent tool call to Slack.
- An agent run on Cloud that asks the provider-choice question for Slack
and then connects through the selected aggregator.
## Risks
- Behaviour change on Cloud only, for native connectors whose every path
needs a customer-created OAuth app and that an aggregator serves. Today
that is Slack (when Chat connectors are off), and Box and Xero if the
aggregator catalog has them. On Cloud, these move to the aggregator
route for new setup, the same as the built-in Google connectors. Saved
connections keep their native row and discovery.
- Cloud users who want their own Slack app can still open
`/apps/connect?source=slack`, but the catalog row no longer links to it
while the rule applies.
- Self-hosted instances keep the native connector unchanged.
- Follow-up, not in this PR: enable managed Slack chat on Cloud (Chat
connectors Cloud default and `PAPERCLIP_SLACK_MANAGED_SETUP_ENABLED`).
This is a flag and operations change. It needs the Cloud Slack broker to
be proven first. When it is enabled, this rule stops yielding Slack
automatically.
## Model Used
- Claude Opus 5.5 (`claude-opus-5-5`), Anthropic, via Claude Code with
tool use (shell, browser inspection of a staging instance, file
editing).
## 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
- [ ] All Paperclip CI gates are green
- [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
|
||
|
|
c3550cfb38 |
fix(daytona): send archive chunks in bounded windows (#19339)
## Thinking Path > - Paperclip manages agents and saves their work when execution stops. > - The Daytona plugin saves an archive through a terminal when disk capacity prevents the normal archive or download copy. > - That fallback sent one 40 KiB chunk and waited for its host write acknowledgement. > - Network delay then applied to every small chunk. A large archive could exceed the recovery deadline even while bytes were moving safely. > - This pull request sends a bounded window of chunks and still acknowledges every completed host write. > - The benefit is faster recovery over delayed connections, with bounded memory and the existing size, space and completion checks. ## Linked Issues or Issue Description Refs #19034, which added the capacity fallback. **What happened?** The archive fallback waits for one network round trip after each 40 KiB chunk. A saved workspace archive can be much larger than that chunk. Repeating a timed-out transfer does not remove this throughput limit. **Expected behavior** Allow a small amount of data to travel before waiting for acknowledgements. Keep memory bounded, write bytes in order, and stop after any write or protocol failure. **Steps to reproduce** 1. Run the real Bash archive sender against a host that delays each acknowledgement by 400 ms. 2. Transfer 1 MiB plus a partial final chunk with a four-second deadline. 3. The original implementation times out. The bounded-window implementation completes and preserves the exact source bytes. **Paperclip version or commit** The failing regression uses the original implementation from `6a66c09f7f7`. ## What Changed - Send at most sixteen 40 KiB chunks before collecting their acknowledgements. Drain the final partial window before the completion receipt. - Serialize host writes and reject more than sixteen pending frames. Stop queued writes on the first failure. - Keep per-frame size checks, total archive limits, the 1 GiB host space reserve, the transfer deadline and bounded teardown. - Add a real Bash regression with delayed acknowledgements, plus overflow and failed-write coverage. Update the plugin documentation. - Update the agent-creator test fixture for the required directory membership role introduced by #15183, which otherwise breaks merged CI typechecking. ## Verification - Failing first: the final real-Bash regression fails against the original source with `Daytona archive stream timed out`. It passes with the change. The empty-stream case passes too. - Standalone Daytona package `pnpm test`: 578 passed, 8 skipped. The skips are the existing opt-in live tests. - Standalone package `pnpm typecheck` and `pnpm build`: passed. - `pnpm test src/file-sync-capacity.live.test.ts` with a staging Daytona key: 2 passed on isolated test sandboxes. This covers actual terminal transport, stop/start, archive and file-copy capacity failures, exact saved hashes, safe links, cleanup and a second export. The tests removed their own sandboxes. - The production dependency assumption is bounded: at most 640 KiB of decoded payloads can wait for host writes. The parser also has a bounded encoded buffer. No background work or idle timer is added. - Initial hosted CI failed with TS2741 in `ui/src/lib/agent-creator.test.ts` after #15183 made `membershipRole` required. Rebased onto that change and added the nullable field to the fixture. UI `pnpm typecheck`, all 4 existing creator-label tests, and `pnpm check:token-gates` now pass locally. Hosted CI subsequently passed on the updated head. - `git diff --check` and a local secret and PII scan: passed. - Full repository checks were not repeated locally for this standalone plugin change. Hosted verification at `bf6b3cb6a622a9523c72b86fdfe616555c8f3ef8`: all 53 check runs passed, with the 2 opt-in Storybook checks skipped; both required gates (`ci / verify`, `ci / e2e`) passed. Greptile is 5/5 at this exact head, with no review threads or merge conflicts. The separate non-required `security/snyk (cryppadotta)` status remains pending; it is not claimed as passed. ## Risks - A burst can queue up to sixteen chunks instead of one. The receiver enforces this bound and acknowledges a chunk only after its ordered host write. - The timeout budget is unchanged. A connection that cannot finish within that budget can still fail. This change does not retry a provider turn or change file-recovery authority. - Source confinement, archive validation, successful producer completion and publication rules are unchanged. No schema migration. ## Model Used - OpenAI `gpt-6.1-sol` with xhigh reasoning, in Codex through T3 Code. Tool use included source edits, real Bash and filesystem tests, and isolated Daytona tests. The runtime does not expose its context window. ## 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: Paperclip <noreply@paperclip.ing> |
||
|
|
00c7738513 |
fix(task-chat): keep messages sendable after a declined connection request (#19331)
## Thinking Path
> - Paperclip is the open source app people use to manage AI agents for
work
> - The task chat composer shows a queue of saved input that waits for
the agent's next turn
> - When a person declines a connection request (for example Slack), the
server queues a read-only receipt so the agent learns the outcome
> - The composer showed that receipt with its raw JSON receipt in hover
text, and the receipt hid the person's next message
> - The next message could not be edited, discarded, or sent, so the
chat looked stuck after a simple "Decline"
> - This pull request shows a readable status for receipts and keeps the
person's own later messages visible and actionable
> - The benefit is that declining a connection resolves cleanly and the
conversation continues
## Linked Issues or Issue Description
**What happened?**
During an onboarding test on staging, a person declined the agent's
"Connect Slack" request. A queued steering item then stayed above the
composer. It could not be edited. Its hover text showed raw JSON.
Sending the next message produced an error.
**Steps to reproduce**
1. Give a task to a Paperclip runner agent whose run is active or waits
on a busy workspace.
2. Let the agent request a connection, then decline it.
3. See the queued item "Rejected: Connect Slack". Hover it: the title is
the full JSON receipt.
4. Send another message. The message never appears in the queue. Its row
controls stay disabled. Send or Interrupt on the receipt queue returns
`409 This queue does not support interruption`.
**Expected behavior**
A declined connection request resolves cleanly. It shows a readable
status. The next message can be sent.
**Evidence (staging wake diagnostics for the test task)**
- 17:52:09: the decline wake for the Slack request. It stayed deferred,
was never claimed, and was skipped at 18:21.
- 17:52:10: a later retry wake for the plan-approval continuation.
- `GET /issues/:id/queued-comments` projects the oldest matching wake.
From 17:52 to 18:21 the composer showed the Slack receipt.
Refs: related to the separate plan-approval queued-message fix, which
changes the recovery sweep. This PR only touches the queue projection
and the receipt label.
## What Changed
- `server/src/services/queued-interaction-response.ts`: add
`queuedInteractionSummary()`. A receipt now has one readable line, for
example `Declined: Slack connection`, `Connected: GitHub connection`, or
`Accepted: Build the app`. The entry `source.summary` carries it. The
steering body for the agent still includes the typed JSON receipt.
- `server/src/routes/issues.ts` (`findQueuedCommentWake`): a queued
user-message wake now takes precedence over a receipt wake. A receipt
shows only when it is the only queued input. The receipt wake itself is
unchanged and is still delivered to the agent.
- `server/src/modules/wake-queue/adapters/postgres.ts`
(`findExistingDeferredWake`): skip interaction-receipt wakes when a new
message picks the deferred wake it merges into. Before, the receipt was
the oldest deferred wake, the merge was skipped, and every later message
started its own wake. Only the first message then appeared in the queue.
Receipts still never absorb user input.
- `packages/shared/src/types/issue.ts`: add the optional `summary` field
to `IssueQueuedCommentEntry.source`.
- `ui/src/components/task-chat/TaskChatQueuedMessages.tsx`: add
`queuedMessageLabel()`. The row text, the hover title, and all
aria-labels use the summary. They never use the raw steering body.
## Verification
Red/green tests were written first and run against the unchanged code.
New tests:
- `server/src/__tests__/issue-queued-comments-routes.test.ts`
- `shows a declined connection receipt as a readable status, not its
JSON`
- `keeps the next message visible and actionable after a declined
connection (running run | stopped run)`: declines Slack, posts the next
message, and asserts that the queue lists that message with
`canEdit`/`canDiscard`, that the discard works, and that the receipt
wake is still pending for the agent.
- `queues every later message together after a declined connection
(legacy run | stopped run)`: two messages after a decline both appear in
one editable queue, and the receipt wake keeps no message ids.
- `ui/src/components/task-chat/TaskChatQueuedMessages.test.tsx`
- `shows a declined connection request as readable text, never its raw
JSON receipt (BUG-08)`
**Red (unchanged code):**
```
server: × shows a declined connection receipt as a readable status, not its JSON
AssertionError: expected { kind: 'interaction', …(3) } to match object { …, summary: 'Declined: Slack connection' }
server: × keeps the next message visible and actionable after a declined connection (running run)
server: × keeps the next message visible and actionable after a declined connection (stopped run)
AssertionError: ["Declined: Slack connection"]: expected undefined to match object { canEdit: true, canDiscard: true }
(the queue lists only the receipt; the new message is missing)
Tests 3 failed | 85 skipped (88)
ui: × shows a declined connection request as readable text, never its raw JSON receipt (BUG-08)
AssertionError: expected 'Reorder queued message: Rejected: Con…' not to contain '{'
Tests 1 failed | 23 skipped (24)
```
An exploratory probe on the unchanged code also showed the send error on
this path: `POST /queued-comments/interrupt` on the receipt queue with a
running native run returns `409 {"error":"This queue does not support
interruption"}`. The exact UI text that the tester saw was not
available.
Second commit (review follow-up), unchanged `findExistingDeferredWake`:
```
server: × queues every later message together after a declined connection (legacy run)
AssertionError: expected [ Array(1) ] to deeply equal [ …(2) ]
Tests 1 failed | 1 passed | 88 skipped (90)
```
With the change: `Tests 2 passed | 88 skipped (90)`.
**Green (with this change):**
```
pnpm --filter server exec vitest run src/__tests__/issue-queued-comments-routes.test.ts
Test Files 1 passed (1) Tests 90 passed (90)
server: heartbeat-comment-wake-batching + src/modules/wake-queue
Test Files 11 passed Tests 322 passed (322)
server: retry-scheduling, wake-diagnostics, question-response-delivery, comment-wake-batching, dot-runner, responsible-user-invariant, stale-queue-invalidation, queued-comments routes
Test Files 8 passed Tests 357 passed (357)
pnpm --filter ui exec vitest run src/components/task-chat/TaskChatQueuedMessages.test.tsx src/lib/issue-queued-comment-queue.test.ts
Test Files 2 passed (2) Tests 31 passed (31)
server: question-response-delivery, connection-intents-service, satisfied-connection-intents
Test Files 3 passed Tests 199 passed (199)
```
A first full run of the route file hit a 30s `beforeAll` timeout while
embedded Postgres started on a loaded machine. One new stopped-run case
was also flaky, because the agent could dispatch the new message before
the assertion. I fixed the flake: the test now occupies the agent on
another task (`maxConcurrentRuns: 1`), which is the existing pattern in
this file. I confirmed again that this test fails without the route fix.
Typecheck: `pnpm --filter @paperclipai/shared typecheck`, `pnpm --filter
@paperclipai/server typecheck`, and `pnpm --filter @paperclipai/ui
typecheck` pass. `pnpm check:token-gates`: all gates clean. I did not
run the full `pnpm test:run` or `pnpm build` locally. CI runs them.
## Risks
- Behavior change: when a receipt and a user message wait at the same
time, the composer now shows the message queue. The receipt is no longer
shown there until it is the only queued input. The receipt wake and its
delivery do not change. The resolved card in the thread still shows the
outcome.
- The first line of the steering body for connection receipts changes
from `Rejected: Connect Slack` to `Declined: Slack connection`. The JSON
receipt for the agent does not change.
- Out of scope (unchanged on master, reproduced without any receipt):
while a native run is running, each new message gets its own queued run,
and the queue shows only the first one. Messages that join a
`scheduled_retry` run's context also do not appear in the queue
projection.
- Overlap: the plan-approval queued-message fix (BUG-03) changes the
recovery sweep, not this code. Both fixes touch the same symptom area.
They do not edit the same functions.
## Model Used
- Claude Opus 5.5 (`claude-opus-5-5`), Anthropic, via Claude Code with
tool use (shell, browser inspection of staging, test execution).
## 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
- [ ] All Paperclip CI gates are green
- [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
|
||
|
|
cad3f8ae09 |
fix(task-chat): keep a yielded turn's streamed reply visible (#19324)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - The task chat shows each native runner turn while it streams, while it settles, and after it settles. > - During the onboarding interview, the agent streams a reply, posts a question card, and ends its turn as `yielded`. > - The live tail hides that reply when the card's pending interaction arrives. The settled turn also hides it, because a yielded turn never fills the final-response slot. > - The user sees the reply appear and then disappear. The reply is still in run history, so this is a rendering regression, not data loss. > - This pull request hides only the control-plane wait stub of a yielded turn. It keeps prose that the agent wrote for the user. > - The benefit is a stable conversation while responses stream and finish. ## Linked Issues or Issue Description **Bug description** During a hands-on onboarding test on staging, interview messages in the first-task chat appeared and then disappeared. **Steps to reproduce** 1. Start onboarding and pick "Interview me and propose a plan". 2. Watch the agent's turn. It streams a reply that describes the question card, for example "I've posted a question card on this task that asks four things...". 3. The question card appears. The reply disappears and does not come back after the run settles or after a reload. **Expected behavior** The conversation stays stable while responses stream and finish. **Related** Refs #18977. That PR changes server-side final-response selection for native standing conversations and leaves yielded waits and cards in control. This PR changes only how the task chat renders a yielded turn's authored reply. The two PRs do not overlap. **Evidence and root cause** - Persisted history is complete. The run's events contain the `agentMessage` `item.completed` with `channel: "final"` and the full reply text. The `run.result.accepted` result has `reportedWorkDisposition: "yielded"` with a `response_wake` continuation. Its summary is different from the reply. - The rendered thread does not contain that reply, also after "More messages" expands the history. - Classification: rendering/replacement, not persistence. Three gates drop the reply. `TaskChatThread` sets `suppressFinal` on the live tail when a pending interaction for that run exists. `TaskChatRunnerTurn` then clears the latched final. `paperclipRunnerFinalResponse` and the settled-turn path (`!sourceYielded`) return no final response for yielded turns. - Those gates were added on purpose so the mechanical "Waiting for <card>." prose that some providers echo does not show as an answer. This change keeps that behavior. ## What Changed - `transcript-adapter.ts`: add `isYieldedWaitStub`. A wait stub is text that echoes the yielded result summary, or a single-line "Waiting for ..." text. For a yielded turn, `paperclipRunnerFinalResponse` now returns the last authored final-channel message. It still returns nothing for a wait stub. New `yielded` and `waitSummary` options let callers state the yield from run metadata. - `TaskChatRunnerTurn.tsx`: `suppressFinal` hides only a wait stub. It no longer hides the agent's authored reply. A new `waitSummary` prop carries the accepted summary. - `TaskChatThread.tsx`: a settled yielded turn renders the authored reply once, in the last populated segment. The reply also counts as a native response for the "no user-facing response" marker and for progress de-duplication. The live tail passes the accepted summary to the runner turn. - Review round 1 (commit |
||
|
|
b929ad43de |
fix: keep dependency waits neutral and explain GitHub access failures (#19315)
## Thinking Path > - Paperclip manages agent work and shows users what can move it forward. > - Task status and tool approval cards describe different parts of that work. > - A queued dependency wait has no provider attempt to retry. > - GitHub can reject an approved action while other connection tools still work. > - These cases showed a false Retry banner and an unhelpful provider error. > - This pull request keeps dependency waits neutral and gives GitHub access failures a direct repair path. ## Linked Issues or Issue Description Related: #19268 preserves pending Retry preparation and current failure causes. **What happened?** A queued wake cancelled by the dependency gate appeared as a failed attempt with Retry. A GitHub MCP permission denial appeared as raw HTTP error text after an approved repository action. **Expected behavior** Keep the task's dependency state. Show GitHub access failures with a clear explanation and a link to the selected connection's Permissions page. Preserve actual failures, provider details, and approval gates. **Steps to reproduce** 1. Queue a wake, then leave its task dependent on unfinished work before dispatch. 2. Open the task after the dependency gate cancels that wake. 3. Separately approve a GitHub action whose MCP result contains `403 Resource not accessible by integration`. 4. Reopen the saved tool approval. ## What Changed - Recognize both queues' unstarted dependency-wait receipts in cancellation provenance and task projections. No dispatch or recovery gate changes. - Classify GitHub's specific permission error after MCP result normalization. Keep result validation, the raw diagnostic, and working tools available. - Apply the same display code to both historical GitHub error codes. Identify the provider from company-scoped connection metadata, including renamed apps, without rewriting stored decisions. - Show a token-based inline access card with **Manage GitHub access** and collapsed **Error details**. - Give agents trusted recovery steps after an approved GitHub action fails. Keep provider text in the untrusted result and prevent automatic replay. - Add regressions, a production-component Storybook case, and execution/connector documentation. ## Verification - Red before the fix: cancellation provenance, dependency-wait projection, the real queue cancellation, approved MCP failure classification, saved interaction projection, and the error card assertions failed at the expected behavior. - Green focused tests: queue cancellation, one ready-task executor, approval-before-dispatch, one failed GitHub request, connection reuse, retained provider diagnostics, saved interaction reads, task list/detail projection and redaction. - UI: 106 component tests passed. Token gates and Storybook catalog checks passed. - `node scripts/typecheck-low-memory.mjs`: passed. - Local source instance: verified a saved dependency wait stays neutral after reload; a saved GitHub error shows repair guidance, expands its original error, and opens the correct connection Permissions page. PostgreSQL and HTTP APIs were real. The GitHub denial was a controlled MCP fixture; no account or provider permission changed. - `pnpm build`: passed for all workspace packages, the Runner binary, server, CLI and UI. The server build and all server typecheck layers also passed after the review repair. - Additional safety checks passed for realistic repository arguments, active recovery, failed Retry preparation, and bounded provider diagnostics. - Review repair: 45 pure tests and 7 PostgreSQL cases passed. These cover both historical error codes, renamed apps, and company/provider/application identity boundaries. A second local browser check verified the renamed app, retained error detail, and correct Permissions destination. - Final review regressions: the dispatcher and metadata cases failed before the repair. Afterward, 25 focused cases and 59 projection/identity cases passed, including connection-key precedence. The native wait and app-only GitHub source also passed a local browser check. - The historical read adds at most one connection query per interaction read batch. It selects IDs and the provider key only and runs only for candidate permission failures. It adds no provider requests. - Full local `pnpm test:run` stopped at the chat suite's `afterAll` cleanup timeout. All 268 assertions in that group and the three prior chat groups passed. The failure is retained here; it is not counted as a full-suite pass. CI passed on `e8a692e1e2` after one workspace-startup rerun. Fresh CI is pending for the combined head. Its first workspace-a attempt timed out in the CLI company import/export test's child-server startup wait; 4,968 UI tests and 287 CLI tests passed in that job. The same shard passed on the preceding commit. The workspace shard passed on its one rerun. All other test, build and browser jobs passed. The [first failure](https://github.com/paperclipai/paperclip/actions/runs/42093823928/job/127478869941) is retained in the Actions history. Greptile reviewed the preceding head at 5/5. Fresh review is pending for the combined head. ## Risks The GitHub classifier matches the documented permission-denial phrase, not every 403. Rate limits, missing resources and other providers retain their existing error behavior. Historical normalization affects display only. A dependency cancellation needs an unstarted run and a supported queue receipt; current user gates, Retry preparation and recovery remain authoritative. No schema migration or credential changes. ## Model Used OpenAI GPT-6, through the Codex agent. The exact runtime model ID and context-window size are not exposed in this session. Used reasoning, repository tools, TypeScript, PostgreSQL, MCP fixtures and browser verification. The parallel agent-recovery commit records Anthropic Claude Opus 5.5 as co-author. ## 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 described the issue in-PR using the bug template - [x] I have not referenced internal or instance-local Paperclip issues or links - [x] My branch name describes the change - [x] I have run the focused tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation - [x] I have considered and documented risks - [ ] All Paperclip CI gates are green - [ ] Greptile is 5/5 with no open findings - [x] I will address reviewer comments before requesting merge --------- Co-authored-by: Paperclip <noreply@paperclip.ing> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
22281d4b3a |
feat(task-chat): approve harness-proposed plans (Codex plan mode, Claude ExitPlanMode) (#19291)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - Agents run through the native runner. Codex and Claude Code each have their own plan mode, and each produces a proposed-plan document. > - Paperclip already has a planning work mode, an issue `plan` document, and a `request_confirmation` approval gate for plans. > - These parts were not connected. The Codex proposed-plan item was transcript text only. The server path never put Codex into plan mode. Claude was never put into plan mode, and its ExitPlanMode plan was dropped. A planning run could close its task as done with no approval. > - This pull request turns a harness's own proposed plan into the issue's Plan document and the existing approval gate, for Codex and Claude. > - The benefit is that users approve or send back the agent's real plan from the task chat. Approve resumes the agent. Request changes sends the reason back to the agent. ## Linked Issues or Issue Description Refs #19252 **Subsystem affected** Native runner provider events (Codex and ACPX Claude), the runner Codex provider (Rust), server native plan synchronization, and the task chat UI. **Problem or motivation** Codex and Claude both produce a proposed-plan document in their native plan mode. Paperclip did not use it. In live tests on the server path, a Codex planning run was not in Codex plan mode, saved its own `implementation-plan` document, and marked the task done without approval. Claude planning runs were not in Claude plan mode, and the ExitPlanMode plan text never reached Paperclip. **Proposed solution** Add a canonical `plan.proposed` event for a harness's proposed plan. Put Codex and Claude into their native plan mode for planning runs. Save a completed proposal as the issue `plan` document with the existing `request_confirmation` gate. Agents can also propose a plan on a standard task; the work mode stays standard. **Alternatives considered** Reuse `plan.updated`. Its schema is the within-turn checklist and is not the durable Plan document, so a separate event keeps the two clear. Stronger prompt text without native plan mode. Live tests showed that the model kept its own document workflow. **Roadmap alignment** This reuses the issue plan document, planning work mode and approval gate that already exist. It adds one canonical provider event. ## What Changed - `packages/paperclip-runner/protocol/schemas/*`: add the `plan.proposed` event (`paperclip.plan.proposed.v1`: `proposalId`, `status`, `markdown` up to 60k characters, `source`). Regenerate the schema bundle, validators and manifest. - `packages/paperclip-runner/src/provider-events.ts`: map the Codex `plan` item and a `<proposed_plan>` block in a completed Codex message to `plan.proposed`. Add `claudePlanProposalEvent`. - `packages/paperclip-runner/runner/crates/runner-core/src/codex_provider.rs`: send Codex's native `collaborationMode: plan` on `turn/start` for a read-only (planning) Codex run. Before this change the server path never sent it. - `runner-core/src/acpx_event_payload.rs`: admit `plan.proposed` as ACPX rich display activity. - `drivers/acpx/codex-runtime-adapter.ts`: set Claude Code to native plan mode for a read-only run. Capture Claude's ExitPlanMode plan from its permission request, record it, and decline the native "Ready to code?" prompt. - `drivers/acpx/codex-acpx-driver.ts`, `cli/acpx-runtime-sidecar.ts`: emit the captured proposal as a rich event. Complete that turn instead of reporting it as cancelled. - `backends/codex-native-backend.ts`: per-harness plan-mode instructions, and a short opt-in hint for Claude on standard tasks. - `server/src/services/native-runtime/native-session-executor.ts`: synchronize a completed `plan.proposed` into the `plan` document and a `request_confirmation` in planning and standard mode. Do not change the issue status during the run (that revoked the run's lease). The run finalizer turns the pending confirmation into the review wait. - `server/src/services/heartbeat-run-summary.ts`: keep a `<proposed_plan>` block out of the posted reply. - UI: new `plan_proposal` provider family. The task chat shows a live "Writing plan" card while a proposal streams and a one-line record when it completes. Resolved plan reviews keep a receipt ("Approved Plan v1", "Requested changes to Plan v1: reason"). Plan previews skip section headings. - Storybook: `Tasks and conversations/.../Task chat/Proposed plan approval` shows the journey. - `doc/SPEC-implementation.md`: describe harness-proposed plan approval. ## Verification - `cargo test -p paperclip-runner-core --lib` (new: `read_only_codex_turns_use_native_plan_collaboration_mode`) - `cd packages/paperclip-runner && npx vitest run src/provider-events.test.ts src/drivers/acpx/codex-runtime-adapter.test.ts` - `cd server && npx vitest run src/__tests__/native-plan-proposal-sync.test.ts src/__tests__/heartbeat-run-summary.test.ts` - `cd ui && npx vitest run src/components/transcript/native-run-events.test.ts src/components/task-chat` - Live test on a local worktree instance with real harnesses: - Codex (`gpt-5.6-sol`), planning task: Codex asked one question, then produced a native plan item. The task showed Plan v1 with Approve plan / Request changes and moved to in review. Approve changed the work mode to standard. Codex then implemented the plan and its tests passed. - Codex, Request changes with a reason: Codex woke in planning mode and produced Plan v2 that includes the change. - Claude (`claude-opus-5-5`), planning task: Claude was in plan mode. ExitPlanMode became Plan v1 and the turn completed. Approve resumed Claude in standard mode, and Claude implemented the plan. - Claude, standard task that asks for a plan first: Claude stopped before code changes and asked for plan approval. The work mode stayed standard. - Storybook: open `Proposed plan approval` and check each stage. ## Risks - Codex planning runs now really use Codex plan mode on the server path. Codex can ask a clarifying question before it proposes. This matches Codex plan mode. - Claude planning runs now use Claude plan mode. A declined ExitPlanMode ends the Claude turn; the runner reports it as completed. Claude's tool row for that request records a rejection from Claude's side. - Codex does not stream the proposed plan on the server path yet, so the live card shows a placeholder until the plan completes. - A `<proposed_plan>` block in any completed Codex message on a standard task now asks for approval. This is the documented opt-in path. > For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and discuss it in `#dev` before opening the PR. Feature PRs that overlap with planned core work may need to be redirected — check the roadmap first. See `CONTRIBUTING.md`. ## Model Used - Anthropic Claude Opus 5.5 (`claude-opus-5-5`), via Claude Code with tool use (shell, file edits, browser). Long context. No extended thinking mode was used. ## 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 - [ ] All Paperclip CI gates are green - [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [ ] I will address all Greptile and reviewer comments before requesting merge 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
1b0f78100d |
fix(access): return membershipRole in the company user directory (#15183)
## Thinking Path
> - Paperclip is the open source app people use to manage AI agents for
work.
> - Agents often check a human approval. The check must confirm the role
of the approving user in the company.
> - An agent can read the company user directory. The directory removes
the membership role from the server record.
> - The admin member list requires `users:manage_permissions`. An
approval check must not need that permission.
> - This pull request returns `membershipRole` in the existing user
directory and keeps all access limits.
> - The benefit is that agents can verify an approver's role without
admin permissions.
## Linked Issues or Issue Description
**What happened?**
`GET /api/companies/{companyId}/user-directory` returns active users
without `membershipRole`. An agent that checks the authority of an
approving user cannot tell an `owner` from other roles. `/members`
requires `users:manage_permissions`.
**Expected behavior**
The directory returns the exact `membershipRole` from
`companyMemberships`. A missing role stays `null`. Reading this field
does not require admin permissions. Member management keeps its current
limits.
**Steps to reproduce**
1. Use a company with an active `owner` user and an active user without
a role.
2. Call `/user-directory` with an agent key.
3. Before this change, neither record has `membershipRole`. After this
change, the field is `owner` and `null`.
4. The same agent still cannot read `/members` or change a member.
## What Changed
- Add `membershipRole` to the select and result of
`loadCompanyUserDirectory`.
- Test the exact `owner`/`null` values, agent read access, denied admin
read and change, denied other company, and denied unauthenticated
request.
- Keep the existing `assertCompanyAccess` and the company, user type,
and active filters.
- The client type includes a nullable `membershipRole`. The management
test rejects only `users:manage_permissions` and checks the exact calls.
The first review findings are fixed in
|
||
|
|
d807887534 |
fix(ui): use one status glyph mapping for every task view (#19329)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - Task status is the main signal on every task surface: sidebar rows, the task header, the status menu, lists, the inbox, pills and chat cards. > - One task state rendered different status icons in different views. A blocked task that waits on an active sub-task showed the blue "in queue" glyph in the task header. The status menu, the chat chip and the sidebar rows showed the red "Blocked" glyph for the same task. > - The cause: each view passed its own subset of the presentation fields to `StatusIcon`. Many views dropped `blockerAttention` and some dropped `externalConversationState`. The status menu rendered its current row from the bare status. The summaries API did not return `blockerAttention`, so the recent-task sidebar could not know the state. > - This pull request puts the state-to-glyph/label mapping in one resolver and makes every task view pass all of its fields. > - The benefit is that the same state uses the same icon and label everywhere. ## Linked Issues or Issue Description No public issue. Found in a hands-on onboarding test on a staging cloud workspace. **What happened?** The sidebar and the task pane/status menu showed different status icons for the same state. On the test task (blocked, waiting on an active sub-task), the task header and the status button showed the blue "in queue" glyph. The selected "Blocked" row in the status menu showed the red blocked glyph. The coordinator sidebar "Recents" and project rows also showed the red blocked glyph, and the chat "Subtask created" chip showed a red "Blocked" chip. **Expected behavior** The same underlying state uses the same icon and label everywhere. **Steps to reproduce** 1. Create a task with a sub-task. Block the parent on the sub-task, and let the sub-task's agent run (the parent is "blocked, covered"). 2. Open the parent task. The header shows the blue "in queue" glyph. 3. Open the status menu. The current "Blocked" row shows the red glyph. 4. With the coordinator sidebar on, look at the task in Recents or in its expanded project. It shows the red glyph. **Paperclip version or commit** `master` at |
||
|
|
1c165e9f1e |
fix(ui): bound the queued-message strip so it scrolls instead of covering the conversation (#19321)
## Thinking Path
> - Paperclip is the open source app people use to manage AI agents for
work.
> - In task chat, a user can queue messages while an agent run is
active. The queued messages show in a strip above the composer, with
Steer, Interrupt, Discard and Edit actions.
> - An onboarding test on staging reported that the steering strip
clipped and covered nearby UI.
> - The strip adds one 44px row for each queued message and has no
height limit. With several queued messages it takes most of the thread.
In the Coordinator layout the dock is absolutely positioned at the
bottom of the thread, so the strip grows up over the conversation.
> - This pull request puts the rows in a bounded list that scrolls. The
status and error lines stay below the list.
> - The benefit is that the conversation stays readable at desktop and
narrow widths, and every queued message stays reachable.
## Linked Issues or Issue Description
**What happened?**
With several queued messages, the queued/steering strip above the task
composer grew without a limit. It covered the transcript and nearby
components. At a 1024x600 window, 8 queued messages made the strip 353px
tall in a 555px thread.
**Expected behavior**
The strip stays readable and inside the available space at normal and
narrow widths. Extra queued messages scroll inside the strip.
**Steps to reproduce**
1. Open a task with an active run in the Coordinator workspace.
2. Queue 6 or more messages.
3. See that the strip covers most of the conversation.
**Paperclip version or commit**
`master` at
|
||
|
|
5d9f6c56c2 |
fix(ui): stop calling setup-draft agents "paused manually" (#19322)
## Thinking Path
> - Paperclip is the open source app people use to manage AI agents for
work
> - The task chat shows a notice when the assigned agent is paused
> - A new agent is stored as `status: "paused"` with `pauseReason:
"setup"` while its setup runs
> - The notice treated every pause reason except budget, import and
system as a manual pause
> - So a user who just created their first agent saw "It was paused
manually." and a "Resume agent" button
> - This pull request shows the real setup state and the correct
recovery action
> - The benefit is that new users do not think that they paused their
agent by mistake
## Linked Issues or Issue Description
**What happened?**
During an onboarding test on a staging cloud workspace, the first agent
showed a "paused manually" warning right after it was created. Work
continued later. The agent activity log shows `agent.identity.created`,
several `agent.updated` events while setup ran, then
`agent.hire_created`. It shows no pause or resume event. The agent was
never paused by an operator. It was a setup draft (`pauseReason:
"setup"`).
**Steps to reproduce**
1. Create a first agent in the onboarding flow.
2. Open the task that is assigned to the agent while the agent setup is
not finished.
3. See "<agent> is paused. New runs will not start until the agent is
resumed. It was paused manually." with a "Resume agent" button.
**Expected behavior**
The notice shows that the agent is still being set up. When the draft
waits for the user, the notice links to the agent page to finish setup.
A real pause keeps a clear "Resume agent" action.
## What Changed
- `IssueAssigneePausedNotice` now handles `pauseReason: "setup"`
separately. It shows "<agent> is still being set up." with an info tone.
- While the lifecycle state is `preparing`, `verifying` or `pausing`,
the notice says that runs start automatically when setup finishes. It
shows no action.
- When the setup draft is parked (`lifecycleState: "paused"`), the
notice shows a "Finish setup" link to the agent page, where the existing
"Finish setup" button lives.
- The notice never offers "Resume agent" for a setup draft.
- `company_archived` pauses now say "It was paused because its company
is archived." They offer no resume, because restoring the company
resumes these agents.
- Only `pauseReason: "manual"` says "It was paused manually." An unknown
or null reason shows no reason sentence.
- Added tests for the setup-draft states and the company-archive pause.
## Verification
Red, on current `master` code with the new tests (`cd ui && npx vitest
run src/components/IssueChatThread.test.tsx -t
IssueAssigneePausedNotice`):
```
× shows a setup-draft agent (preparing) as still being set up, not manually paused 35ms
× shows a setup-draft agent (paused) as still being set up, not manually paused 11ms
× explains a company-archive pause instead of calling it manual 12ms
AssertionError: expected 'CEO is paused.New runs will not start…' not to contain 'paused manually'
Tests 3 failed | 5 passed | 100 skipped (108)
```
Green, same command after the fix:
```
Tests 8 passed | 100 skipped (108)
```
Neighbouring suites (`npx vitest run
src/components/IssueChatThread.test.tsx
src/components/TaskChatThread.test.tsx`):
```
Test Files 2 passed (2)
Tests 471 passed | 1 skipped (472)
```
- `node scripts/check-token-gates.mjs`: all gates clean.
- `tsc --noEmit -p ui`: no errors in the changed files. The local run
shows errors only from unbuilt workspace packages
(`@paperclipai/plugin-sdk/ui` dist and the generated storybook feature
map). CI builds these packages.
- I did not run the full `pnpm -r typecheck` / `pnpm test:run` / `pnpm
build`. CI runs them.
## Risks
- Low risk. The change is UI-only and limited to one notice component.
- A null or unknown pause reason no longer says "manually". It still
says that the agent is paused and still offers "Resume agent".
## Model Used
- Claude Opus 5.5 (`claude-opus-5-5`), Anthropic, via Claude Code with
tool use (shell, file edits, browser inspection of the staging
workspace).
## 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
- [ ] All Paperclip CI gates are green
- [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
|
||
|
|
2575b941d0 |
feat(task-chat): show hook and auto-review decisions as governance rows (#19266)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - Agents run on harnesses such as Codex and Claude, and the task chat shows what each run did > - Harnesses make automatic decisions: hooks block or allow tool calls, and Codex auto-review approves or denies actions > - Today Paperclip drops these decisions or shows them as generic rows. Codex `safety.review.*` always says `decision: "unknown"`, the native Rust runner drops `hook/*` and `item/autoApprovalReview/*`, and claude-agent-acp drops Claude hook messages > - An operator cannot see why an agent changed course or which action ran without a person's approval. This conflicts with Paperclip's approval-gate model > - This pull request records each hook and review decision with its reason and shows it as a small governance row in the task chat > - The benefit is that automatic decisions become auditable, and a blocked action explains itself without opening run logs ## Linked Issues or Issue Description Refs #19252 (precedent: canonical `plan.updated` events rendered as a task-chat card). Builds on #19259 (ACP `_meta` passthrough from ACPX), now merged. **Subsystem affected** Runner provider events (Rust native Codex normalizer, TS drivers, ACPX sidecar), the claude-agent-acp patch, the PRP provider-event schema, and the task chat activity UI. **Problem or motivation** Hook and auto-review outcomes reach Paperclip but are lost or flattened. Codex reviews always record an unknown decision. Native Codex runs drop hook and review notifications in the Rust normalizer. Claude hook messages never leave the adapter. Codex reuses one `run.id` for every call of a hook, and the id contains a host path. **Proposed solution** Map the real outcome, decision, action, risk and reason into additive optional fields on `paperclip.hook.v1` and `paperclip.safety.review.v1`. Forward Claude SDK hook messages. Render small grey rows: a stopped action is tinted and shows its reason, an approved review folds into the command it approved as an "auto-approved" mark, and routine hook passes stay out of activity summaries. **Alternatives considered** Separate rows for every approval. This duplicated each approved command, so approvals fold into the command row instead. ## What Changed - Runner (Rust): new `governance_events.rs`. `normalize_codex_notification` now maps `hook/started|completed` and `item/autoApprovalReview/started|completed`. Each hook call gets its own id (a digest of the run id and start time), so no host path is stored. - Runner (TS): new `governance-events.ts` with the same mapping for the TS Codex driver, and the Claude hook mapping. The ACPX sidecar publishes Claude hook updates as schema-validated `hook.*` rich events. - claude-agent-acp patch: turns on `includeHookEvents` and forwards `hook_started` / `hook_response` on `session_info_update._meta.claudeCode.hook`, with bounded output. - Protocol: additive optional fields. Hook records get `outcome`, `message`, `source` and `toolName`, and the `blocked` and `stopped` statuses. Review records get `actionKind`, `action`, `riskLevel`, `userConsent` (the reviewer's user-authorization level; keys that end in "authorization" are redacted as secrets), `rationale` and `decidedBy`, and the `timed_out` and `aborted` decisions. Regenerated the manifest and validators. - Fixed: the hook `blocking` flag read `executionMode === "blocking"`, but Codex sends `sync` / `async`. - UI: `native-run-events` keeps the full hook and review payloads. `governance-presentation.ts` writes the row labels. `fold-auto-reviews.ts` attaches an approved review to its command row. The rows show the tint, the reason line and the "auto-approved" mark. Activity summaries lead with a block or denial. - Storybook: "Task chat / Governance rows" shows every outcome, a Codex run, a Claude run and the live line. - Docs: added a governance activity section to `packages/paperclip-runner/docs/protocol-compatibility.md`. ## Verification - `pnpm --filter @paperclipai/paperclip-runner exec vitest run src/governance-events.test.ts src/provider-events.test.ts src/drivers/codex src/drivers/acpx src/cli`. 2305 tests pass. This includes a replay of real Codex 0.160 notifications from a session with hooks and auto-review (`test-fixtures/governance/codex-0.160-hooks-auto-review.json`, sanitized). - `cargo test --release -p paperclip-runner-core`. The full suite passes, and `governance_events::tests` replays the same fixture. - `cd ui && npx vitest run`. 11,047 tests pass. - `node scripts/typecheck-low-memory.mjs`, `pnpm check:token-gates`, and the runner contract checks (`check:protocol-manifest`, `check:protocol-types`, `check:capability-contract`, `check:protocol-coverage`, replay goldens, contract fingerprints) pass. - Live test on a local isolated instance. A Codex agent and a Claude agent each used a preconfigured home with a PreToolUse hook that blocks edits to `0001_init.sql`, plus UserPromptSubmit and PostToolUse hooks. Both runs showed "PreToolUse hook blocked a tool call" (Codex) or "PreToolUse hook blocked Bash" (Claude), with the hook's message. They also showed "UserPromptSubmit hook added context", and the group summary started with the block. - Auto-review cannot run in Paperclip today, because the native Codex runner only allows `approvalPolicy: never`. The review mapping and the approval fold are proven against real Codex 0.160 app-server output (fixture above) and in Storybook. ## Risks - Low risk to execution. These records are display-only and carry no authority. All new schema fields are optional, so older records stay valid and older UIs ignore the new fields. - The `auto-approved` fold depends on `targetItemId` matching the command's execution id. Real Codex 0.160 data confirms that it matches. When there is no match, the review stays as its own row. - In Paperclip's isolated homes, hooks do not run, because the runner never copies hooks into an isolated home. Rows appear only for agents with a preconfigured home, or with future managed hooks. - The claude-agent-acp patch changes. The ACPX profile check still passes, because the patch is Paperclip's ACPX layer and not the upstream release. ## Model Used - Claude Opus 5.5 (`claude-opus-5-5`) in Claude Code, with tool use (shell, browser and file editing) and extended reasoning. ## 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 - [ ] All Paperclip CI gates are green - [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [ ] I will address all Greptile and reviewer comments before requesting merge 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
dd889e6a0b |
feat: show the assignee's provider usage limit in task properties (#19270)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - Agents run on the native Runner through the Codex app-server and the Claude ACP harness > - Both harnesses report the provider account's rate-limit windows: Codex sends `account/rateLimits/updated`, and Claude sends its SDK `rate_limit_event` as `usage_update._meta["_claude/rateLimit"]` > - Paperclip dropped both signals, so an operator could not see that an agent was near or past its provider limit > - This pull request normalizes both signals into one account-scoped snapshot, keeps the latest snapshot per agent, and shows it as one "Usage limit" line in the task properties pane > - The benefit is that an operator sees "5h 78% · resets 15:40" (amber above 80%, "Limited until …" when the provider refuses work, "using credits" when a used-up window falls back to credits) next to the assignee, and can click it for every window ## Linked Issues or Issue Description Refs #19246 Refs #19259 **Is your feature request related to a problem?** Codex and Claude report provider rate-limit windows during a run. Paperclip dropped them: the Codex notification fell through the Rust normalizer with no branch, and ACPX dropped Claude's `_meta`. Operators could not see how close an agent was to its provider limit. **Describe the solution you'd like** Store the latest reported windows per agent and show one compact line in the task properties pane, with a popover that lists every window. **Describe alternatives you've considered** A full gauge in the agent list and the run header. A design review chose one property line with a details popover instead. ## What Changed - Runner (Rust, the runnerd path): new `provider_rate_limits.rs`. Codex `account/rateLimits/updated` becomes a `provider.notice.recorded` event (category `provider.rate_limits`, scope `account`). `CodexProviderState` merges sparse updates and emits a notice only when the windows change. ACPX `usage_update` with a sanitized `rateLimit` field also emits the notice. - Runner (sidecar): `acpx-runtime-sidecar.ts` forwards only `status`, `rateLimitType`, `utilization` and `resetsAt` from `_meta["_claude/rateLimit"]`. This needs the ACPX `_meta` passthrough from #19259. Until that merges, Claude emits nothing. - Runner (TypeScript in-process drivers): the same mapping in `codex-session-notifications.ts` and `codex-acpx-driver.ts` through `drivers/provider-rate-limits.ts`. - Shared: `provider-rate-limits.ts` holds the snapshot type, the parser, the merge, and `summarizeProviderRateLimits` (fullest current window, expiry by reset time, limited versus using credits). - Server: `agent-provider-rate-limits.ts` merges each notice into `agent_runtime_state.state_json.providerRateLimits`, scoped by company and agent. A session reset keeps the snapshot. No migration. - UI: `AgentRateLimitPropertyValue` adds a "Usage limit" row under the assignee in `IssueProperties`. Transcripts treat the notice as run-log only. A run status event refreshes the assignee's runtime state. - Storybook: `Tasks and conversations/Task creation and lifecycle/Usage limit property`. - Docs: `doc/run-log-events.md` describes the notice and its storage. ## Verification - `cd packages/paperclip-runner/runner && cargo test -p paperclip-runner-core --lib rate_limit` and `--test acpx_provider_events`: sparse Codex merge, dedupe, reached window, checkpoint round trip, Claude utilization and rejection, notice shape. - `cd packages/paperclip-runner && npx vitest run src/drivers/provider-rate-limits.test.ts src/drivers/codex` - `cd packages/shared && npx vitest run src/provider-rate-limits.test.ts`: summary, expiry, limited, using credits, parse and merge. - `cd server && npx vitest run src/__tests__/agent-provider-rate-limits.test.ts`: create and merge, out-of-order snapshot, company isolation, unrelated notices, session reset keeps the snapshot. - `cd ui && npx vitest run src/components/transcript src/components/issue-properties src/context/LiveUpdatesProvider` - `pnpm -r typecheck` and `pnpm check:token-gates` pass. - Live test on a local worktree instance: a native Codex agent on a ChatGPT subscription login ran a real task. The runner recorded one `provider.rate_limits` notice. The server stored it. The task properties pane showed "7d 100% · using credits" (this account's weekly window was used up and had credits, and the run succeeded). The transcript showed no extra row. - Not verified live: Claude. The local Claude CLI was not signed in, and the Claude path also needs #19259. The Rust and sidecar paths have tests. - Not run locally: the full `pnpm test:run` and `pnpm build`. CI runs them. ## Risks - Low risk. The snapshot is display data. It does not hold or start work. The existing provider-limit wait (#19246) still reads typed run failures. - Codex can send a rate-limit update often. The runner emits a notice only when the windows change, so run-log growth stays small. - With API-key auth, the harnesses report no windows, so no row appears. This is the intended result. - `CodexProviderState` gains two optional serde fields with defaults, so older checkpoints still load. > For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and discuss it in `#dev` before opening the PR. Feature PRs that overlap with planned core work may need to be redirected — check the roadmap first. See `CONTRIBUTING.md`. ## Model Used - Claude Opus 5.5 (`claude-opus-5-5`), Anthropic, through Claude Code with tool use (shell, file edits, browser) and extended reasoning. ## 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 - [ ] All Paperclip CI gates are green - [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
86a9d3ec6c |
feat(task-chat): tool rows that say what ran and how it went (#19265)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - The task chat shows each tool call an agent makes as a short activity row. > - Real Claude runs showed Bash rows named "Terminal" with no command and Write rows stuck at "Preparing file…". No row showed an exit code or a duration, and a tool refused by policy looked like any other failure. > - Codex already reported exit codes, durations and parsed command actions, but the UI dropped them, and every Codex read looked like a shell command. > - This pull request gives both harnesses one row grammar: a verb icon, the real subject, an exit chip and a duration. > - The benefit is that a reviewer can see what ran and how it went without opening each row. ## Linked Issues or Issue Description Refs #19259 (this branch includes its `_meta` passthrough commit; merge #19259 first or together). **Problem or motivation** Claude tool rows hide what ran: the runner keeps the first ACP title ("Terminal", "Preparing file…") and drops the refined one. `exitCode` and `durationMs` are null on every Claude tool event. The UI ignores `tool.execution.progressed`, `exitCode` and `durationMs` for every harness. **Proposed solution** Read real tool facts in the runner (Claude `_meta.claudeCode`, raw input and result text; Codex `commandActions`), carry them in the canonical tool event, and render one row grammar in the task chat. **Alternatives considered** Enable Claude's `terminal_output` client capability to get `terminal_exit`. That changes how command output arrives, and Claude's own exit code is derived from the error flag anyway, so this PR reads the error flag and the "Exit code N" text instead. ## What Changed - **Runner (TS):** `createAcpxToolEventNormalizer` keeps the latest concrete title instead of the first placeholder. It merges tool facts across the lifecycle and measures the duration. New `acpxToolDetailFromRuntimeEvent` reads the native tool name, the command or pattern, the description, the exit code and a "Permission denied" reason. Exit 0 is inferred only for Claude `Bash`, where a non-zero exit is always a failed result. - **ACPX sidecar:** reads the facts before `rawInput` is dropped and sends a bounded `toolDetail`. A file path argument becomes an attested workspace-relative location. - **runner-core (Rust):** validates `toolDetail`. `normalize_acpx_tool_call` uses the native name, exit code, duration, subject, description and blocked reason. Codex `commandExecution` gets its operation, a single-file target and a subject from `commandActions`. The shell wrapper is removed, and a single search reads as `"TODO" in src`. - **Protocol:** `toolExecution` gains the optional fields `subject`, `description` and `blockedReason`. Generated validators and the manifest are regenerated. - **UI:** - `nativeRunEventsToTranscript` handles `tool.execution.progressed` and passes a canonical `detail` on `tool_call` entries. - The task-chat row shows `$ command`, a path or a pattern, a red `exit N` chip (exit 0 only for commands) and a duration (0 is hidden). - Three or more consecutive reads fold into "Read N files a, b, c +1". - A refused tool shows "Blocked" with its reason. - **Storybook:** `Tasks/Tool rows` compares the data recorded today with the new runner data for Claude and Codex. ## Verification - `cd packages/paperclip-runner && npx vitest run src/provider-events.test.ts src/cli src/drivers/acpx` (1,957 pass) - `cd packages/paperclip-runner/runner && cargo test -p paperclip-runner-core --lib provider_events` - `cd ui && npx vitest run src/components/transcript src/components/task-chat` (973 pass) - `pnpm check:token-gates`, `pnpm --filter paperclip-runner build` (includes the protocol coverage and replay-golden checks) - Live runs on a local instance with real harnesses: - Codex (gpt-5.6-sol): the rows read `$ node --test` with `exit 1` and then `exit 0`, plus real durations. A three-file `sed` shows as one command and does not claim a single file. - Claude (claude-sonnet-5-5 through ACPX): the rows show `Bash` and `Edit` instead of "Terminal" and "Preparing file…". Commands show their real text, `exit 0` and durations, and edits show `Edited temp.js`. - Not seen live: a real Claude `Write`, a folded read run and a Claude policy denial. Unit and Rust tests cover them. ## Risks - The tool-execution schema gains only optional fields, so older events stay valid. Older runs keep rendering with what they recorded. - Commands now cross the sidecar boundary as `subject` (bounded to 4,000 characters). Codex already recorded commands as the tool name, and server redaction still applies. - The tool lifecycle now keeps the latest concrete title. A provider that retitles a call to something less useful would show the newer title. ## Model Used - Claude Opus 5.5 (`claude-opus-5-5`) in Claude Code, with tool use, code execution and browser automation. ## 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 - [ ] All Paperclip CI gates are green - [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [ ] I will address all Greptile and reviewer comments before requesting merge 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
1eff07f29e |
feat(task-chat): show Claude subagents as a collapsible tree in the runner turn (#19264)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - The task chat shows what an agent does in a run. The Paperclip Runner sends this activity as canonical provider events. > - Claude runs subagents through its Agent (Task) tool. A run that delegates showed a confusing burst of unrelated tool calls. > - The subagent data was already sent, but it was lost: ACPX dropped `_meta`, the hardened sidecar dropped `rawInput`, and async subagents report "launched" as the tool result. > - This pull request maps each Agent call to a canonical `delegation` event, links each child tool to its subagent, and shows subagents as a collapsible card or tree. > - The benefit is that operators can see what each subagent was asked, what it is doing now, which tools it used, and what it returned. ## Linked Issues or Issue Description Refs #19252 (the docked plan card used the same canonical-event pattern) Refs #19259 (ACPX `_meta` passthrough, merged). This PR builds on it. **What happened?** When a Claude agent used its Agent tool, the task chat showed one generic "Task" row and then the subagents' tool calls as flat rows in the parent turn. The subagent type, prompt, progress and result were not visible. **Expected behavior** Each subagent shows as its own card with its type, description, prompt, live progress summary, nested tool rows and result. Subagents that start together show as one tree with status dots. **Steps to reproduce** 1. Assign a Claude (Paperclip Runner, ACPX) agent a task that asks it to launch three Explore subagents in parallel. 2. Open the task while the run is live. 3. Before this change, the subagents' tool calls appear flat in the parent turn. ## What Changed - **claude-agent-acp patch:** Under the isolated runner context, the patch turns on the SDK option `agentProgressSummaries`. It forwards each subagent's `task_progress` summary and its terminal state and summary onto the spawning tool call as `_meta.claudeCode.subagentProgress` and `subagentState`. Native subagent sessions stay off, because ACPX cannot follow child ACP sessions. - **Runner:** The new file `claude-subagent-lineage.ts` tracks each Agent/Task call across ACP update deltas. It maps the call to `delegation.started|updated|completed` events and stamps child tools with `parentItemId`. An async subagent stays running after its "Async agent launched" result until its own state settles. - **Sidecar path:** `acpx-runtime-sidecar.ts` reads the lineage before it drops `_meta` and `rawInput`. Delegations go out as schema-checked rich events. Child tools carry `parentToolCallId`, which Rust (`acpx_event_payload.rs`, `provider_events.rs`) maps to `parentItemId`. - **Contracts:** The provider-event schema adds optional `prompt` and `result` to delegation children and optional `parentItemId` to tool executions. The protocol modules are regenerated. ACPX Claude now advertises the `delegation` event family. - **UI:** `native-run-events.ts` keeps delegation payloads and the tool parent link. `buildTurnTimelineRows` groups adjacent delegations into a new `subagent_group` row, nests child tool rows (plain and provider-activity shapes), and hides the spawning call's own tool row. The new `TaskChatSubagentCard.tsx` renders the card and tree. A new size token caps the result height. - **Storybook:** The new story `Tasks and conversations/…/Task chat/Subagents` has 7 states. ## Verification - `pnpm --filter @paperclipai/paperclip-runner exec vitest run src/cli src/drivers/acpx src/provider-events.test.ts src/claude-subagent-lineage.test.ts src/protocol` (2069 passed) - `cargo test --release --locked -p paperclip-runner-core --lib` in `packages/paperclip-runner/runner` (488 passed, including the new parent-link test) - `node --test test/protocol-contract.test.mjs test/acpx-sidecar-contract.test.mjs test/acpx-codex-package-contract.test.mjs test/acpx-rich-extensions-package-contract.test.mjs` (48 passed) - `pnpm --filter @paperclipai/ui exec vitest run src/components/task-chat src/components/transcript`, including the new `subagent-timeline.test.ts` - `check:protocol-types`, `check:protocol-manifest`, `check:acpx-profiles` and `pnpm check:token-gates` pass. - **Live test:** A local test-drive instance ran a Claude Opus 5.5 agent on the Paperclip Runner (hardened sidecar path). The agent ran real tasks that launched three parallel Explore subagents. The live view showed "Running 3 subagents · 2 done" with a progress summary. The settled view showed "Ran 3 subagents", each with its prompt, nested tools and its own result text. ## Risks - `agentProgressSummaries` makes Claude Code generate a short progress summary for each running subagent about every 30 seconds. This adds a small model cost to runs that delegate. - The adapter patch reads `task_notification` and terminal `task_updated` messages. A future claude-agent-acp version can change these. The patch hunks then fail to apply, and the dependency bump must update them. - If a delegation event is lost, child tools stay at the top level as before. Nothing is hidden without a matching delegation. - Codex is not changed. Codex subagents need `multi_agent`, which Paperclip keeps off on purpose. Changing that is a separate policy decision. ## Model Used - Claude Opus 5.5 (`claude-opus-5-5`) in Claude Code, with tool use (shell, file edits, browser automation). It did the investigation, implementation, tests and live test. ## 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 - [ ] All Paperclip CI gates are green - [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
d361f92071 |
feat(task-chat): show harness status notices as chips, out of the answer (#19267)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - Agents run through the native runner. The runner turns harness events from Codex and Claude into canonical provider events, and the task chat shows them. > - Harnesses report their own lifecycle: context compaction, retries, model fallback, and warnings. Paperclip lost or mangled these reports. > - Claude (claude-agent-acp 0.73) sends compaction, model-fallback and warning banners as ordinary message text, so "Compacting..." ended up inside the agent's answer and the issue comment. > - Codex sends `error` with the text in `error.message` and a `willRetry` flag. Paperclip read `params.message`, so every Codex error said "Provider notice", and every retry looked fatal. > - This pull request keeps these reports out of the answer and shows them as small status chips between the turn's activity. > - The benefit is that users can see why an agent paused, retried or forgot earlier context, and the answer text stays clean. ## Linked Issues or Issue Description **Subsystem affected** Native runner provider-event mapping (TypeScript driver, ACPX sidecar and Rust runner-core) and the task chat transcript. **Problem or motivation** Claude status banners are mixed into assistant answer text. Codex error notices lose their message and their retry state. The task chat hid all of these notices, and settled turns stripped every provider notice. **Proposed solution** Classify Claude banners as provider notices at the ACPX boundary. Map Codex `TurnError` fields and `willRetry` correctly. Render status notices as inline chips. A retry chip fades after later provider work. A final error shows the real provider message. **Alternatives considered** Patch claude-agent-acp to tag banners in `_meta`. ACPX keeps only `origin`, `kind` and `source` from `_meta`, and other sessions own the ACPX `_meta` passthrough work. Banner chunks already have no `messageId`, and model output always has one, so the classification needs no adapter patch. **Roadmap alignment** This makes existing harness signals visible. It adds no new protocol schema. It uses the existing `paperclip.provider.notice.v1` `category` and `details` fields. ## What Changed - Codex `error` notifications (TypeScript `provider-events.ts` and Rust `runner-core/src/provider_events.rs`): read `error.message`, map `willRetry: true` to a recoverable `provider_retry` notice, keep category `error` for a final error, and add the `CodexErrorInfo` kind, HTTP status, and the "Reconnecting... n/m" attempt count as notice details. Retries in one turn share one notice id. - New `claude-status-banners.ts`: classifies the claude-agent-acp compaction, model-fallback and SDK informational banners. A chunk must have no `messageId` and match a known banner exactly. - ACPX sidecar and the TypeScript ACPX driver emit these banners as `provider_notice` events instead of answer text. Compaction start and end share one notice key and carry a `Phase` detail. - Rust runner-core accepts an optional `noticeKey` and bounded `details` on ACPX `provider_notice` events. - UI: new `TaskChatStatusNotice` chip and `status-notice-presentation.ts`. Status notices become top-level timeline rows, render as chips wherever protocol cards render, and stay visible in settled (historical) turns. Generic warnings stay hidden as before. - New tokens `--tc-status-notice-warning-*` in `ui/src/index.css`. - Storybook story `Tasks and conversations/.../Task chat/Status notices` with eight states. - `doc/run-log-events.md`: describes the status notice categories. ## Verification - `pnpm --filter @paperclipai/ui exec vitest run src/components/task-chat src/components/transcript` - `pnpm --filter @paperclipai/paperclip-runner exec vitest run src/provider-events.test.ts src/drivers/acpx/claude-status-banners.test.ts src/drivers/acpx/codex-acpx-driver.test.ts src/cli/acpx-runtime-sidecar.test.ts` - `cargo test -p paperclip-runner-core --lib provider_events` and `--test acpx_provider_events` - `pnpm check:token-gates` - Storybook: open `product-task-chat-status-notices--all-states-gallery`. - Live test-drive on an isolated worktree instance: - Codex (gpt-5.6-sol, app-server 0.160): a local pass-through proxy in front of the real OpenAI API cut the first two response streams. Codex ran its own retries. The chat showed an amber "Reconnecting" chip live, then "Recovered after retry" once work continued. With every stream cut, Codex made five retries and then sent a final error with the real message. - Claude (claude-haiku-5-5 through claude-agent-acp 0.73): a long reading task triggered Claude's own auto-compaction twice. The chat showed "Compacting context…" live and "Context compacted" afterwards. The final answer and the issue comment contained no compaction text. - Not verified live: model fallback and Claude informational banners. They need a model refusal or a blocking hook. Unit tests cover them. ## Risks - Low to medium. A Claude model message that is exactly a banner text and has no `messageId` would become a notice. Model output from claude-agent-acp always carries a `messageId`. - Older stored Codex `error` notices (category `error`, not recoverable) now render as a red row instead of being hidden. - Claude retries (`api_retry`) are still not visible. claude-agent-acp reports them only to clients that negotiate session-failure records, and ACPX drops `_meta`. This is a follow-up that depends on the ACPX `_meta` passthrough work. - On a failed Codex turn the thread collapses to a summary, so the red row does not show there. The existing task banner already shows the real provider message. - Some local suites failed on this machine. They do not touch the changed code: Cursor Cloud staging-custody tests, the ACPX Claude dependency-graph pin test (a timeout), and the Rust `task_memory` monitor tests. CI is the reference for these. > For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and discuss it in `#dev` before opening the PR. Feature PRs that overlap with planned core work may need to be redirected — check the roadmap first. See `CONTRIBUTING.md`. ## Model Used - Claude Opus 5.5 (`claude-opus-5-5`) in Claude Code, with tool use, code execution and browser automation. Default context window. Extended reasoning was not enabled. ## 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 - [ ] All Paperclip CI gates are green - [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge Refs paperclipai/paperclip#19252 (plan card precedent). 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
088f85c5fe |
fix: rename the managed environment to Paperclip Sandbox (#19296)
## Thinking Path > - Paperclip manages AI agents and their execution environments. > - Managed installations supply a default sandbox through managed configuration. > - Most selectors show the configured environment name. > - A fallback label, two errors, and examples still use Paperclip Computer. > - This pull request changes that stock copy to Paperclip Sandbox. > - Existing and custom environment names continue to come from the stored row. ## Linked Issues or Issue Description **What existing behavior does this improve?** The managed environment label in agent settings and the errors shown when the managed sandbox is unavailable. **Subsystem affected** The agent configuration UI, runner selection, and environment reconciliation tests. **Current behavior** Fallback copy and current examples call the managed sandbox Paperclip Computer. The actual environment name is already configurable. **Proposed behavior** Use Paperclip Sandbox for stock copy and current examples. Keep configured names unchanged in selectors, including legacy names and custom names. **Reason and benefit** The name identifies this environment as a managed sandbox and removes ambiguity. **Breaking changes** The displayed fallback and error text change. Error codes, execution behavior, and environment identity remain the same. No migration is needed. **Additional context** No duplicate rename issue or pull request was found. This is a copy update, with no new roadmap feature. ## What Changed - Update the managed fallback label and two unavailable-sandbox error messages. - Update current test and Storybook fixtures without changing story IDs or behavior. - Test configured names, fallback copy, and the unavailable-sandbox message. - Add a PostgreSQL regression test for a rename that retains the environment ID, instance default, agent binding, environment variables, and lease. ## Verification - `pnpm -r typecheck` passed. - `pnpm build` passed. - Focused coverage: 956 cases across nine changed suites. The new fixture initially tried to insert an existing singleton; its corrected upsert passed with all 52 environment-service cases. The updated runner suite also passed all 243 cases. - The two UI suites passed all 189 cases, including configured legacy/custom names and the missing-default fallback. - `pnpm check:token-gates` passed. - `node scripts/storybook-catalog.mjs --check` passed. The catalog is structural evidence only. - `node --test scripts/check-maps.test.mjs scripts/storybook-catalog.test.mjs scripts/storybook-feature-index.test.mjs` passed. - Full `pnpm test:run` is in progress. No live provider or browser journey is claimed by these tests. - CI passed on the current head after one server-shard rerun. The first attempt hit a 10 ms deadline assertion in the unchanged status-card timing test; its isolated local run and the complete rerun shard passed. The original failure and rerun are retained in the PR comment. - Reviewed the diff for secrets, personal data, and run artifacts. ## Risks Low risk: runtime edits change three display strings. Managed reconciliation is unchanged. The regression test exercises the existing rename against PostgreSQL. The configured name still controls normal display, so this code change alone does not rename existing database rows. A managed configuration update uses the existing reconciliation path. Roll back the copy by reverting this commit. ## Model Used OpenAI GPT-6.1 Sol (`gpt-6.1-sol`) through Codex in T3 Code, xhigh reasoning, with repository tools and code execution. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used, version, and capabilities - [x] I have checked ROADMAP.md; this copy update does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs - [x] I have described the issue in the PR with the enhancement template fields - [x] No internal or instance-local issue references - [x] The branch name describes the change and contains no internal ticket ID - [x] Focused tests pass locally - [x] Relevant tests were added or updated - [x] Relevant copy and examples were updated; no API or schema documentation changed - [x] Risks are documented - [x] All CI gates passed on the current head, including the server 11/12 rerun and aggregate verify - [ ] Full local test suite completed (still running; six chat shards passed) - [x] Greptile is 5/5 on the current head with no unresolved findings - [x] I will address all reviewer comments before requesting merge Co-authored-by: Paperclip <noreply@paperclip.ing> |
||
|
|
cb0b7525e0 |
feat(task-chat): warn at the top of a run when an MCP server failed to start (#19289)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - Each agent run shows its activity in the task chat. The Paperclip runner turns harness events into that activity. > - Codex reports `mcpServer/startupStatus/updated` when an MCP server fails to start. The runner dropped this event at the notification allowlist and in the Rust normalizer. > - When an MCP server fails, the agent runs without its tools. The agent then says "I could not reach the server", and the user cannot see why. > - This pull request maps a failed MCP start to a user-facing provider notice and shows it as one warning line at the top of the run. > - The benefit is that the cause of a "cannot reach my tools" answer is visible next to that answer. ## Linked Issues or Issue Description Refs #19252 (the plan card, which set the pattern for promoting a dropped harness signal to a dedicated task-chat surface). **Problem description** Codex sends `mcpServer/startupStatus/updated` (`name`, `status`, `error`, `failureReason`) during `thread/start`. The TypeScript allowlist (`codex-thread-normalization.ts`) and the Rust normalizer (`runner-core/src/provider_events.rs`) both dropped it. A run with a broken MCP server showed no sign of the failure. The agent only said that it could not reach the tools. **Proposed solution** Map `status: "failed"` to `provider.notice.recorded` with `category: "mcp_server_startup_failed"`, `severity: "warning"`, `scope: "session"` and `userActionable: true`. Show these notices as one run-health line under the runner header: "github MCP server failed to start: No such file or directory (os error 2)". **Alternatives considered** An inline notice row in the timeline. It scrolls away and sits among tool rows. A run-level line next to the header is easier to connect to the agent's answer. ## What Changed - Runner (Rust, production Codex path): `normalize_codex_notification` maps a failed `mcpServer/startupStatus/updated` to a `provider.notice.recorded` notice. `starting`, `ready` and `cancelled` stay out of the transcript. The new helper removes the Codex wrapper text ("MCP client for \`x\` failed to start: MCP startup failed:") so that the line shows the real reason. `reauthenticationRequired` becomes "needs re-authentication". - Runner (TypeScript): the same mapping in `canonicalProviderEventsFromCodex`, and the method is added to `isSupportedCodexNotificationMethod`. - Server: the `view=conversation` run-event query keeps `mcp_server_startup_failed` notices. A settled run can then still show the warning. Other notices stay out of that view. - UI: new `TaskChatRunHealthBanner`. `partitionRunHealthItems` takes MCP failures out of the run's items, with one line per server where the latest report wins. `TaskChatRunnerTurn` (live runs) and `TaskChatTurn` (settled, historical and merged turns) show it under the header. `coalesceSettledTurns` merges the failures when it merges turns. - Storybook: `Tasks and conversations/…/Task chat/Run health` shows one failure, several failures, a finished run and a healthy run, all through the production runner turn. ## Verification - `pnpm --filter @paperclipai/paperclip-runner exec vitest run src/provider-events.test.ts src/drivers/codex src/protocol`: 508 tests pass. - `cargo test --release -p paperclip-runner-core --lib -- provider_events`: 20 tests pass. - `pnpm --filter @paperclipai/ui exec vitest run src/components/task-chat src/components/transcript src/components/TaskChatThread.test.tsx`: 1340 tests pass, including the new `TaskChatRunHealthBanner.test.tsx` (persisted event to rendered banner, deduplication, settled historical turn, merged turns). - `pnpm --filter @paperclipai/server exec vitest run src/__tests__/task-cold-open.test.ts`: the conversation view keeps the MCP notice and still excludes other notices. - `pnpm check:token-gates` is clean. `node scripts/typecheck-low-memory.mjs` passes. - Live test on a local instance with Codex 0.160: a Codex agent with a preconfigured Codex home whose `config.toml` has `[mcp_servers.github] command = "github-mcp-server-not-installed"`. Codex reported the failure during `thread/start`. The persisted event had the summary "github MCP server failed to start: No such file or directory (os error 2)". The banner showed while the run was live. It also showed on the settled turn after "More run output", above the agent's answer that it could not reach the GitHub MCP server. ## Risks - Low risk. The change adds one notice category. It does not change how existing notices map or render. - A settled run whose transcript is deferred on a cold open (a successful run with a posted agent comment) shows the warning only after "More run output". This is the same as all other run activity under the current compact history. - Claude does not report MCP startup failures over ACP. `claude-agent-acp` reads MCP status only for OAuth. This change is therefore Codex-only. - Provisional task titles from provider session names are not part of this change. Codex app-server does not generate thread names (only its TUI does). Claude generates its title after the turn ends, and ACPX drops the title text. > For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and discuss it in `#dev` before opening the PR. Feature PRs that overlap with planned core work may need to be redirected — check the roadmap first. See `CONTRIBUTING.md`. ## Model Used - Claude Opus 5.5 (`claude-opus-5-5`), through Claude Code with tool use (shell, file edits, browser automation for Storybook and the live test). ## 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 - [ ] 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 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
b400f76647 |
feat(ui): submit task composers with Enter by default (#19272)
Use Enter to submit task replies and new tasks, with Shift+Enter for a new line. Add an experimental preference to require Command/Ctrl+Enter. Preserve autocomplete selection and IME confirmation, and retain the modifier shortcut until saved settings load. Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
c6996799c4 |
feat(task-chat): show an inline diff for every file edit (#19269)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - The task chat shows what an agent did during a run, including each tool call > - Codex and Claude both report the patch for every file edit, but Paperclip dropped it. Claude's ACP `diff` content was never read. The Codex `fileChange` item became a generic item with no patch. Codex `turn/diff/updated` had no native-runner mapping > - A reviewer could not see what an agent changed without opening the workspace > - This pull request carries a bounded patch on each edit call and shows it in the edit row. Each turn that changed files ends with a "Changed in this turn" card > - The benefit is that a reviewer can check every change in the conversation, with the same view for Codex and Claude ## Linked Issues or Issue Description Refs #19252 (precedent: canonical `plan.updated` events as a docked plan card). **Subsystem affected** Paperclip runner (Rust and TypeScript canonical event mapping), PRP provider-event schema, and the task-chat UI. **Problem or motivation** Edit rows say "Edited a file" with no content. Claude Edit/Write `diff` content is lost after the ACPX sidecar. The Codex native runner drops `fileChange.changes` and `turn/diff/updated`. The existing workspace-changes card showed a raw text patch in a dialog, and only on the in-process Codex path. **Proposed solution** Add an optional, bounded `fileChanges` list to `paperclip.tool.execution.v1`. Fill it from Codex `fileChange` items and Claude ACP `diff` content. Map Codex `turn/diff/updated` to `workspace.change.updated` on the native runner. In the UI, show `+N −M` on each edit row, open a compact colored diff, and end the turn with the change set. **Alternatives considered** A runner-side git diff at turn end. It needs workspace access and extra cost on every turn. The harness patches are already available. For Claude, the UI builds the turn card from the edit rows instead of new per-turn runner state. ## What Changed - Protocol: optional `fileChanges[]` on `toolExecution` in `provider-event.schema.json`, with the regenerated schema bundle, validators and manifest. Paths are workspace-relative. A patch is at most 32 KiB, and a call has at most 32 files. - Runner (Rust): new `tool_file_changes.rs`. A Codex `fileChange` item now also emits `tool.execution.*` with `fileChanges`; the native item event stays for the recovery and progress projections. `turn/diff/updated` becomes `workspace.change.updated`. `normalize_acpx_tool_call` re-validates the sidecar's `fileChanges`. `normalize_codex_notification_in` resolves absolute paths against the session cwd. - Runner (Rust): `has_bounded_rich_display_shape` accepts schema-valid workspace diffs. Without this change, durable storage cut each patch string to a 4 KiB preview. Patches use the uncapped secret redactor. - Runner (TS): new `tool-file-changes.ts`. The ACPX sidecar computes `fileChanges` from ACP `diff` content with the working directory. The in-process Codex and ACPX mappers do the same, with an optional `context` argument. - UI: new `TaskChatDiffView` (colored rows, hunk labels, a height cap, "Show N more lines"). Edit rows show counts and the diff. Collapsed activity groups show edit totals. The workspace card is now "Changed in this turn", with in-place per-file diffs, and it sits at the end of the turn. When a harness sends no whole-turn diff (Claude), the card is built from the edit rows. A change set is marked complete when its run ends. - UI: `native-run-events.ts` maps `workspace.change.updated` and attaches each edit's latest patch to its row (the `diff` transcript entries now carry `toolUseId`). - Design tokens: `--diff-add-*`, `--diff-remove-*` and `--sz-edit-diff-max-h` come from the status icon hues. - Storybook: `Tasks/Edit diffs` story. Docs: `doc/run-log-events.md`. ## Verification - Real runs on a local instance (`test-drive`, native runner): - Codex (`gpt-5.6-sol`): the "Applied a patch" rows show `+9` and `+35 −2` with their diffs. The turn ends with "Changed in this turn", 2 files, `+42`, from `turn/diff/updated`. - Claude (`claude-opus-5-5` via ACPX): the Write and Edit rows show `+5`, `+14 −1` and `+9` with correct hunks. The turn card is built from the edit rows. - Codex model note: with `gpt-5.4`, pinned Codex 0.160 reports "model metadata not found". The model then wrote files through the shell, so no `fileChange` items occurred. - `pnpm check:token-gates`: all gates clean. - `pnpm --filter @paperclipai/ui exec vitest run src/components/task-chat src/components/transcript src/adapters`: 1073 passed. - `packages/paperclip-runner`: `vitest run src/provider-events.test.ts src/tool-file-changes.test.ts src/cli/acpx-runtime-sidecar.test.ts` passed. `check:protocol-types` and `check:protocol-manifest` match. - `cargo test -p paperclip-runner-core --lib provider_events tool_file_changes`: passed. `cargo fmt --check`: clean. - Storybook: open `Tasks and conversations/…/Tasks/Edit diffs`. ## Risks - Larger payloads: an edit call can carry up to 96 KiB of patch in Rust, and the sidecar keeps 48 KiB under its 128 KiB frame. Above the budget, a file keeps its counts and drops its patch (`diffTruncated`). - Redaction: each patch goes through the shared secret redactor. Before this change, a 4 KiB preview cap also applied. - Claude turn card: it joins each edit's patch in order. It is not a net diff. For a file the turn created, the counts are net and exact. For an existing file, the counts are summed over its edits. - The workspace card moves to the end of the turn. One adapter test changed to match. - Local only: four Linux cgroup `task_memory` Rust tests fail on macOS. They do not touch these modules. ## Model Used Claude Opus 5.5 (`claude-opus-5-5`), via Claude Code with tool use (shell, browser and file editing) and a long context window. ## 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 - [ ] All Paperclip CI gates are green - [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
d8c47159d4 |
feat(task-chat): show Codex reasoning summaries as headline bullets (#19271)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - The task chat shows what an agent does while it runs, including a "Thinking" row for provider reasoning > - Real Codex runs produced reasoning items with no text > - So the Thinking row only says "Thinking" and never tells the user what the agent works on > - This pull request asks Codex for its own reasoning summaries, keeps every summary part, and shows the parts as bullets > - The benefit is that a user can see what the agent is thinking about, and a collapsed live run shows the newest headline as its status line ## Linked Issues or Issue Description Refs #19252 (same pattern: show a harness signal that Paperclip already receives) **Subsystem affected** Native runner (Rust runnerd Codex provider and event normalization, JS Codex driver) and the task chat UI (Thinking row and activity rows). **Problem or motivation** Codex 0.160 resolves an unset reasoning summary from the model, and current models resolve it to `"none"`. The rollout of a real gpt-5.6-sol run records `turn_context.summary = "none"`, and all of its reasoning items have `summary: []`. A local A/B with `codex exec` proved the cause: `model_reasoning_summary=none` gives no reasoning text, and `auto` gives headlines. Also, runnerd dropped `item/reasoning/*` notifications and ignored the reasoning item's `summary[]`. **Proposed solution** Send `summary: "auto"` on Codex `turn/start`. Map `item/reasoning/summaryTextDelta` and `summaryPartAdded` to reasoning deltas, with a blank line before each later part. Use the joined `summary[]` as the completed item text. In the UI, split the provider text at headline lines and show one bullet per part. **Alternatives considered** Use `summary: "detailed"`. That gives longer text, but `auto` lets the provider choose the best summarizer. **Roadmap alignment** This makes existing provider signals visible. It adds no new protocol event type or data model. **Additional context** Research note: overlooked harness signals, item 2. Claude is out of scope here. A live Claude run showed thinking blocks with signatures and empty text: current models default `thinking.display` to `"omitted"`. Claude Code ignores the `showThinkingSummaries` setting in SDK mode, and ACPX does not forward a `thinking` option, so the fix needs a claude-agent-acp patch hunk. That patch is also changed by #19264, so the Claude change follows after #19264 merges. The UI in this PR already shows prose-only (Claude) summaries. ## What Changed - Rust runnerd (`codex_provider.rs`): send `summary: "auto"` on every Codex `turn/start`. - Rust runnerd (`provider_events.rs`): map `item/reasoning/summaryTextDelta` and later `summaryPartAdded` to `item.delta` with `kind: "reasoning"` and `channel: "summary"`. Use the joined `summary[]` as a completed reasoning item's text. - JS Codex driver: send `summary: "auto"` on direct app-server transports, map `summaryPartAdded`, and read `summary[]` in `itemText`. - UI: new `reasoning-summary.ts` splits provider text into headline sections, and `TaskChatReasoningSummary` shows one bullet per part. The Thinking row and the activity row use the newest headline as their one-line status. Prose-only summaries (Claude) stay as prose. - Storybook: new "Task chat reasoning summaries" story with live, expanded, finished and Claude states. - Tests: Rust normalizer test, JS driver test, and splitter unit tests. ## Verification - `cargo test -p paperclip-runner-core` (provider events and the shared identity golden). - `pnpm --filter @paperclipai/paperclip-runner exec vitest run src/drivers/codex` - `pnpm --filter @paperclipai/ui exec vitest run src/components/task-chat src/components/transcript` - `pnpm check:token-gates` - Live test on a local worktree instance with a real Codex agent (gpt-5.6-sol). The Codex rollout now records `summary: "auto"`. Run events contain `**Assessing transaction boundary issues**`, a part break, and `**Planning atomic claim fix and verification**`. The task chat shows "Thought · Planning atomic claim fix and verification", and the expanded row lists both headlines as bullets. - Storybook: open "Tasks and conversations / Task creation and lifecycle / Tasks / Task chat reasoning summaries". - Claude was not changed. A live Claude run confirmed the cause for the follow-up (empty, signed thinking blocks). ## Risks - Codex now writes reasoning summaries, which adds a small number of output tokens per turn. This is the same cost as Codex CLI with its normal default. - The UI treats a line that is only bold text as a headline. A prose line that is only bold text also starts a new bullet. This is display only. > For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and discuss it in `#dev` before opening the PR. Feature PRs that overlap with planned core work may need to be redirected — check the roadmap first. See `CONTRIBUTING.md`. ## Model Used - Claude Opus 5.5 (`claude-opus-5-5`) in Claude Code, with tool use, code execution and browser automation. Default context window. ## 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 - [ ] All Paperclip CI gates are green - [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
b0fa2ef9bf |
feat(task-chat): show web searches, model switches, waits and verification checks as dedicated rows (#19262)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - Agents run through the native runner. The runner turns harness activity into typed canonical events such as `research.*`, `model.route.changed`, `wait.*` and the run's own verification checks. > - The task chat flattened these events into generic tool rows. A web search showed as "Ran Research eventType: research.started, summary: …". The run's verification checks were dropped completely. > - Live tests found a second break: the Rust runner core forwarded Codex `webSearch` items without their query, action or results. The canonical `research.*` events therefore had `query: null`. > - This pull request keeps the full payload for these families (as #19252 did for plans), adds small dedicated rows, and keeps the web-search fields through the durable runner. > - The benefit is that users see what the agent searched for, which model actually ran, how long a wait lasts, and whether each check passed, without opening the run log. ## Linked Issues or Issue Description Refs #19252 (same pattern for the plan card) **Subsystem affected** Task chat activity rows (UI), the native run-event transcript mapping, and the Rust runner core Codex normalizer. **Problem or motivation** Provider activity that the runner already maps to canonical events reaches the task chat as unreadable generic rows. Verification checks never appear. For Codex, the web-search query and action are lost before they reach the canonical event. **Proposed solution** Keep `research`, `model_identity`, `artifact`, `review` and `wait` events as `provider_activity` entries with their full payload. Project the runner's `verification` items as a new `verification` family. Render dedicated rows: a web search with its quoted query and source-domain chips, a model switch as `from → to · reason`, a wait with a live countdown, and green/red check lines. Keep bounded web-search and sleep fields in the Rust normalizer. **Alternatives considered** A separate "Checks" block beside the final answer. We kept the checks in the activity group, because the group summary already leads with "Check failed" when a check fails. ## What Changed - `ui/src/components/transcript/native-run-events.ts`: keep research, model, artifact, review and wait events as `provider_activity` with the full payload. Map `item.completed` items of kind `verification` to the new `verification` family. Context, hook, safety and delegation stay on the generic path, because other work items own them. - `packages/adapter-utils/src/types.ts`, `ui/src/components/task-chat/task-chat-model.ts`, `ui/src/lib/issue-chat-messages.ts`: add the `verification` provider-activity family. - `ui/src/components/task-chat/task-chat-activity-presentation.ts`: add labels: "Searched the web “query”", "Opened a web page host/path", "Switched models a → b · reason", "Waiting 30s" / "Waited 30s", and "Check passed" / "Check failed" / "Check not run". - `ui/src/components/task-chat/TaskChatRunnerActivityGroup.tsx` and `TaskChatProtocolActivityRow.tsx`: show up to three source-domain chips under a finished search, a live countdown for a running wait, and a check line with a tinted icon and its detail. - `ui/src/components/task-chat/completed-activity-summary.ts`: the group summary leads with "Check failed" when a check fails, and says "Switched models" for a reroute. - `ui/src/components/task-chat/transcript-adapter.ts`: verification detail keys, and a `startedAt` timestamp that stays across lifecycle merges (used by the countdown). - `packages/paperclip-runner/runner/crates/runner-core/src/provider_events.rs`: keep bounded `query`, `action` and http(s) `results` for Codex `webSearch` items, and `durationMs` for `sleep` items. Other item types do not change. - `ui/storybook/stories/tasks/task-chat-provider-activity.stories.tsx`: new story. Its fixtures are persisted run events that go through the production transcript path. ## Verification - `pnpm --filter @paperclipai/ui exec vitest run src/components/transcript src/components/task-chat src/components/TaskChatThread.test.tsx src/adapters/paperclip-runner src/lib`: 275 files and 3669 tests pass. - `cargo test -p paperclip-runner-core`: all tests pass, including the new `keeps_bounded_web_search_and_sleep_identity`. - UI typecheck is clean. `pnpm check:token-gates` is clean. `cargo fmt --check` is clean. - Storybook: open "Tasks and conversations / … / Task chat / Provider activity". It shows a settled run, a live search, a live wait countdown and a narrow layout. - Live test on a local worktree instance with a real Codex agent (gpt-5.6-sol, Codex app-server 0.160). The task asked for a web search, a parser with tests, a pause, and two checks. The task chat showed "Searched the web “ISO 8601 week date first week Thursday conversion calendar date”" and two green check rows ("node --test week-date.test.js · 8 tests passed; 0 failed.", "node --check week-date.js"). The group summary read "Ran checks". Before the runner fix, the same search had `query: null`. Not verified live: - The source-domain chips. Codex 0.160 sends `results: null`, because it keeps search results on the server. The chips appear only when a provider reports sources. Unit tests and the story cover them. - The wait countdown and the model-switch row. In the live run Codex paused with a shell `sleep`, not a native `sleep` item, and no reroute occurred. Unit tests and the story cover both. - Claude. Its WebSearch and WebFetch calls arrive as generic tool executions, because ACPX drops the tool metadata. They show as tool rows, as before. The ACPX `_meta` work is separate. ## Risks - Low risk. The change only affects how canonical events display. The generic path stays for the families that this PR does not change. - The Rust normalizer now persists the web-search query and the source URLs/titles in the run events. This data was already intended for the canonical `research.v1` event, and it is bounded (4,000 characters per text field, 64 results, http(s) URLs only). - A search that Codex reports with `action: other` and no query shows as "Searched the web" with no subject. > For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and discuss it in `#dev` before opening the PR. Feature PRs that overlap with planned core work may need to be redirected — check the roadmap first. See `CONTRIBUTING.md`. ## Model Used - Claude Opus 5.5 (`claude-opus-5-5`) in Claude Code, with tool use (shell, file edit, browser automation) and extended reasoning. ## 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 - [ ] All Paperclip CI gates are green - [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
01dd6ab336 |
fix(recovery): show the saved-work recovery step and record why it failed (#19260)
## Thinking Path
> - Paperclip is the open source app people use to manage AI agents for
work.
> - Sometimes a failed run left files in a sandbox. Then Retry first
runs system recovery to save those files before the task continues.
> - Recovery has steps: confirm that the previous attempt stopped, save
its files, then finish.
> - The task page did not show these steps. People saw "Queued" or
"Trying again in…" with a retry time that kept moving.
> - Each unclassified failure of the stop-confirmation step was recorded
only as `provider_unavailable`, so a repeated deferral could not be
diagnosed.
> - This pull request shows the current recovery step on the task. It
also records why each failed attempt failed, in closed labels.
> - The benefit is that people can see what Retry waits for, and
operators can see why recovery deferred.
## Linked Issues or Issue Description
Refs #19249
**What happened?**
A person clicked Retry on a task whose failed run had a retained
sandbox. For about 7 minutes the task showed only "Queued", and the
retry time moved forward twice. Recovery deferred twice in the
stop-confirmation step. Each deferral was recorded only as
`provider_unavailable` with an opaque fingerprint, so the cause could
not be found.
**Expected behavior**
The task shows the recovery step that it waits for, such as "Checking
that the previous attempt stopped. Trying again in 30s…". Each failed
attempt keeps a closed-label cause, for example `sandbox_not_running` or
`transport_timeout`, with an optional errno-style code and HTTP status.
**Steps to reproduce**
1. Get a remote task run to fail after its sandbox was placed, so that
recovery owns saved work.
2. Click Retry while the sandbox provider does not respond to the stop
check.
3. The task shows "Queued" or "Trying again in…". The recovery evidence
records only `provider_unavailable`.
**Paperclip version or commit**
master at
|
||
|
|
8227259d86 |
feat(task-chat): show the agent's native plan as a task list above the composer (#19252)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - Agents run through the native runner. The runner turns each harness's native plan into a canonical `plan.updated` event. > - The task chat did not show these plans. A small "Step 2 / 5" pill showed the checklist only on hover, and in live runs it received no plan data. > - Live tests found three breaks. The UI flattened `plan.updated` into tool rows. Headless Claude Code hides its task tools from current models. Codex ships its `update_plan` tool disabled. > - This pull request fixes the three breaks and replaces the pill with a docked plan card above the composer. > - The benefit is that users see what the agent finished, what it does now, and what comes next. The view is the same for Claude, Codex, Grok and Copilot. ## Linked Issues or Issue Description **Subsystem affected** Task chat UI (turn status island), native runner ACPX launch environment for Claude, and native runner Codex app-server launch arguments. **Problem or motivation** Harnesses report native plans, and the runner records them as `plan.updated` events. Users do not see them. The live transcript builder converts `plan.updated` into generic tool rows, so the plan steps are lost. Claude Code in headless mode does not offer TaskCreate/TaskUpdate for current models, so Claude never makes a plan. Codex 0.160 has `update_plan` disabled by default, so Codex writes its checklist into a Paperclip document instead. **Proposed solution** Keep the full plan snapshot in the live transcript. Enable the Claude task tools with `CLAUDE_CODE_ENABLE_TODO_TOOLS=1` in the ACPX launch environment. Enable the Codex plan tool with `tools.update_plan.enabled=true`. Show the plan as a docked card with clear rules for when it shows, collapses and hides. **Alternatives considered** Show the plan only in the hover popover (the old behavior). Users did not find it. Write the plan into the issue Plan document. That mixes a per-turn checklist with the reviewed planning document. **Roadmap alignment** This makes existing native runner plan events visible. It adds no new protocol or data model. **Additional context** Grok and Copilot needed no harness change. Cursor could not start in a local worktree instance (an unrelated startup admission problem), so this PR does not verify Cursor. ## What Changed - `ui/src/components/transcript/native-run-events.ts`: keep `plan.updated` as `provider_activity` with family `plan` and the full payload, not as a tool row. - `ui/src/components/task-chat/TaskChatTurnStatusIsland.tsx`: replace the hover pill with a docked plan card. It shows done, current, upcoming and blocked steps, a progress bar and file-change totals. - Visibility rules: hidden with no steps and after the run ends; collapses when all steps are done; header only for one-step plans and while a question or approval is pending; window around the current step for plans over 7 steps; collapsed by default on mobile. - `ui/src/components/TaskChatThread.tsx`: pass `defaultCollapsed` (mobile) and `compact` (pending runtime request), and reset the card per run. - `ui/src/components/task-chat/transcript-adapter.ts`: keep the `failed` step status. - `packages/paperclip-runner/src/drivers/acpx/environment.ts`: set `CLAUDE_CODE_ENABLE_TODO_TOOLS=1` for Claude launches. A host value cannot turn it off. - `packages/paperclip-runner/src/drivers/codex/codex-security-config.ts`: add `-c tools.update_plan.enabled=true` before the policy overrides and the `app-server` subcommand. - `ui/storybook/stories/tasks/task-chat-agent-plan.stories.tsx`: new story for each state. It uses the production composer dock, composer and question takeover. - Tests for all of the above. `ui/src/index.css` replaces the unused popover size token with a list max-height token. ## Verification - `pnpm --filter @paperclipai/ui exec vitest run src/components/transcript src/components/task-chat src/components/TaskChatThread.test.tsx src/adapters/paperclip-runner` (1345 tests pass). - `pnpm --filter @paperclipai/paperclip-runner exec vitest run src/drivers/acpx/environment.test.ts src/drivers/codex` (pass). - UI and runner typecheck are clean. `pnpm check:token-gates` is clean. - Storybook: open "Tasks and conversations / … / Task chat / Agent plan". The "All States Gallery" story shows every state. "Live Run Simulation" animates a run. - Live test on a local worktree instance with real API keys: a multi-step task for each harness. The card showed and updated during the run for Claude (Opus 5.5), Codex (gpt-5.6-sol), Grok (grok-4.7) and Copilot (gpt-5.6-luna). For Claude the card collapsed when all steps were done and hid after the run ended. - Codex probe: `codex exec` with the pinned 0.160 binary reports no `update_plan` tool by default and reports the tool with `-c tools.update_plan.enabled=true`. ## Risks - Claude and Codex now get their plan tools. Agents can spend a few tokens on plan updates. The tools are standard harness features. - The Codex flag goes before the web-search and project-instruction policy overrides, so the existing policy tail check still holds. - Runs that finish fast show the card only briefly. This is the intended hide rule. - Cursor plan display is not verified. > For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and discuss it in `#dev` before opening the PR. Feature PRs that overlap with planned core work may need to be redirected — check the roadmap first. See `CONTRIBUTING.md`. ## Model Used - Claude Opus 5.5 (`claude-opus-5-5`) in Claude Code, with tool use (shell, file edit, browser automation) and extended reasoning. ## 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 - [ ] All Paperclip CI gates are green - [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
21640b6d51 |
feat(connections): gate the built-in Google Workspace connector behind an experimental toggle (#19247)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - The Apps catalog lets operators connect external tools, including Google services. > - Paperclip has a built-in Google Workspace connector, but Google has not yet verified Paperclip's Google app. > - The built-in connector also hides the Composio and Arcade Google apps, because native Google definitions claim those app names. > - Users therefore see an unverified connector and cannot find the working aggregator Google apps. > - This pull request puts the built-in connector behind a default-off experimental setting. When the setting is off, the aggregator Google apps appear. > - The benefit is that users get working Google connectors now, and the team can still test the built-in connector on demand. ## Linked Issues or Issue Description **Problem** Google has not verified Paperclip's Google app yet. The Apps page still offers the built-in Google Workspace connector. The built-in Google definitions also suppress the Composio and Arcade Google apps (Gmail, Google Calendar, Google Drive, Docs, Sheets, Slides, Chat), so users cannot find them. **Proposed solution** Add the `enableGoogleWorkspaceConnector` experimental setting. The default is off. When it is off, hide and block the built-in connector, and show the aggregator Google apps. When it is on, keep the current behavior. **Alternatives considered** Delete the built-in connector until verification is complete. We rejected this option because the team must continue to test the connector. **Additional context** Composio documents Gmail (63 tools), Google Calendar (50 tools), and Google Drive toolkits that use Composio-managed OAuth. These toolkits do not need Paperclip's Google app verification. ## What Changed - Added the default-off `enableGoogleWorkspaceConnector` experimental setting to the shared types, validator, feature catalog, server defaults, and the managed-key list for Paperclip Cloud staging. - Added `experimentalFeatureKey: "enableGoogleWorkspaceConnector"` to the `google-workspace` app definition. The existing generic connector gate then hides the connector in the gallery and blocks its setup, discovery, execution, and agent suggestions when the setting is off. - Added a "Google Workspace connector (Paperclip)" toggle card to **Settings → Experimental**. - Apps page (`Browse.tsx`): when the setting is off, built-in Google rows without saved accounts no longer claim aggregator app identities. The Composio and Arcade Google apps then show as aggregator rows. The legacy Google slug filter now applies only to native rows, so the Composio `gmail` row is not dropped. - Saved per-service Google connections (Gmail, Drive, and others) are not gated. They stay visible and usable. - Updated `doc/connections/GOOGLE-WORKSPACE.md`. - Tests: added tests for the hidden and visible Apps page states, the settings toggle, and the definition gate. Existing built-in Google Workspace tests now enable the setting. ## Verification - `cd packages/shared && npx vitest run` passes (1055 tests). - `cd server && npx vitest run src/__tests__/connection-management.integration.test.ts src/__tests__/tool-access-service.test.ts src/__tests__/tool-gateway-service.test.ts src/services/gmail-tool-governance.test.ts src/services/google-chat-tool-policy.test.ts src/__tests__/instance-settings-service.test.ts src/__tests__/health.test.ts src/__tests__/instance-settings-managed-overlay.test.ts` passes (864 tests). - `cd ui && npx vitest run src/pages/apps src/pages/InstanceExperimentalSettings.test.tsx src/features/connections` passes. - `tsc --noEmit` passes for `packages/shared`, `server`, and `ui`. The `ui` run shows errors only in the untouched `storybook/support/feature-map` files. - `pnpm check:token-gates` passes. - Manual check: open **Apps** with the setting off. Search for "Gmail". The Composio Gmail row appears, and the built-in Google Workspace card does not. Turn on the setting in **Settings → Experimental**. The built-in card appears again. ## Risks - Existing built-in `google-workspace` connections stop running while the setting is off, because the generic gate blocks execution. This is intentional, so that the unverified Google app is not used. Turn on the setting on instances that must keep these connections. - Saved per-service Google connections are not affected. - When the setting is on, the behavior does not change. > For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and discuss it in `#dev` before opening the PR. Feature PRs that overlap with planned core work may need to be redirected — check the roadmap first. See `CONTRIBUTING.md`. ## Model Used - Claude Opus 5.5 (Anthropic), model ID `claude-opus-5-5`, running in Claude Code with tool use (shell, file edits, web fetch). ## 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 - [ ] 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 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
7fd05e1354 |
fix(skills): keep initial file editor drafts clean (#19241)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - People inspect and edit skill files from the Skills library. > - The Markdown editor receives the body without YAML frontmatter. > - The skill page compared that body with the entire saved file. > - Opening Edit therefore showed unsaved changes before the person typed. > - This pull request uses the same saved body for initialization, comparison and Discard. > - Clean files stay clean, while real edits retain the existing save path. ## Linked Issues or Issue Description **What happened?** Open an editable SKILL.md with YAML frontmatter in the Skills library. Select Files, then Edit. The page immediately shows Unsaved changes without input. The draft contains only the body, while the dirty check compares it with the full file. **Expected behavior** Opening Edit leaves the file clean and Save disabled. Real input enables Save. Discard restores the original body. Saving an edit keeps the existing frontmatter. **Steps to reproduce** 1. Open a managed skill whose SKILL.md has YAML frontmatter and a Markdown body. 2. Select Files, then Edit. 3. Make no editor input. 4. Observe the dirty indicator and Save state. **Paperclip version or commit** Reproduced locally on master |
||
|
|
b3da1d886a |
fix(ui): retain Coordinator label filters across reloads (#19233)
## Thinking Path
> - Paperclip is the open source app people use to manage AI agents for
work.
> - Operators use task filters to keep a useful view of their work.
> - Coordinator saves status and assignee filters in the task-list URL.
> - A selected label stayed only in React state, so reload removed it
and showed unrelated rows.
> - This change saves and restores selected labels through the same
page-owned URL path.
> - Operators can reload and share that filtered collection without
selecting its labels again.
## Linked Issues or Issue Description
**What happened?**
In Coordinator All tasks, select a status, assignee, and label. Sort by
Task ID and reload. Status, assignee, and sort remain selected, but the
label is cleared and rows without that label appear.
**Expected behavior**
Reload and history navigation retain the selected labels with the other
URL filters. Clear filters removes the selected labels.
**Steps to reproduce**
1. Open Coordinator All tasks with labeled and unlabeled tasks for the
same assignee and status.
2. Select that status, assignee, and a label.
3. Change Task ID sorting and reload the page.
4. Check both the selected label and the displayed tasks.
**Paperclip version or commit**
Source regression reproduced at master
|
||
|
|
56517dda6c |
fix(ui): bundle connector, toolbar, empty-state and agent roster fixes (#18716)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - Operators use connector setup, collection headers, empty states, and agent lists to manage that work. > - Provider redirects replace the setup page, and collection controls use different sizes. > - Agent selection inserts a bar above the list. The row link highlights only part of the row. > - This pull request keeps sign-in in a separate window and applies the Tasks control sizes to collection and audit headers. > - It also reuses artifact artwork for empty collections and gives agent selection a fixed action card. > - These changes preserve the operator's place and keep controls and rows stable. ## Linked Issues or Issue Description **What happened?** Connector sign-in replaced the current page. Inline collection controls had different heights. Projects and Artifacts used small placeholder empty states. Agent selection moved the list, hover covered only the identity cell, and chat/status shared that cell without matching headings. **Expected behavior** Provider sign-in opens in a new tab or window. Collection controls match Tasks. Empty collections use the large artifact graphics. Agent actions float above the page while rows remain aligned. **Steps to reproduce** Start connector sign-in from a page or dialog. Compare collection and Audit headers. Open an empty Projects or Artifacts collection. Select an agent, then hover across its row. Related public work: #13584 covers an earlier connector new-tab implementation, including same-page fallbacks that this bundle does not use. #8528 covers Tasks toggle sizing. #17742 covers scoped agent Audit sections. This bundle does not change server callback or audit authorization contracts. ## What Changed - Reserve a separate authorization window during the click. Use validated sign-in URLs, retain a new-tab fallback, and close blank windows after failed requests. Store Cloud reauthentication state in the destination window. - Use the Tasks 44px control foundation for shared collection headers and Audit, Costs, Timeline, Secrets, Teams, Gateways, and agent skill controls. - Use a large artifact stack with an off-white Paperclip image with a dark icon for Projects and artifact Tasks empty states. Use one matching artifact for other types. Set 20px gaps and use the label “Create project”. Action hover and keyboard focus animate the artwork. - Portal agent bulk actions to a fixed card 48px above the bottom safe area. Use quintic entry/exit motion and respect reduced motion. Retain card contents during exit. - Give chat and status separate cells, add a Status heading, use the MessagesSquare chat action with a hover tooltip, and highlight the entire row. - Add linked agent chips and a manager picker to the agent profile. Block self and descendant manager choices. Keep the name crown and custom title inline during edits. - Update design guidance, the connection maps, regression tests, and empty-state Storybook fixtures. ## Verification - Final commit `a41a6c6494a839deaaec1ef7cc50c90078ab6381`: all 55 checks passed, three skipped. [Canonical CI run](https://github.com/paperclipai/paperclip/actions/runs/41999792769) includes all eight browser shards and all server/runner/workspace groups. Greptile: 5/5, zero unresolved review findings. - Workspace typecheck/build passed. Local UI suite passed 11,006 tests in 880 files, plus 542 CLI tests. Subsequent connector callback changes passed all 245 AppsConnect tests, UI typecheck, token gates, and query-error policy checks. Manager cache/error regressions passed four tests. Map checks passed. - Local connector browser suite: 20 passed. All six chat integration shards: 1,931 passed. Workspace B groups passed; database tests passed 313 cases across 72 files with one worker. - Browser preview verified agent manager changes, overview links, inline name/title geometry, empty-state colors, row actions and the chat tooltip. Live provider consent and post-deployment feature verification remain separate from these fixtures. - Preserved failures: ten bulk-roster tests initially missed the portaled action card; their selectors were fixed and all twelve roster tests passed. A nested fixture selected pnpm 11 and removed local dependencies; the local shim now pins pnpm 9. Embedded PostgreSQL native links were restored. A Python 3.9 fixture failure passed all 19 tests with the current runtime. Concurrent local database startup failures passed on the one-worker rerun. - The broad local serialized server run passed 3,791 tests with one scheduling assertion failure, which passed in isolation. The local general-server run reproduced a native recovery provider/model fixture failure and has not completed. These server sources are unchanged by this bundle; all final canonical CI server shards passed. This is not a claim that every broad local run passed. - [Earlier CI run](https://github.com/paperclipai/paperclip/actions/runs/41995119880) failed a browser test during cleanup when heartbeat-run cancellation hit a PostgreSQL lock timeout. All final browser shards passed without weakening that test. - Review follow-ups cover Slack popup/fallback recovery, a single artwork hover transform, shared manager error rendering, detached standalone OAuth windows, and verified task-bound callbacks in both hosts. ## Risks - Browser popup policy and provider callback behavior can affect sign-in completion. The original setup page stays open; blocked windows have an explicit recovery path. - Shared toolbar styles affect several surfaces. Menu content remains in its existing portals; canonical label tabs and search clear buttons retain their own geometry. - No schema, server, API authorization, or migration change. - Required CI and review are complete. Deployment provenance and hosted feature verification are checked separately after merge. ## Model Used OpenAI Codex, GPT-6 family, with reasoning, repository tools, test execution, and browser inspection. The exact model ID and context-window size were not exposed in this session. ## 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 relevant tests locally and they pass (broader local exceptions are recorded above) - [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: Paperclip <noreply@paperclip.ing> |
||
|
|
9e9a628a57 |
feat(ui): turn Artifacts V1 on for every instance and hide its toggle (#19164)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - Artifacts show the output of agent work on the Artifacts page, in the panel Artifacts tab, and in the task thread > - #17228 added the Artifacts V1 presentation behind an experimental setting that is off by default > - The presentation is now ready for all users, so an opt-in toggle is no longer necessary > - A new default alone does not reach all instances, because each experimental write persists every flag > - This pull request removes the toggle and turns V1 on for every instance > - The benefit is one artifact presentation for all users, with an off switch for hosting operators ## Linked Issues or Issue Description Refs #17228 Refs #17263 **Is your feature request related to a problem? Please describe.** Artifacts V1 shows only on instances where an admin turned on an experimental setting. Other users see the previous cards. **Describe the solution you would like** Show Artifacts V1 on all instances. Remove the toggle from Experimental settings. **Describe alternatives you have considered** A new default without a change to the hook. This does not work, because many instances have a stored false that nobody chose, and no toggle would remain to change it. ## What Changed - Removed the Artifacts V1 card from Instance Settings, Experimental. - Changed `enableArtifactsV1` to default on in the schema, the feature catalog, and the settings service. - Changed `resolveArtifactsV1Enabled` to ignore a stored false. It honours false only when the value comes from managed config. - Kept the flag and the previous cards, so a hosting operator can hold V1 off. - Kept the key in the Cloud staging list, so a managed false does not hold V1 off on staging. - Updated unit tests, the Artifacts V1 plan, and the directions-lab Today reference. - Moved the attachment and upload e2e specs and the runner download helper to the V1 rows. - Added V1 tests for a Markdown review: expansion, deep link, and open, raw and download actions. ## Verification - `cd ui && npx vitest run`: one test file failed before its fix. That file tests the previous cards, and it now mocks the hook to off. I reran it with the other changed UI tests, and they pass. I did not repeat the full UI run after the fix. - `npx playwright test --config tests/e2e/playwright.config.ts tests/e2e/text-attachment-tabs.spec.ts tests/e2e/artifact-uploads.spec.ts tests/e2e/artifact-tab-arrival.spec.ts`: 10 tests pass on V1. - `tests/e2e/cloud-auth.spec.ts` failed once in CI on a task heading. It does not touch artifacts, and 10 local runs pass. - `cd server && npx vitest run src/__tests__/instance-settings`: 183 tests pass. - `cd packages/shared && npx vitest run src/feature-catalog.test.ts src/validators/instance.test.ts`: 35 tests pass. - `pnpm run check:token-gates` and the `ui` and `server` typechecks pass. I did not run the full repository check. - In the artifact directions lab, with no stored settings, the Today right panel renders the V1 rows. - I did not test this on a live instance. After merge, confirm on staging that the Experimental page has no Artifacts V1 card and that all three surfaces show V1. ## Risks - All users see V1 after the next release, not only staging users. To revert, revert this pull request. - Users cannot turn V1 off. Only a hosting operator can, through managed config, and not on Cloud staging. - An instance with a managed `enableArtifactsV1: false` stays on the previous cards. The cloud harness source has no reference to this key, but I cannot read the live fleet configuration. - V1 surfaces render before settings load. An operator-held instance can briefly show V1 before the previous cards. - Admins who use the API can still write the flag. The write has no effect on unmanaged instances. > For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and discuss it in `#dev` before opening the PR. Feature PRs that overlap with planned core work may need to be redirected — check the roadmap first. See `CONTRIBUTING.md`. ## Model Used - Anthropic Claude Opus 5.5 (`claude-opus-5-5`) in Claude Code, with tool use and code execution. ## 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 - [ ] All Paperclip CI gates are green - [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
c3c2a680ee |
fix(ui): lift a picture front on hover like the sheets in Artifacts V1 (#17263)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - The Artifacts page, the panel's Artifacts tab and the task thread show the artifacts that agents produce. Behind the experimental setting Artifacts V1 (#17228) they use the presentation that the artifact directions lab settled. > - On the Artifacts page, a hovered tile turns the two backing pages of a stack and lifts the front artwork by 6px. The lift targets the `data-artifact-front` hook. Sheets carry the hook. A picture or poster-less video front is a bare print and does not carry it. > - So on a picture stack, or a single picture tile, the backings turn but the artwork stands still. Tonio saw this on staging today. > - This pull request puts the print inside the same lifted wrapper as the sheets. > - The benefit is that every front moves the same way on hover, as the lab and the mocks do. ## Linked Issues or Issue Description Refs #17228 (the Artifacts V1 pull request that introduced the hover rules and the print front). **What happened?** With Artifacts V1 on, hover a task stack on the Artifacts page whose newest artifact is a picture. The two backing pages turn by 5°, but the picture does not rise. A single picture tile does not rise either. Sheet fronts (documents, text, files) rise 6px as designed. **Expected behavior** Every front rises 6px while its tile is hovered, as the lab's MVP V1 kit and the PCLP-Core mocks show, and as `index.css` already specifies for `data-artifact-front`. **Steps to reproduce** 1. Settings → Experimental → turn on Artifacts V1. 2. Open the Artifacts page with a task whose newest artifact is a picture. 3. Hover the task's stack. The backings fan out; the picture stays where it is. **Paperclip version or commit** master at |