feat(tasks): clear a finished cloud run's conversation without a sandbox - #76943
Conversation
🤖 CI report
|
| File | Size | Δ vs base |
|---|---|---|
render-query/src/render-query/render-query.js |
21.78 MiB | 🔺 +1.4 KiB (+0.0%) |
Posted automatically by build-bundle-size-report · uncompressed bytes from dist-report
✅ Eager graph — within budget
How much code each root ships on the eager path — downloaded and parsed before the surface is interactive. Measured from the esbuild output chunks (post-tree-shake, static imports only); lazy import() / React.lazy chunks are not counted.
| Root | Eager (shipped) | Δ vs base | Budget |
|---|---|---|---|
entry (logged-out pages, app bootstrap)src/index.tsx |
1.27 MiB · 22 files | no change | ███░░░░░░░ 28.1% of 4.51 MiB |
authenticated shell (every logged-in page)src/scenes/AuthenticatedShell.tsx |
8.51 MiB · 3,133 files | 🔺 +131 B (+0.0%) | █████████░ 87.6% of 9.71 MiB |
🟢 node_modules/monaco-editor/ stays out of src/index.tsx
🟢 src/lib/components/ActivityLog/describers stays out of src/index.tsx
🟢 [object Object] stays out of src/index.tsx
🟢 [object Object] stays out of src/index.tsx
🟢 node_modules/monaco-editor/ stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/lib/components/ActivityLog/describers stays out of src/scenes/AuthenticatedShell.tsx
🟢 [object Object] stays out of src/scenes/AuthenticatedShell.tsx
🟢 [object Object] stays out of src/scenes/AuthenticatedShell.tsx
Largest files eagerly shipped from src/index.tsx
| Size | File |
|---|---|
| 126.8 KiB | ../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.production.min.js |
| 24.6 KiB | ../node_modules/.pnpm/buffer@6.0.3/node_modules/buffer/index.js |
| 6.3 KiB | ../node_modules/.pnpm/react@18.3.1/node_modules/react/cjs/react.production.min.js |
| 4.5 KiB | ../node_modules/.pnpm/@jspm+core@2.1.0/node_modules/@jspm/core/nodelibs/browser/process.js |
| 3.9 KiB | ../node_modules/.pnpm/scheduler@0.23.2/node_modules/scheduler/cjs/scheduler.production.min.js |
| 1.4 KiB | ../node_modules/.pnpm/base64-js@1.5.1/node_modules/base64-js/index.js |
| 1.3 KiB | src/RootErrorBoundary.tsx |
| 912 B | ../node_modules/.pnpm/ieee754@1.2.1/node_modules/ieee754/index.js |
| 789 B | src/scenes/ChunkLoadErrorBoundary.tsx |
| 762 B | src/index.tsx |
Largest files eagerly shipped from src/scenes/AuthenticatedShell.tsx
| Size | File |
|---|---|
| 304.9 KiB | ../node_modules/.pnpm/posthog-js@1.417.0/node_modules/posthog-js/dist/rrweb.js |
| 267.7 KiB | ../node_modules/.pnpm/@posthog+icons@0.38.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/icons/dist/posthog-icons.es.js |
| 243.8 KiB | ../node_modules/.pnpm/posthog-js@1.417.0/node_modules/posthog-js/dist/module.js |
| 238.4 KiB | src/taxonomy/core-filter-definitions-by-group.json |
| 154.3 KiB | ../node_modules/.pnpm/re2js@0.4.1/node_modules/re2js/build/index.esm.js |
| 126.8 KiB | ../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.production.min.js |
| 103.8 KiB | src/lib/api.ts |
| 94.6 KiB | ../packages/quill/packages/quill/dist/index.js |
| 93.3 KiB | ../node_modules/.pnpm/prosemirror-view@1.40.1/node_modules/prosemirror-view/dist/index.js |
| 90.6 KiB | ../node_modules/.pnpm/@tiptap+core@3.20.6_@tiptap+pm@3.20.6/node_modules/@tiptap/core/dist/index.js |
Posted automatically by check-eager-graph · sizes are eager output bytes (shipped, post-tree-shake) from the esbuild metafile · part of #32479
✅ Toolbar bundle — eager 2.22 MiB within budget
What the toolbar ships to customer pages, measured from the esbuild output (minified, post-tree-shake). The eager set is the entry plus everything statically imported from it — fetched before any feature runs; deferred chunks load lazily. The eager guardrail is 5.72 MiB. Each output file must also stay below 10 MB, where CloudFront stops compressing it. The module boundary is enforced separately by check-toolbar-graph.
| Metric | Size | Δ vs base | Budget |
|---|---|---|---|
| Eager (shipped) entry + static imports |
2.22 MiB · 17 files | no change | ████░░░░░░ 38.7% of 5.72 MiB |
| Deferred (lazy) | 2.08 MiB · 33 files | no change | n/a — loads on demand |
Loader dist/toolbar.js |
1.1 KiB | no change | █░░░░░░░░░ 5.8% of 19.5 KiB |
Largest eagerly-shipped chunks
| Size | File |
|---|---|
| 730.0 KiB | dist/toolbar/toolbar-app-LL5TI34A.css |
| 565.3 KiB | dist/toolbar/chunk-chunk-RCUAWDGK.js |
| 484.6 KiB | dist/toolbar/chunk-chunk-2OORENDY.js |
| 133.6 KiB | dist/toolbar/chunk-chunk-QQ2DRXHJ.js |
| 131.8 KiB | dist/toolbar/chunk-chunk-T5KY5WYR.js |
| 71.2 KiB | dist/toolbar/toolbar-app-UDDFGSJT.js |
| 69.0 KiB | dist/toolbar/chunk-chunk-27JL52RE.js |
| 35.6 KiB | dist/toolbar/chunk-chunk-2U5IYX7Z.js |
| 20.9 KiB | dist/toolbar/chunk-chunk-KWHQMXDE.js |
| 12.2 KiB | dist/toolbar/chunk-chunk-PIK3PADE.js |
Posted automatically by check-toolbar-size · sizes are toolbar output bytes (shipped, post-tree-shake) from the esbuild metafile
✅ Dist folder size — 🔺 +35.3 KiB (+0.0%)
Total size of the built frontend/dist folder (all assets), compared against the base branch.
Total: 1431.09 MiB · 🔺 +35.3 KiB (+0.0%)
ℹ️ MCP UI apps size — 31 app(s), 16614.3 KB JS
Built size of each MCP UI app (main.js + styles.css).
| App | JS | CSS |
|---|---|---|
| debug | 599.6 KB | 184.6 KB |
| action | 457.8 KB | 184.6 KB |
| action-list | 564.4 KB | 184.6 KB |
| cohort | 456.8 KB | 184.6 KB |
| cohort-list | 563.4 KB | 184.6 KB |
| email-template | 456.6 KB | 184.6 KB |
| error-details | 472.4 KB | 184.6 KB |
| error-issue | 457.5 KB | 184.6 KB |
| error-issue-list | 564.3 KB | 184.6 KB |
| experiment | 561.5 KB | 184.6 KB |
| experiment-list | 565.2 KB | 184.6 KB |
| experiment-results | 566.7 KB | 184.6 KB |
| feature-flag | 567.2 KB | 184.6 KB |
| feature-flag-list | 570.9 KB | 184.6 KB |
| feature-flag-testing | 461.0 KB | 184.6 KB |
| insight-actors | 562.2 KB | 184.6 KB |
| invite-email-preview | 456.0 KB | 184.6 KB |
| llm-costs | 559.5 KB | 184.6 KB |
| session-recording | 458.6 KB | 184.6 KB |
| survey | 458.4 KB | 184.6 KB |
| survey-global-stats | 562.2 KB | 184.6 KB |
| survey-list | 565.1 KB | 184.6 KB |
| survey-stats | 562.2 KB | 184.6 KB |
| trace-span | 457.2 KB | 184.6 KB |
| trace-span-list | 564.3 KB | 184.6 KB |
| workflow | 457.1 KB | 184.6 KB |
| workflow-list | 563.7 KB | 184.6 KB |
| loops-review | 461.4 KB | 184.6 KB |
| query-results | 750.8 KB | 184.6 KB |
| render-ui | 828.9 KB | 184.6 KB |
| visual-review-snapshots | 461.6 KB | 184.6 KB |
⚠️ Backend coverage — 91.0% of changed backend lines covered — 6 uncovered
🧪 Backend test coverage
Patch coverage — changed backend lines (products + core): ██████████████████░░ 91.0% (63 / 69)
| File | Patch | Uncovered changed lines |
|---|---|---|
products/tasks/backend/presentation/views/api.py |
83.3% | 1492, 1499 |
products/tasks/backend/models.py |
86.4% | 2551–2552, 2554 |
products/tasks/backend/facade/api.py |
90.0% | 2680 |
🤖 Agents: add a test covering the lines above, or note why under "How did you test this code?". Machine-readable gap list: the patch-coverage artifact on this run (gh run download 31750512626 -n patch-coverage), or the coverage-data block at the end of this comment.
Per-product line coverage (touched products)
| Product | Coverage | Lines |
|---|---|---|
demo |
███████████░░░░░░░░░ 56.3% |
1,497 / 2,661 |
tasks |
██████████████░░░░░░ 70.2% |
38,020 / 54,148 |
signals |
█████████████████░░░ 82.9% |
27,774 / 33,494 |
cdp |
█████████████████░░░ 84.2% |
3,914 / 4,649 |
data_modeling |
█████████████████░░░ 86.3% |
8,909 / 10,326 |
actions |
█████████████████░░░ 86.6% |
717 / 828 |
notebooks |
█████████████████░░░ 87.2% |
8,547 / 9,806 |
cohorts |
██████████████████░░ 87.6% |
6,528 / 7,452 |
product_tours |
██████████████████░░ 87.9% |
1,303 / 1,482 |
data_warehouse |
██████████████████░░ 88.7% |
12,307 / 13,880 |
managed_warehouse |
██████████████████░░ 88.8% |
6,642 / 7,478 |
exports |
██████████████████░░ 89.1% |
7,533 / 8,455 |
engineering_analytics |
██████████████████░░ 89.4% |
6,839 / 7,649 |
dashboards |
██████████████████░░ 89.5% |
6,222 / 6,949 |
alerts |
██████████████████░░ 90.4% |
4,554 / 5,039 |
mcp_analytics |
██████████████████░░ 90.4% |
3,968 / 4,388 |
streamlit_apps |
██████████████████░░ 90.7% |
2,630 / 2,901 |
conversations |
██████████████████░░ 90.8% |
19,364 / 21,329 |
error_tracking |
██████████████████░░ 91.2% |
11,325 / 12,415 |
stamphog |
██████████████████░░ 91.3% |
4,505 / 4,936 |
slack_app |
██████████████████░░ 92.5% |
11,334 / 12,255 |
canvas |
███████████████████░ 92.6% |
2,923 / 3,155 |
early_access_features |
███████████████████░ 92.9% |
1,347 / 1,450 |
ai_observability |
███████████████████░ 92.9% |
17,244 / 18,560 |
web_analytics |
███████████████████░ 92.9% |
16,337 / 17,578 |
posthog_ai |
███████████████████░ 93.2% |
1,326 / 1,422 |
surveys |
███████████████████░ 93.3% |
5,943 / 6,373 |
reminders |
███████████████████░ 93.4% |
468 / 501 |
marketing_analytics |
███████████████████░ 93.5% |
16,405 / 17,551 |
approvals |
███████████████████░ 93.5% |
3,491 / 3,734 |
product_analytics |
███████████████████░ 93.6% |
7,124 / 7,611 |
review_hog |
███████████████████░ 94.1% |
9,319 / 9,906 |
endpoints |
███████████████████░ 94.3% |
8,814 / 9,349 |
workflows |
███████████████████░ 94.4% |
8,046 / 8,526 |
skills |
███████████████████░ 94.7% |
3,869 / 4,085 |
data_quality |
███████████████████░ 95.3% |
1,457 / 1,529 |
logs |
███████████████████░ 95.4% |
12,372 / 12,975 |
replay_vision |
███████████████████░ 95.6% |
21,019 / 21,996 |
experiments |
███████████████████░ 95.6% |
28,832 / 30,152 |
annotations |
███████████████████░ 96.2% |
732 / 761 |
revenue_analytics |
███████████████████░ 96.3% |
1,887 / 1,960 |
customer_analytics |
███████████████████░ 96.5% |
12,779 / 13,248 |
user_interviews |
███████████████████░ 96.5% |
2,638 / 2,734 |
feature_flags |
███████████████████░ 96.6% |
18,730 / 19,397 |
warehouse_sources |
███████████████████░ 97.5% |
391,616 / 401,660 |
data_catalog |
████████████████████ 97.8% |
2,746 / 2,808 |
pulse |
████████████████████ 98.4% |
2,017 / 2,049 |
Report-only. Patch coverage = changed backend lines covered vs origin/master. Sorted lowest first.
Known gaps: lines covered only by Temporal tests show as uncovered; core line numbers may drift if master changed the same file.
4fe0807 to
e1e3106
Compare
122eadb to
53d234b
Compare
53d234b to
90a387c
Compare
🦔 ReviewHog reviewed this pull requestFound 0 must fix, 4 should fix, 3 consider. Published 7 findings (view the review). |
|
ReviewHog Alpha 🦔 If you find any issues helpful - please reply "valid", "invalid", etc., for evaluation purposes 🙏 |
There was a problem hiding this comment.
ReviewHog Report
Business logic
Issues: 2 issues
Files (4)
products/tasks/backend/models.pyproducts/tasks/backend/facade/api.pyproducts/tasks/backend/presentation/views/api.pyproducts/tasks/mcp/tools.yaml
What were the main changes
- TaskRun.emit_conversation_cleared() writes the typed /clear message plus a _posthog/conversation_cleared marker straight into a finished run's log, so resume rebuilds an empty conversation past it
- facade.clear_task_run_conversation gates on run.is_terminal, returning not_found/not_terminal outcomes instead of racing a live agent's log writer
- New POST runs/{id}/clear_conversation/ endpoint: 200 with the updated run DTO on success, 404 if missing, 409 if the run is still active (send /clear to its agent instead)
- MCP tools.yaml registers the new operation, disabled by default like other run-mutation endpoints
Changes
Issues: 5 issues
Files (3)
products/desktop/packages/api-client/src/posthog-client.tsproducts/desktop/packages/core/src/sessions/sessionEvents.tsproducts/desktop/packages/core/src/sessions/sessionService.ts
Prompt To Fix All With AI### Issue 1
products/posthog_ai/frontend/logics/runStreamLogic.ts:2087-2092
**Capability state remains stale**
When a resume chain contains an earlier run with `conversationClear` enabled and a later run whose agent does not advertise it, this sticky reducer remains true and authorizes the terminal-run clear endpoint. The UI then displays “Conversation cleared,” but the incapable agent ignores the boundary on resume and restores the full conversation.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.Reviews (1): Last reviewed commit: "fix(tasks): address review findings on t..." | Re-trigger Greptile |
🦔 Hogbox preview · ✅ ready▶ Open the preview
commit |
|
React Doctor found no issues in the changed files. 🎉 Reviewed by React Doctor for commit |
There was a problem hiding this comment.
Pull request overview
Adds a dedicated “clear conversation” pathway for finished cloud task runs, avoiding the cost of spinning up a new sandbox just to execute /clear. This is implemented as a new backend endpoint that appends a /clear user turn plus a _posthog/conversation_cleared boundary marker to the run log, along with frontend + desktop rendering and capability-gated calling behavior.
Changes:
- Backend: add
POST /api/projects/:id/tasks/:task_id/runs/:run_id/clear_conversation/to record a/clearboundary only for terminal runs (409 for active runs). - Frontend (cloud thread): render
_posthog/conversation_cleared, handle “clearing”/“clearing_failed” status frames, and gate finished-run clears on the advertisedconversationClearcapability. - Desktop: add an API client method + SessionService shortcut to record the boundary and paint the cleared divider locally for finished cloud runs.
Reviewed changes
Copilot reviewed 19 out of 20 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| products/tasks/mcp/tools.yaml | Registers the new clear-conversation operation in MCP tools (disabled by default). |
| products/tasks/frontend/generated/api.ts | Adds generated API client function for the clear-conversation endpoint. |
| products/tasks/backend/tests/test_api.py | Adds backend tests for boundary recording, dedupe, and active-run rejection. |
| products/tasks/backend/presentation/views/api.py | Adds the clear_conversation DRF action with OpenAPI annotations. |
| products/tasks/backend/models.py | Adds log-writing helpers to append a /clear turn + conversation boundary marker. |
| products/tasks/backend/facade/api.py | Adds facade method to lock/validate terminal status and append boundary to the log. |
| products/posthog_ai/frontend/types/wireTypes.ts | Extends notification param typings for conversation-cleared and status error fields. |
| products/posthog_ai/frontend/types/wireTypes.test.ts | Extends type contract tests for new notification shapes. |
| products/posthog_ai/frontend/types/streamTypes.ts | Adds conversation_cleared to ThreadItemType and clarifies errorMessage usage. |
| products/posthog_ai/frontend/logics/runStreamLogic.ts | Updates log folding to render the boundary divider and handle clearing statuses/errors; tracks conversationClearSupported. |
| products/posthog_ai/frontend/logics/runStreamLogic.test.ts | Adds logic tests for capability precedence and clear divider/status behavior. |
| products/posthog_ai/frontend/logics/runInteractionLogic.ts | Routes /clear on terminal runs to the new endpoint when capability is supported; avoids wrapping /clear in context. |
| products/posthog_ai/frontend/logics/runInteractionLogic.test.ts | Adds tests for terminal-run clear shortcut and capability-gated fallback behavior. |
| products/posthog_ai/frontend/components/ThreadView.tsx | Adds height estimate for the new conversation_cleared thread item type. |
| products/posthog_ai/frontend/components/ThreadRow.tsx | Renders ConversationClearedItem for the new thread item type. |
| products/posthog_ai/frontend/components/ThreadItems.tsx | Implements UI for “Clearing…” status and “Conversation cleared” divider. |
| products/desktop/packages/core/src/sessions/sessionServiceCloudClear.test.ts | Adds desktop tests for finished-run /clear boundary shortcut and fallback. |
| products/desktop/packages/core/src/sessions/sessionService.ts | Adds finished-run /clear shortcut to call backend boundary endpoint and paint events locally. |
| products/desktop/packages/core/src/sessions/sessionEvents.ts | Adds helper to create the local events sequence for a finished-run clear boundary. |
| products/desktop/packages/api-client/src/posthog-client.ts | Adds API client method to call the clear-conversation endpoint with typed error handling. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
😎 Stack merged successfully - details. |
cca74da to
db71288
Compare
HostHog preview —
|
A live run's /clear goes to its agent. A finished one has no agent, and
resuming into a whole new run just to clear a conversation that run would
rebuild from the log anyway is wasteful, so the boundary is recorded against
the finished run instead: POST runs/{id}/clear_conversation appends the typed
message plus a _posthog/conversation_cleared marker to its log. The logs
endpoint serves a resume chain concatenated, so rehydration stops at the
marker and the next run continues with an empty conversation, its checkpoints
and visible history intact.
Only for a finished run — an active one has an agent that owns the clear, and
a live writer on the same log object this read-modify-write append would
race, so it returns 409. Repeat calls against a log already ending at the
boundary append nothing.
The web composer gates on the conversationClear capability from the latest
run_started frame and falls back to an ordinary new run when it is absent.
The thread renders the boundary and a "Clearing…" spinner, and /clear is sent
unwrapped: a context block would hide the command behind it.
Generated-By: PostHog Desktop
Task-Id: 2578f561-b94e-46ac-8546-d3368f5098bb
Generated-By: PostHog Desktop Task-Id: 2578f561-b94e-46ac-8546-d3368f5098bb
|
👋 Visual changes detected for this PR. Review and approve in PostHog Visual Review If these changes are unexpected, they may be caused by a flaky test or a broken snapshot on master. Don't approve — rerun the job or wait for a fix. |
db71288 to
7b043ea
Compare
extractRequestErrorMessage passed through any non-empty error/detail
string from the backend, including Django's generic {"detail":"Not
found."} for an unmatched route. On a pre-#76943 backend without the
clear_conversation endpoint, that surfaced /clear's failure as a bare
"Not found." with no indication a clear was attempted or what to do
next. Treat that literal DRF placeholder as non-actionable and fall
through to the endpoint's own fallback message plus status code.
Generated-By: PostHog Desktop
Task-Id: 2578f561-b94e-46ac-8546-d3368f5098bb
Problem
Follows #76457 (merged), which made
/clearwork on a live cloud run.A finished run is the other half, and most cloud runs are finished when you look at them. There's no agent to send
/clearto, so the composer treated it as an ordinary message and started a whole new run: boot a sandbox, resume the conversation, clear it, idle. A full run's cost to clear a conversation the next run would rebuild from the log anyway.The cloud thread also rendered none of it.
_posthog/conversation_clearedfell throughfoldLogToThread's catch-all, and the twoclearingstatus frames showed up as rawStatus: clearingrows.Changes
POST runs/{id}/clear_conversationappends the typed message plus a_posthog/conversation_clearedmarker to a finished run's log. Thelogsendpoint already serves a resume chain concatenated, so rehydration stops at the marker with no change: the next run continues the task with an empty conversation, and its checkpoints, artifacts, and visible history are untouched.Only for a finished run. An active one has an agent that owns the clear, and a live writer on the same log object this read-modify-write append would race, so it returns 409. Same reasoning as the note at
webhooks.py:245. A repeat call against a log already ending at the boundary appends nothing, and the append holds the run's row lock so a concurrent resume can't flip it active mid-write.The web composer gates on the
conversationClearcapability from the latestrun_startedand falls back to an ordinary new run when it's absent. The thread renders the boundary and a "Clearing…" spinner mirroring compaction, and/clearis sent unwrapped, since a context block would hide the command behind it.Note
The desktop client half lives in #82950 and merges after this deploys - the "Desktop backend coupling" check requires the split, because desktop releases aren't orchestrated with backend deploys and this endpoint must exist before a desktop build calls it.
How did you test this code?
Manually, against a local stack, with a seeded finished run:
I typed
/clearin the composer on a finished run and got the/clearbubble, the "Conversation cleared" divider, and the context ring at zero, through the real endpoint. I could not test the resume half or a live cloud run locally: both need a sandbox provider and a Temporal worker that a local stack doesn't have.Automated, run locally on this exact content: the three backend
clear_conversationtests, the three web suites (runStreamLogic,runInteractionLogic,wireTypes), frontend typecheck, and a kea typegen idempotence check.New tests, and the regression each catches:
test_clear_conversation_records_the_boundary- the marker lands with the typed message ahead of it, tagged for client replay, and carries nosessionId. If it ever gained one, resume would target a bogus session. Also covers the repeat-call no-op: without it, a double-submit stacks duplicate dividers.test_clear_conversation_rejects_an_active_run(queued, in_progress) - 409 and an untouched log. Without the guard this appends into a log with a live writer.runInteractionLogic.test.ts- with the capability absent, the composer starts an ordinary run and never calls the endpoint. This is the silent-wrong-behavior case.runStreamLogic.test.ts- the capability gate follows the latestrun_started, so an agent rollback mid-chain drops it instead of ratcheting true.Automatic notifications
Docs update
None needed. No user-facing docs cover
/clearyet.🤖 Agent context
Autonomy: Human-driven (agent-assisted)
Claude Code (PostHog Desktop session) fixed review findings from the bot reviewers, rebased the branch after #76457 squash-merged, and split the desktop client out to #82950 when the "Desktop backend coupling" check required it - the surviving content is what charlesvien approved, minus
products/desktop. Skills invoked: /stacking-prs, /writing-tests, /writing-code-comments, /writing-pr-descriptions, /resolve-conflicts, /address-pr-reviews.