Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions .claude/docs/plans/2026-03-26-issue-4900-ai-streaming-history.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Issue 4900: AI streaming history bloat

## Source of truth

- Source type: GitHub issue
- Source id: #4900
- Title: Streaming with withAIBatch accumulates operations and may slow undo
- URL: https://github.com/udecode/plate/issues/4900
- Task type: bug / performance

## Expected outcome

- Long AI streaming sessions should not build a giant undo batch that makes `tf.ai.undo()` or accept flows slower as chunk count grows.
- Keep current AI insert/chat behavior intact from a user point of view.

## Constraints and repo rules

- Non-trivial task: use repo-local planning file, not root planning files.
- Check institutional learnings before implementation.
- Use a sane test seam before the fix if possible.
- If `.ts` changes, verify with install -> build -> typecheck sequence for touched package(s), then `pnpm lint:fix`.

## Findings

- No relevant prior solution found in `.claude/docs/solutions/`.
- `withAIBatch` only merges batches and tags the last undo batch. It does not compact operations.
- Streaming insert mode is wrapped with `withAIBatch(..., { split: isFirst })` in the AI kit integration.
- `undoAI` currently relies on the last undo batch being tagged as AI and calls native `editor.undo()`.
- Accept/hide logic already distinguishes AI preview state from accepted content using AI marks and anchor cleanup.

## Working hypothesis

- The real bug is treating streamed preview updates as normal history.
- Better fix: keep preview streaming out of history, then finalize or discard preview explicitly.
- If preview is unsaved, accept likely needs to remove preview without saving, then insert the final accepted content as one normal batch.

## Next steps

1. Confirm accept/reject/reset paths needed for unsaved preview.
2. Add a failing test that proves streaming no longer bloats undo history.
3. Implement the smallest package-level fix.
4. Verify targeted tests, then package build -> typecheck -> lint.
19 changes: 19 additions & 0 deletions .claude/docs/plans/2026-03-26-pr-and-comment-4900.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# PR And Comment 4900

## Goal

Open or update the PR for the current checkout, then update the existing GitHub issue comment for issue `#4900` with the PR URL.

## Checklist

- [in_progress] Load the PR workflow and record the task plan
- [pending] Run `check`
- [pending] Inspect branch and PR state
- [pending] Commit and push the full current checkout
- [pending] Open or update the PR
- [pending] Update the existing `#4900` issue comment with the PR link

## Findings

- Repo rules require `check` before any PR create or update.
- Repo rules also require using the entire current checkout as-is, including unrelated changes.
19 changes: 19 additions & 0 deletions .claude/docs/plans/2026-03-26-task-skill-auto-pr-sync.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Task Skill Auto PR Sync

## Goal

Update the task skill so verified code-changing tracked work opens or updates the PR before any tracker comment, and any GitHub issue comment includes the PR URL.

## Checklist

- [completed] Read the current `task` skill source and adjacent skill/repo rules
- [completed] Update `.claude/skills/task/task.mdc` with PR-before-comment behavior
- [completed] Run the skill sync step
- [completed] Verify the generated task skill reflects the new rules

## Findings

- The current task skill explicitly says not to default to PR creation.
- The current GitHub sync-back section says not to mention PR mechanics in the issue comment.
- Repo rules already require `check` before PR creation, so the task skill should defer to that workflow instead of inventing a new one.
- `pnpm run prepare` runs `pnpm dlx skiller@latest apply`, which regenerated `.codex/skills/task/SKILL.md` with the new wording.
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
---
module: AI
date: 2026-03-26
problem_type: performance_issue
component: assistant
symptoms:
- "Long insert-mode AI streams make `tf.ai.undo()` slower as chunk count grows"
- "Accepting streamed AI output also gets slower after long responses"
- "The last AI undo batch contains one history entry but still stores a large number of underlying operations"
root_cause: logic_error
resolution_type: code_fix
severity: high
tags:
- ai
- streaming
- undo
- history
- withAIBatch
- streamInsertChunk
- performance
---

# AI streaming preview should snapshot before unsaved chunks

## Problem

Insert-mode AI streaming was wrapping every `streamInsertChunk` call in `withAIBatch`.

That looked reasonable because it kept the whole preview in one undo batch, but the batch still accumulated every streamed operation. Undo cost therefore scaled with chunk count instead of the final accepted content.

## Symptoms

- `tf.ai.undo()` became progressively slower after long streamed responses.
- Accepting insert-mode AI output also slowed down after long streams.
- History looked compact at a glance because there was only one undo batch, but that batch still held a large operations array.

## What Didn't Work

Reading `withAIBatch` in isolation was misleading. It only does two things:

1. merge into the current history batch
2. tag the batch as AI-generated

It does not compact prior operations.

Chasing `streamInsertChunk` alone was also the wrong level. The real problem was not the transform logic itself. The problem was treating streamed preview updates as normal history writes.

## Solution

Capture the editor state once before insert-mode streaming starts, stream preview chunks with `withoutSaving`, and only write history when the user accepts the final result.

The implementation had three parts:

### 1. Capture a pre-stream snapshot

```ts
captureAIStreamSnapshot(editor);

editor.tf.withoutSaving(() => {
editor.tf.insertNodes({
children: [{ text: '' }],
type: getPluginType(editor, KEYS.aiChat),
});
});
```

### 2. Keep streamed preview out of history

```ts
editor.tf.withoutSaving(() => {
if (!getOption('streaming')) return;

editor.tf.withScrolling(() => {
streamInsertChunk(editor, chunk, {
textProps: {
[getPluginType(editor, KEYS.ai)]: true,
},
});
});
});
```

### 3. Accept by restoring the snapshot, then committing the final value once

```ts
if (!commitAIStreamValue(editor, getAcceptedInsertValue(editor))) {
withAIBatch(editor, () => {
tf.ai.removeMarks();
editor.getTransforms(AIChatPlugin).aiChat.removeAnchor();
});
}
```

`tf.ai.undo()` also gained a snapshot restore fallback. If there is no AI-tagged history batch but AI preview content still exists, it restores the captured pre-stream state instead of trying to replay chunk history.

## Why This Works

Preview streaming and accepted editor history have different jobs:

- preview streaming needs responsive incremental rendering
- accepted editor history needs one sane undo step

Using one mechanism for both creates the slowdown. A merged history batch is still a transcript of every chunk. Restoring a snapshot avoids that transcript entirely.

The accept path then turns the preview into one fresh history entry whose cost scales with the final document diff, not with how many network chunks arrived on the way there.

## Prevention

- Do not use `withAIBatch` for insert-mode preview streaming. Use it for saved AI edits, not for chunk-by-chunk preview rendering.
- If streamed content is disposable preview state, snapshot first and stream with `withoutSaving`.
- When accept should remain undoable, restore the snapshot and commit the final accepted value in one new batch.
- Test both sides of the flow:
- preview streaming should leave history empty before accept
- accept should create one compact undoable batch
- `tf.ai.undo()` should restore the original pre-stream value when preview is still present
22 changes: 17 additions & 5 deletions .claude/skills/task/task.mdc
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ Handle $ARGUMENTS. Be thorough, not ceremonial. Start from the source of truth,
- Prefer targeted tests and checks during iteration.
- Keep the user updated at milestones.
- Verify the actual result before claiming done.
- Do not default to research swarms, review swarms, browser proof, PR creation, or compounding.
- Do not default to research swarms, review swarms, or browser proof.
- For verified code-changing work, default to creating or updating the PR unless the user explicitly said not to.
- Do not default to compounding.

## Intake

Expand Down Expand Up @@ -83,7 +85,8 @@ Apply this section only when the task source is a tracker item.
- Use `gh` for fetch and sync-back.
- If useful, rename the thread to `<issue-number> <issue-title>`.
- If the task is code-changing, prefer a branch name that includes the issue number.
- If the task reaches a meaningful outcome and came from the issue, post a concise issue comment unless blocked or the user said not to.
- If the task changed code and reached a verified meaningful outcome, create or update the PR before any issue comment unless blocked or the user said not to.
- If the task reaches a meaningful outcome and came from the issue, post a concise issue comment after the PR exists unless blocked or the user said not to.

### Linear

Expand All @@ -94,7 +97,7 @@ Apply this section only when the task source is a tracker item.

### Tracked Task Non-Rules

- Do not require PR creation for every tracked task.
- Do not require PR creation for tracker tasks that did not change code, ended blocked, or were purely investigative.
- Do not require browser screenshots for every tracked task.
- Do not require tracker comments for investigations that ended blocked or inconclusive unless sync-back is useful.

Expand Down Expand Up @@ -122,6 +125,9 @@ Apply this section only when the task source is a tracker item.
- `agent-browser` or `test-browser`
Use only when there is a real browser surface to verify.
Require real browser proof only for browser or UI tasks.
- `git-commit-push-pr`
Use when verified work changed code and should ship as a PR.
Create or update the PR before any tracker comment.
- `ce-compound`
Use only after verified, non-trivial work that produced reusable knowledge.
Never load it at the start.
Expand Down Expand Up @@ -188,6 +194,7 @@ Keep verification mandatory but proportional.
- Run browser verification only for browser or UI tasks.
- Run broader repo-wide gates only when repo instructions require them or the change scope justifies them.
- If the repo has a standard final gate, run it last.
- If verified work changed code, create or update the PR before tracker sync-back unless the user explicitly said not to.
- If the task came from a tracked issue and the task reached a meaningful outcome, sync back unless the user said not to.
- If UI changed, capture proof from the real browser surface.
- Do not hardcode PR creation, screenshots, or tracker comments for every task.
Expand Down Expand Up @@ -237,14 +244,17 @@ Apply this section only when the task came from a tracker item and reached a mea
- Keep it focused on:
- reproduced or baselined, when relevant
- fixed or implemented
- PR: <full PR URL>, when one exists
- re-verified, with browser mention only when relevant
- remaining caveat, if any
- Do not mention:
- file names
- tests, typecheck, or lint
- screenshot paths
- branch names
- PR mechanics
- commit, push, or staging mechanics
- Do not write the issue comment before the PR exists.
- If writing the comment after code-changing work, include the full PR URL.
- Start only the first sentence with `Codex ...`.
- Italicize each paragraph separately.

Expand All @@ -253,6 +263,8 @@ Example:
```md
_Codex implemented and verified this issue._

_PR: https://github.com/owner/repo/pull/123._

_Reproduced the bug, applied the fix, and re-verified the affected flow._

_Remaining caveat: none._
Expand Down Expand Up @@ -286,4 +298,4 @@ _Remaining caveat: none._
- Verification matched the change scope.
- Final handoff matched the task type.
- Testing or batch handoff reported the completed slice, verification, and remaining queue when relevant.
- Any tracker, browser, review, or compound follow-up was done only if actually relevant.
- Any tracker, browser, review, or compound follow-up was done only if actually relevant.
21 changes: 17 additions & 4 deletions .codex/skills/task/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ Handle $ARGUMENTS. Be thorough, not ceremonial. Start from the source of truth,
- Prefer targeted tests and checks during iteration.
- Keep the user updated at milestones.
- Verify the actual result before claiming done.
- Do not default to research swarms, review swarms, browser proof, PR creation, or compounding.
- Do not default to research swarms, review swarms, or browser proof.
- For verified code-changing work, default to creating or updating the PR unless the user explicitly said not to.
- Do not default to compounding.

## Intake

Expand Down Expand Up @@ -90,7 +92,8 @@ Apply this section only when the task source is a tracker item.
- Use `gh` for fetch and sync-back.
- If useful, rename the thread to `<issue-number> <issue-title>`.
- If the task is code-changing, prefer a branch name that includes the issue number.
- If the task reaches a meaningful outcome and came from the issue, post a concise issue comment unless blocked or the user said not to.
- If the task changed code and reached a verified meaningful outcome, create or update the PR before any issue comment unless blocked or the user said not to.
- If the task reaches a meaningful outcome and came from the issue, post a concise issue comment after the PR exists unless blocked or the user said not to.

### Linear

Expand All @@ -101,7 +104,7 @@ Apply this section only when the task source is a tracker item.

### Tracked Task Non-Rules

- Do not require PR creation for every tracked task.
- Do not require PR creation for tracker tasks that did not change code, ended blocked, or were purely investigative.
- Do not require browser screenshots for every tracked task.
- Do not require tracker comments for investigations that ended blocked or inconclusive unless sync-back is useful.

Expand Down Expand Up @@ -129,6 +132,9 @@ Apply this section only when the task source is a tracker item.
- `agent-browser` or `test-browser`
Use only when there is a real browser surface to verify.
Require real browser proof only for browser or UI tasks.
- `git-commit-push-pr`
Use when verified work changed code and should ship as a PR.
Create or update the PR before any tracker comment.
- `ce-compound`
Use only after verified, non-trivial work that produced reusable knowledge.
Never load it at the start.
Expand Down Expand Up @@ -195,6 +201,7 @@ Keep verification mandatory but proportional.
- Run browser verification only for browser or UI tasks.
- Run broader repo-wide gates only when repo instructions require them or the change scope justifies them.
- If the repo has a standard final gate, run it last.
- If verified work changed code, create or update the PR before tracker sync-back unless the user explicitly said not to.
- If the task came from a tracked issue and the task reached a meaningful outcome, sync back unless the user said not to.
- If UI changed, capture proof from the real browser surface.
- Do not hardcode PR creation, screenshots, or tracker comments for every task.
Expand Down Expand Up @@ -244,14 +251,17 @@ Apply this section only when the task came from a tracker item and reached a mea
- Keep it focused on:
- reproduced or baselined, when relevant
- fixed or implemented
- PR: <full PR URL>, when one exists
- re-verified, with browser mention only when relevant
- remaining caveat, if any
- Do not mention:
- file names
- tests, typecheck, or lint
- screenshot paths
- branch names
- PR mechanics
- commit, push, or staging mechanics
- Do not write the issue comment before the PR exists.
- If writing the comment after code-changing work, include the full PR URL.
- Start only the first sentence with `Codex ...`.
- Italicize each paragraph separately.

Expand All @@ -260,6 +270,8 @@ Example:
```md
_Codex implemented and verified this issue._

_PR: https://github.com/owner/repo/pull/123._

_Reproduced the bug, applied the fix, and re-verified the affected flow._

_Remaining caveat: none._
Expand Down Expand Up @@ -294,3 +306,4 @@ _Remaining caveat: none._
- Final handoff matched the task type.
- Testing or batch handoff reported the completed slice, verification, and remaining queue when relevant.
- Any tracker, browser, review, or compound follow-up was done only if actually relevant.

2 changes: 1 addition & 1 deletion apps/www/public/r/ai-docs.json

Large diffs are not rendered by default.

Loading
Loading