@bastani/atomic 0.8.30-alpha.1 → 0.8.30-alpha.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +4 -0
- package/dist/builtin/cursor/package.json +2 -2
- package/dist/builtin/intercom/package.json +1 -1
- package/dist/builtin/mcp/package.json +1 -1
- package/dist/builtin/subagents/package.json +1 -1
- package/dist/builtin/web-access/package.json +1 -1
- package/dist/builtin/workflows/CHANGELOG.md +1 -0
- package/dist/builtin/workflows/README.md +1 -1
- package/dist/builtin/workflows/package.json +1 -1
- package/dist/builtin/workflows/src/runs/foreground/executor.ts +19 -10
- package/dist/core/anthropic-thinking-guard.d.ts +15 -0
- package/dist/core/anthropic-thinking-guard.d.ts.map +1 -0
- package/dist/core/anthropic-thinking-guard.js +205 -0
- package/dist/core/anthropic-thinking-guard.js.map +1 -0
- package/dist/core/compaction/compaction.d.ts +8 -2
- package/dist/core/compaction/compaction.d.ts.map +1 -1
- package/dist/core/compaction/compaction.js +19 -3
- package/dist/core/compaction/compaction.js.map +1 -1
- package/dist/core/compaction/context-compaction.d.ts.map +1 -1
- package/dist/core/compaction/context-compaction.js +84 -14
- package/dist/core/compaction/context-compaction.js.map +1 -1
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +15 -3
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +22 -28
- package/dist/core/session-manager.js.map +1 -1
- package/dist/modes/interactive/components/context-compaction-summary-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/context-compaction-summary-message.js +2 -2
- package/dist/modes/interactive/components/context-compaction-summary-message.js.map +1 -1
- package/docs/compaction.md +8 -5
- package/docs/session-format.md +1 -1
- package/docs/workflows.md +2 -0
- package/package.json +2 -2
|
@@ -150,7 +150,7 @@ What Survives:
|
|
|
150
150
|
- User instructions: The original task and any clarifications.
|
|
151
151
|
|
|
152
152
|
Conditionally Deleted:
|
|
153
|
-
- Old Reasoning decisions: If there is nothing else to remove and the target reduction is not met, you can remove
|
|
153
|
+
- Old Reasoning decisions: If there is nothing else to remove and the target reduction is not met, you can remove entire stale assistant entries, EXCEPT do not delete individual content blocks from any retained assistant message that contains thinking or redacted_thinking blocks. Thinking-bearing assistant messages are all-or-nothing for replay safety.
|
|
154
154
|
|
|
155
155
|
<output_format>
|
|
156
156
|
Call the context_delete tool one or more times with deletion targets in this shape:
|
|
@@ -525,7 +525,7 @@ function formatProtectedToolDependencyError(transcript, blockedTarget, context)
|
|
|
525
525
|
function isProtectedContextDeletionErrorMessage(message) {
|
|
526
526
|
return (/\bprotected\b/i.test(message) ||
|
|
527
527
|
/Cannot delete (?:recent context entry|content block .* because entry .* is one of the last)/u.test(message) ||
|
|
528
|
-
/latest assistant message|thinking\/redacted_thinking block in the latest assistant message/u.test(message));
|
|
528
|
+
/latest assistant message|thinking\/redacted_thinking block in (?:the latest|a retained) assistant message/u.test(message));
|
|
529
529
|
}
|
|
530
530
|
function assertNoRecentContextDeletionTargets(transcript, targets) {
|
|
531
531
|
const recentEntryIds = getRecentContextEntryIds(transcript);
|
|
@@ -535,29 +535,63 @@ function assertNoRecentContextDeletionTargets(transcript, targets) {
|
|
|
535
535
|
}
|
|
536
536
|
}
|
|
537
537
|
}
|
|
538
|
-
function latestAssistantEntry(transcript) {
|
|
538
|
+
function latestAssistantEntry(transcript, deletedEntryIds = new Set()) {
|
|
539
539
|
for (let index = transcript.entries.length - 1; index >= 0; index--) {
|
|
540
540
|
const entry = transcript.entries[index];
|
|
541
|
-
if (entry.role === "assistant")
|
|
541
|
+
if (entry.role === "assistant" && !deletedEntryIds.has(entry.entryId))
|
|
542
542
|
return entry;
|
|
543
543
|
}
|
|
544
544
|
return undefined;
|
|
545
545
|
}
|
|
546
|
-
function
|
|
547
|
-
const
|
|
548
|
-
if (!latestAssistant || !assistantEntryHasThinkingContentBlock(latestAssistant))
|
|
549
|
-
return;
|
|
546
|
+
function findAssistantThinkingContentBlockDeletionViolation(transcript, targets) {
|
|
547
|
+
const deletedEntryIds = getDeletedEntryIds(targets);
|
|
550
548
|
for (const target of targets) {
|
|
551
|
-
if (target.
|
|
549
|
+
if (target.kind !== "content_block")
|
|
552
550
|
continue;
|
|
551
|
+
if (deletedEntryIds.has(target.entryId))
|
|
552
|
+
continue;
|
|
553
|
+
const entry = findTranscriptEntry(transcript, target.entryId);
|
|
554
|
+
if (entry && assistantEntryHasThinkingContentBlock(entry))
|
|
555
|
+
return target;
|
|
556
|
+
}
|
|
557
|
+
return undefined;
|
|
558
|
+
}
|
|
559
|
+
function findLatestAssistantThinkingDeletionViolation(transcript, targets) {
|
|
560
|
+
const deletedEntryIds = getDeletedEntryIds(targets);
|
|
561
|
+
const latestRetainedAssistant = latestAssistantEntry(transcript, deletedEntryIds);
|
|
562
|
+
for (const target of targets) {
|
|
553
563
|
if (target.kind === "entry") {
|
|
554
|
-
|
|
564
|
+
const entry = findTranscriptEntry(transcript, target.entryId);
|
|
565
|
+
if (!entry || !assistantEntryHasThinkingContentBlock(entry))
|
|
566
|
+
continue;
|
|
567
|
+
const deletedEntryIdsIfTargetWereKept = new Set(deletedEntryIds);
|
|
568
|
+
deletedEntryIdsIfTargetWereKept.delete(target.entryId);
|
|
569
|
+
if (latestAssistantEntry(transcript, deletedEntryIdsIfTargetWereKept)?.entryId === target.entryId) {
|
|
570
|
+
return target;
|
|
571
|
+
}
|
|
572
|
+
continue;
|
|
555
573
|
}
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
574
|
+
if (latestRetainedAssistant?.entryId === target.entryId &&
|
|
575
|
+
assistantEntryHasThinkingContentBlock(latestRetainedAssistant)) {
|
|
576
|
+
return target;
|
|
559
577
|
}
|
|
560
578
|
}
|
|
579
|
+
return undefined;
|
|
580
|
+
}
|
|
581
|
+
function assertNoAssistantThinkingContentBlockDeletionTargets(transcript, targets) {
|
|
582
|
+
const violation = findAssistantThinkingContentBlockDeletionViolation(transcript, targets);
|
|
583
|
+
if (!violation)
|
|
584
|
+
return;
|
|
585
|
+
throw new Error(`Cannot delete content block ${violation.entryId}:${violation.blockIndex} because a thinking/redacted_thinking block in a retained assistant message must remain unmodified; retained assistant messages containing thinking/redacted_thinking content blocks are all-or-nothing`);
|
|
586
|
+
}
|
|
587
|
+
function assertNoLatestAssistantThinkingDeletionTargets(transcript, targets) {
|
|
588
|
+
const violation = findLatestAssistantThinkingDeletionViolation(transcript, targets);
|
|
589
|
+
if (!violation)
|
|
590
|
+
return;
|
|
591
|
+
if (violation.kind === "entry") {
|
|
592
|
+
throw new Error(`Cannot delete assistant entry ${violation.entryId} because it is the latest assistant message retained after other deletions and contains thinking/redacted_thinking content blocks`);
|
|
593
|
+
}
|
|
594
|
+
throw new Error(`Cannot delete content block ${violation.entryId}:${violation.blockIndex} because a thinking/redacted_thinking block in the latest assistant message must remain unmodified; the latest retained assistant message contains thinking/redacted_thinking content blocks`);
|
|
561
595
|
}
|
|
562
596
|
function isToolCallBlockDeleted(entry, callId, deletedEntryIds, deletedContentBlocks) {
|
|
563
597
|
if (deletedEntryIds.has(entry.entryId))
|
|
@@ -615,6 +649,11 @@ function canonicalizeEntryTargets(transcript, targets, entry) {
|
|
|
615
649
|
return deleteEntryTarget(targets, entry.entryId);
|
|
616
650
|
}
|
|
617
651
|
function addToolCallDeletion(transcript, targets, entry, callId) {
|
|
652
|
+
if (assistantEntryHasThinkingContentBlock(entry)) {
|
|
653
|
+
if (!canDeleteTarget(transcript, { kind: "entry", entryId: entry.entryId }))
|
|
654
|
+
return false;
|
|
655
|
+
return deleteEntryTarget(targets, entry.entryId);
|
|
656
|
+
}
|
|
618
657
|
let changed = false;
|
|
619
658
|
for (const blockIndex of toolCallBlockIndexes(entry, callId)) {
|
|
620
659
|
const target = { kind: "content_block", entryId: entry.entryId, blockIndex };
|
|
@@ -685,7 +724,9 @@ function reconcileToolDependencies(transcript, initialTargets) {
|
|
|
685
724
|
continue;
|
|
686
725
|
recordChange(deleteEntryTarget(targets, result.entryId));
|
|
687
726
|
const callEntryTarget = { kind: "entry", entryId: callEntry.entryId };
|
|
688
|
-
const callBlockTarget =
|
|
727
|
+
const callBlockTarget = assistantEntryHasThinkingContentBlock(callEntry)
|
|
728
|
+
? callEntryTarget
|
|
729
|
+
: firstToolCallBlockTarget(callEntry, callId) ?? callEntryTarget;
|
|
689
730
|
if (!canDeleteTarget(transcript, callBlockTarget)) {
|
|
690
731
|
if (isRecentTarget(transcript, callBlockTarget)) {
|
|
691
732
|
throw new Error(formatRecentContextDeletionError(transcript, callBlockTarget));
|
|
@@ -869,6 +910,7 @@ export function validateContextDeletionRequest(request, transcript) {
|
|
|
869
910
|
// Tool reconciliation can add targets after the per-request checks above, so
|
|
870
911
|
// these post-reconcile assertions remain authoritative.
|
|
871
912
|
assertNoRecentContextDeletionTargets(transcript, reconciledTargets);
|
|
913
|
+
assertNoAssistantThinkingContentBlockDeletionTargets(transcript, reconciledTargets);
|
|
872
914
|
assertNoLatestAssistantThinkingDeletionTargets(transcript, reconciledTargets);
|
|
873
915
|
const reconciledDeletedEntryIds = getDeletedEntryIds(reconciledTargets);
|
|
874
916
|
for (const target of reconciledTargets) {
|
|
@@ -1075,6 +1117,34 @@ function filterProtectedGrepCandidates(candidates, matches, currentTargets, tran
|
|
|
1075
1117
|
eligibleMatches.push(match);
|
|
1076
1118
|
}
|
|
1077
1119
|
}
|
|
1120
|
+
// Some latest-assistant thinking violations only become visible after a grep batch also
|
|
1121
|
+
// deletes newer assistant entries. Classify the newly-unsafe grep candidates as
|
|
1122
|
+
// protected/skipped before maxMatches, expectedMatchCount, stats, or removals are computed.
|
|
1123
|
+
let changed = true;
|
|
1124
|
+
while (changed) {
|
|
1125
|
+
changed = false;
|
|
1126
|
+
const mergedTargets = mergeContextDeletionTargets(currentTargets, eligibleCandidates);
|
|
1127
|
+
const violation = findLatestAssistantThinkingDeletionViolation(transcript, mergedTargets);
|
|
1128
|
+
if (!violation)
|
|
1129
|
+
continue;
|
|
1130
|
+
const violationKey = targetKey(violation);
|
|
1131
|
+
let violationIndex = eligibleCandidates.findIndex((candidate) => targetKey(candidate) === violationKey);
|
|
1132
|
+
if (violationIndex < 0) {
|
|
1133
|
+
violationIndex = eligibleCandidates.findIndex((_candidate, candidateIndex) => {
|
|
1134
|
+
const remainingCandidates = eligibleCandidates.filter((_candidateToKeep, index) => index !== candidateIndex);
|
|
1135
|
+
const remainingTargets = mergeContextDeletionTargets(currentTargets, remainingCandidates);
|
|
1136
|
+
const remainingViolation = findLatestAssistantThinkingDeletionViolation(transcript, remainingTargets);
|
|
1137
|
+
return !remainingViolation || targetKey(remainingViolation) !== violationKey;
|
|
1138
|
+
});
|
|
1139
|
+
}
|
|
1140
|
+
if (violationIndex < 0)
|
|
1141
|
+
continue;
|
|
1142
|
+
const [skippedMatch] = eligibleMatches.splice(violationIndex, 1);
|
|
1143
|
+
eligibleCandidates.splice(violationIndex, 1);
|
|
1144
|
+
if (skippedMatch)
|
|
1145
|
+
pushProtectedGrepSkip(skipped, skippedMatch);
|
|
1146
|
+
changed = true;
|
|
1147
|
+
}
|
|
1078
1148
|
return { candidates: eligibleCandidates, matches: eligibleMatches };
|
|
1079
1149
|
}
|
|
1080
1150
|
function copyDeletionTarget(target) {
|