@bastani/atomic 0.8.27 → 0.8.28-alpha.1
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 +22 -0
- package/dist/builtin/intercom/package.json +1 -1
- package/dist/builtin/mcp/package.json +2 -2
- package/dist/builtin/subagents/package.json +1 -1
- package/dist/builtin/web-access/package.json +1 -1
- package/dist/builtin/workflows/CHANGELOG.md +14 -0
- package/dist/builtin/workflows/README.md +11 -9
- package/dist/builtin/workflows/package.json +1 -1
- package/dist/builtin/workflows/src/authoring.d.ts +5 -2
- package/dist/builtin/workflows/src/extension/background-ui-adapter.ts +3 -1
- package/dist/builtin/workflows/src/extension/hil-answer-notifications.ts +17 -25
- package/dist/builtin/workflows/src/extension/index.ts +133 -18
- package/dist/builtin/workflows/src/extension/render-result.ts +22 -2
- package/dist/builtin/workflows/src/extension/workflow-schema.ts +3 -3
- package/dist/builtin/workflows/src/runs/foreground/executor.ts +210 -16
- package/dist/builtin/workflows/src/sdk-surface.ts +1 -1
- package/dist/builtin/workflows/src/shared/authoring-contract.d.ts +42 -5
- package/dist/builtin/workflows/src/shared/store-types.ts +8 -2
- package/dist/builtin/workflows/src/shared/store.ts +51 -0
- package/dist/builtin/workflows/src/shared/types.ts +14 -4
- package/dist/builtin/workflows/src/tui/graph-view.ts +4 -1
- package/dist/builtin/workflows/src/tui/prompt-card.ts +6 -0
- package/dist/builtin/workflows/src/tui/stage-chat-view.ts +11 -1
- package/dist/core/agent-session.d.ts +4 -4
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +147 -31
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/auth-guidance.d.ts +10 -1
- package/dist/core/auth-guidance.d.ts.map +1 -1
- package/dist/core/auth-guidance.js +26 -1
- package/dist/core/auth-guidance.js.map +1 -1
- package/dist/core/compaction/branch-summarization.d.ts +2 -2
- package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
- package/dist/core/compaction/branch-summarization.js +7 -7
- package/dist/core/compaction/branch-summarization.js.map +1 -1
- package/dist/core/compaction/compaction.d.ts +4 -84
- package/dist/core/compaction/compaction.d.ts.map +1 -1
- package/dist/core/compaction/compaction.js +3 -479
- 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 +39 -82
- package/dist/core/compaction/context-compaction.js.map +1 -1
- package/dist/core/compaction/index.d.ts +1 -1
- package/dist/core/compaction/index.d.ts.map +1 -1
- package/dist/core/compaction/index.js +1 -1
- package/dist/core/compaction/index.js.map +1 -1
- package/dist/core/extensions/types.d.ts +10 -8
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/index.d.ts +1 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js.map +1 -1
- package/dist/core/messages.d.ts +1 -11
- package/dist/core/messages.d.ts.map +1 -1
- package/dist/core/messages.js +10 -25
- package/dist/core/messages.js.map +1 -1
- package/dist/core/session-manager.d.ts +5 -8
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +12 -76
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/settings-manager.d.ts +0 -3
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +0 -4
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/dist/modes/interactive/components/chat-message-renderer.d.ts +1 -5
- package/dist/modes/interactive/components/chat-message-renderer.d.ts.map +1 -1
- package/dist/modes/interactive/components/chat-message-renderer.js +5 -9
- package/dist/modes/interactive/components/chat-message-renderer.js.map +1 -1
- package/dist/modes/interactive/components/chat-session-host.d.ts.map +1 -1
- package/dist/modes/interactive/components/chat-session-host.js +0 -3
- package/dist/modes/interactive/components/chat-session-host.js.map +1 -1
- package/dist/modes/interactive/components/index.d.ts +0 -1
- package/dist/modes/interactive/components/index.d.ts.map +1 -1
- package/dist/modes/interactive/components/index.js +0 -1
- package/dist/modes/interactive/components/index.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +4 -27
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-client.d.ts +1 -1
- package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-client.js +2 -2
- package/dist/modes/rpc/rpc-client.js.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +1 -1
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-types.d.ts +0 -1
- package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-types.js.map +1 -1
- package/docs/compaction.md +210 -181
- package/docs/extensions.md +31 -20
- package/docs/json.md +3 -4
- package/docs/session-format.md +12 -21
- package/docs/sessions.md +3 -1
- package/docs/settings.md +2 -5
- package/docs/workflows.md +11 -9
- package/examples/extensions/README.md +1 -1
- package/examples/extensions/custom-compaction.ts +43 -106
- package/examples/extensions/handoff.ts +6 -44
- package/examples/extensions/trigger-compact.ts +5 -4
- package/package.json +5 -5
- package/dist/modes/interactive/components/compaction-summary-message.d.ts +0 -16
- package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +0 -1
- package/dist/modes/interactive/components/compaction-summary-message.js +0 -43
- package/dist/modes/interactive/components/compaction-summary-message.js.map +0 -1
|
@@ -20,9 +20,9 @@ import { stripFrontmatter } from "../utils/frontmatter.js";
|
|
|
20
20
|
import { resolvePath } from "../utils/paths.js";
|
|
21
21
|
import { sleep } from "../utils/sleep.js";
|
|
22
22
|
import { ATOMIC_GUIDE_COMMAND_NAME, ATOMIC_GUIDE_HELP_CHOICES, atomicGuideModeForChoice, getAtomicGuideMessage, isAtomicGuideHelpChoice, normalizeAtomicGuideMode, } from "./atomic-guide-command.js";
|
|
23
|
-
import { formatNoApiKeyFoundMessage, formatNoModelSelectedMessage } from "./auth-guidance.js";
|
|
23
|
+
import { formatNoApiKeyFoundMessage, formatNoModelSelectedMessage, formatUnresolvedModelMessage, } from "./auth-guidance.js";
|
|
24
24
|
import { executeBashWithOperations } from "./bash-executor.js";
|
|
25
|
-
import { calculateContextTokens, collectEntriesForBranchSummary, contextCompact as runContextCompact, estimateContextTokens, generateBranchSummary, prepareContextCompaction, shouldCompact, } from "./compaction/index.js";
|
|
25
|
+
import { calculateContextTokens, collectEntriesForBranchSummary, contextCompact as runContextCompact, estimateContextTokens, generateBranchSummary, prepareContextCompaction, shouldCompact, validateContextDeletionRequest, } from "./compaction/index.js";
|
|
26
26
|
import { DEFAULT_THINKING_LEVEL } from "./defaults.js";
|
|
27
27
|
import { exportSessionToHtml } from "./export-html/index.js";
|
|
28
28
|
import { createToolHtmlRenderer } from "./export-html/tool-renderer.js";
|
|
@@ -35,6 +35,15 @@ import { buildSystemPrompt } from "./system-prompt.js";
|
|
|
35
35
|
import { createLocalBashOperations } from "./tools/bash.js";
|
|
36
36
|
import { createAllToolDefinitions, defaultToolNames } from "./tools/index.js";
|
|
37
37
|
import { createToolDefinitionFromAgentTool } from "./tools/tool-definition-wrapper.js";
|
|
38
|
+
function deepFreeze(value) {
|
|
39
|
+
if (value && typeof value === "object") {
|
|
40
|
+
Object.freeze(value);
|
|
41
|
+
for (const nested of Object.values(value)) {
|
|
42
|
+
deepFreeze(nested);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return value;
|
|
46
|
+
}
|
|
38
47
|
/**
|
|
39
48
|
* Parse a skill block from message text.
|
|
40
49
|
* Returns null if the text doesn't contain a skill block.
|
|
@@ -357,7 +366,7 @@ export class AgentSession {
|
|
|
357
366
|
// Regular LLM message - persist as SessionMessageEntry
|
|
358
367
|
this.sessionManager.appendMessage(event.message);
|
|
359
368
|
}
|
|
360
|
-
// Other message types (bashExecution,
|
|
369
|
+
// Other message types (bashExecution, branchSummary) are persisted elsewhere
|
|
361
370
|
// Track assistant message for auto-compaction (checked on agent_end)
|
|
362
371
|
if (event.message.role === "assistant") {
|
|
363
372
|
this._lastAssistantMessage = event.message;
|
|
@@ -824,6 +833,15 @@ export class AgentSession {
|
|
|
824
833
|
if (!this.model) {
|
|
825
834
|
throw new Error(formatNoModelSelectedMessage());
|
|
826
835
|
}
|
|
836
|
+
// Defensive guard: a model that never resolved to a real provider
|
|
837
|
+
// (for example an unknown/unresolved model id that reached this path
|
|
838
|
+
// as a bare string) has no `provider`, which would otherwise fail deep
|
|
839
|
+
// in auth resolution as the confusing "No API key found for undefined".
|
|
840
|
+
// Surface a clear, accurate "unknown model" error instead.
|
|
841
|
+
const resolvedProvider = this.model.provider;
|
|
842
|
+
if (typeof resolvedProvider !== "string" || resolvedProvider.length === 0) {
|
|
843
|
+
throw new Error(formatUnresolvedModelMessage(this.model));
|
|
844
|
+
}
|
|
827
845
|
if (!this._modelRegistry.hasConfiguredAuth(this.model)) {
|
|
828
846
|
const isOAuth = this._modelRegistry.isUsingOAuth(this.model);
|
|
829
847
|
if (isOAuth) {
|
|
@@ -1483,6 +1501,9 @@ export class AgentSession {
|
|
|
1483
1501
|
if (!this.model) {
|
|
1484
1502
|
throw new Error(formatNoModelSelectedMessage());
|
|
1485
1503
|
}
|
|
1504
|
+
// Capture the narrowed model now (control-flow narrowing holds immediately after the
|
|
1505
|
+
// guard) so the lazy planner-fallback closure below can use a non-undefined model.
|
|
1506
|
+
const model = this.model;
|
|
1486
1507
|
const pathEntries = this.sessionManager.getBranch();
|
|
1487
1508
|
const settings = this.settingsManager.getCompactionSettings();
|
|
1488
1509
|
const mode = options.mode ?? "standard";
|
|
@@ -1490,28 +1511,118 @@ export class AgentSession {
|
|
|
1490
1511
|
if (!preparation) {
|
|
1491
1512
|
return undefined;
|
|
1492
1513
|
}
|
|
1493
|
-
|
|
1514
|
+
// Planner fallback used when no extension supplies a deletionRequest. Auth is resolved
|
|
1515
|
+
// lazily here so extension-provided deletion requests keep working offline. Returns
|
|
1516
|
+
// undefined when auth is unavailable (auto-mode resolvers), signaling a no-op compaction.
|
|
1517
|
+
const runPlanner = async () => {
|
|
1518
|
+
const auth = await options.resolvePlannerAuth();
|
|
1519
|
+
if (!auth)
|
|
1520
|
+
return undefined;
|
|
1521
|
+
return runContextCompact(preparation, model, auth.apiKey, auth.headers, options.abortController.signal, this.thinkingLevel, mode);
|
|
1522
|
+
};
|
|
1523
|
+
// Emit session_before_compact to allow extensions to cancel or provide a deletion request.
|
|
1524
|
+
// This happens BEFORE any auth resolution so local extension deletion requests work
|
|
1525
|
+
// without configured API credentials.
|
|
1526
|
+
let fromExtension = false;
|
|
1527
|
+
let validated;
|
|
1528
|
+
if (this._extensionRunner.hasHandlers("session_before_compact")) {
|
|
1529
|
+
// Deep-clone the preparation only when a before-compact handler actually exists. Extensions
|
|
1530
|
+
// receive an isolated, frozen snapshot so they cannot mutate protection metadata
|
|
1531
|
+
// (protectedEntryIds, entry .protected flags, etc.) on the internal preparation used for
|
|
1532
|
+
// validation. Building it lazily avoids deep-cloning the transcript — largest exactly when
|
|
1533
|
+
// compaction fires — on the common no-extension path.
|
|
1534
|
+
let extensionPreparation;
|
|
1535
|
+
try {
|
|
1536
|
+
extensionPreparation = deepFreeze(structuredClone(preparation));
|
|
1537
|
+
}
|
|
1538
|
+
catch (error) {
|
|
1539
|
+
// structuredClone only throws if an entry carries a non-cloneable value (a function or a
|
|
1540
|
+
// class instance). Transcript entries are plain data today, so this guards a latent
|
|
1541
|
+
// invariant: surface a clear error instead of letting a raw DataCloneError abort an
|
|
1542
|
+
// otherwise-viable compaction.
|
|
1543
|
+
throw new Error(`Failed to snapshot transcript for compaction extensions: ${error instanceof Error ? error.message : String(error)}`);
|
|
1544
|
+
}
|
|
1545
|
+
const hookResult = (await this._extensionRunner.emit({
|
|
1546
|
+
type: "session_before_compact",
|
|
1547
|
+
reason: options.reason,
|
|
1548
|
+
mode,
|
|
1549
|
+
preparation: extensionPreparation,
|
|
1550
|
+
branchEntries: pathEntries,
|
|
1551
|
+
signal: options.abortController.signal,
|
|
1552
|
+
}));
|
|
1553
|
+
if (hookResult?.cancel) {
|
|
1554
|
+
throw new Error("Compaction cancelled");
|
|
1555
|
+
}
|
|
1556
|
+
if (hookResult?.deletionRequest) {
|
|
1557
|
+
const extensionDeletionRequest = hookResult.deletionRequest;
|
|
1558
|
+
// Reject empty deletion requests before any side effects (backup, append, rebuild).
|
|
1559
|
+
if (!Array.isArray(extensionDeletionRequest.deletions) || extensionDeletionRequest.deletions.length === 0) {
|
|
1560
|
+
throw new Error("No safe context deletions proposed by extension");
|
|
1561
|
+
}
|
|
1562
|
+
// Validate against the internal transcript snapshot, not the extension-facing clone.
|
|
1563
|
+
// Auth is NOT resolved here — local extension deletion requests work offline.
|
|
1564
|
+
validated = validateContextDeletionRequest(extensionDeletionRequest, preparation.transcript, { mode });
|
|
1565
|
+
// Reject if reconciliation reduced deletions to zero.
|
|
1566
|
+
if (validated.deletedTargets.length === 0) {
|
|
1567
|
+
throw new Error("No safe context deletions proposed by extension");
|
|
1568
|
+
}
|
|
1569
|
+
fromExtension = true;
|
|
1570
|
+
}
|
|
1571
|
+
}
|
|
1572
|
+
// Planner fallback shared by both paths: no before-compact handler at all, or a handler that
|
|
1573
|
+
// observed without supplying a deletionRequest. Resolves auth lazily; undefined means auth is
|
|
1574
|
+
// unavailable (auto-mode resolvers), so compaction is a no-op.
|
|
1575
|
+
if (!validated) {
|
|
1576
|
+
const plannerResult = await runPlanner();
|
|
1577
|
+
if (!plannerResult) {
|
|
1578
|
+
return undefined;
|
|
1579
|
+
}
|
|
1580
|
+
validated = plannerResult;
|
|
1581
|
+
}
|
|
1494
1582
|
if (options.abortController.signal.aborted) {
|
|
1495
1583
|
throw new Error("Compaction cancelled");
|
|
1496
1584
|
}
|
|
1497
1585
|
const backupPath = this.sessionManager.writeBackupSnapshot(options.backupLabel);
|
|
1498
|
-
this.sessionManager.appendContextCompaction(validated.deletedTargets, validated.protectedEntryIds, validated.stats, backupPath);
|
|
1586
|
+
const compactionEntryId = this.sessionManager.appendContextCompaction(validated.deletedTargets, validated.protectedEntryIds, validated.stats, backupPath);
|
|
1499
1587
|
const sessionContext = this.sessionManager.buildSessionContext();
|
|
1500
1588
|
this.agent.state.messages = sessionContext.messages;
|
|
1501
|
-
|
|
1589
|
+
const result = {
|
|
1502
1590
|
...validated,
|
|
1503
1591
|
promptVersion: 1,
|
|
1504
1592
|
...(backupPath ? { backupPath } : {}),
|
|
1505
1593
|
};
|
|
1594
|
+
// Emit session_compact so extensions can observe the validated result. This is a pure
|
|
1595
|
+
// observation hook fired AFTER the compaction has been committed (backup written,
|
|
1596
|
+
// context_compaction entry persisted, active context rebuilt). A misbehaving observer must
|
|
1597
|
+
// never turn a successful, already-persisted compaction into a reported failure, so any
|
|
1598
|
+
// throw is routed to the non-fatal extension-error channel and compaction still reports
|
|
1599
|
+
// success.
|
|
1600
|
+
const contextCompactionEntry = this.sessionManager.getEntry(compactionEntryId);
|
|
1601
|
+
try {
|
|
1602
|
+
await this._extensionRunner.emit({
|
|
1603
|
+
type: "session_compact",
|
|
1604
|
+
reason: options.reason,
|
|
1605
|
+
mode,
|
|
1606
|
+
result,
|
|
1607
|
+
contextCompactionEntry,
|
|
1608
|
+
fromExtension,
|
|
1609
|
+
});
|
|
1610
|
+
}
|
|
1611
|
+
catch (error) {
|
|
1612
|
+
this._extensionRunner.emitError({
|
|
1613
|
+
extensionPath: "<session_compact>",
|
|
1614
|
+
event: "session_compact",
|
|
1615
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1616
|
+
stack: error instanceof Error ? error.stack : undefined,
|
|
1617
|
+
});
|
|
1618
|
+
}
|
|
1619
|
+
return result;
|
|
1506
1620
|
}
|
|
1507
1621
|
/**
|
|
1508
1622
|
* Manually compact the session context using deletion-only verbatim context compaction.
|
|
1509
|
-
* Aborts current agent operation first.
|
|
1623
|
+
* Aborts current agent operation first.
|
|
1510
1624
|
*/
|
|
1511
|
-
async compact(
|
|
1512
|
-
if (customInstructions?.trim()) {
|
|
1513
|
-
throw new Error("Custom compaction instructions are not supported; use /compact without arguments");
|
|
1514
|
-
}
|
|
1625
|
+
async compact() {
|
|
1515
1626
|
this._disconnectFromAgent();
|
|
1516
1627
|
await this.abort();
|
|
1517
1628
|
this._compactionAbortController = new AbortController();
|
|
@@ -1520,12 +1631,14 @@ export class AgentSession {
|
|
|
1520
1631
|
if (!this.model) {
|
|
1521
1632
|
throw new Error(formatNoModelSelectedMessage());
|
|
1522
1633
|
}
|
|
1523
|
-
|
|
1634
|
+
// Auth is resolved lazily: only called when the planner fallback is needed.
|
|
1635
|
+
// Extensions that provide a deletionRequest work without configured credentials.
|
|
1636
|
+
const model = this.model;
|
|
1524
1637
|
const result = await this._applyContextVerbatimCompaction({
|
|
1525
|
-
|
|
1526
|
-
headers,
|
|
1638
|
+
resolvePlannerAuth: () => this._getRequiredRequestAuth(model),
|
|
1527
1639
|
abortController: this._compactionAbortController,
|
|
1528
1640
|
backupLabel: "compact",
|
|
1641
|
+
reason: "manual",
|
|
1529
1642
|
});
|
|
1530
1643
|
if (!result) {
|
|
1531
1644
|
throw new Error("Nothing to compact (session too small)");
|
|
@@ -1570,12 +1683,14 @@ export class AgentSession {
|
|
|
1570
1683
|
if (!this.model) {
|
|
1571
1684
|
throw new Error(formatNoModelSelectedMessage());
|
|
1572
1685
|
}
|
|
1573
|
-
|
|
1686
|
+
// Auth is resolved lazily: only called when the planner fallback is needed.
|
|
1687
|
+
// Extensions that provide a deletionRequest work without configured credentials.
|
|
1688
|
+
const model = this.model;
|
|
1574
1689
|
const result = await this._applyContextVerbatimCompaction({
|
|
1575
|
-
|
|
1576
|
-
headers,
|
|
1690
|
+
resolvePlannerAuth: () => this._getRequiredRequestAuth(model),
|
|
1577
1691
|
abortController: this._compactionAbortController,
|
|
1578
1692
|
backupLabel: "context-compact",
|
|
1693
|
+
reason: "manual",
|
|
1579
1694
|
});
|
|
1580
1695
|
if (!result) {
|
|
1581
1696
|
throw new Error("Nothing to context-compact (session too small)");
|
|
@@ -1754,23 +1869,24 @@ export class AgentSession {
|
|
|
1754
1869
|
});
|
|
1755
1870
|
return;
|
|
1756
1871
|
}
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
aborted: false,
|
|
1764
|
-
willRetry: false,
|
|
1765
|
-
});
|
|
1766
|
-
return;
|
|
1767
|
-
}
|
|
1872
|
+
// Auth is resolved lazily: only called when the planner fallback is needed.
|
|
1873
|
+
// This allows extension-provided deletion requests to run before auth is checked,
|
|
1874
|
+
// enabling local extension compaction even when API credentials are unavailable.
|
|
1875
|
+
// Auto-mode resolver returns undefined (rather than throwing) when auth is missing,
|
|
1876
|
+
// so compaction silently no-ops if the planner would be needed but credentials are absent.
|
|
1877
|
+
const model = this.model;
|
|
1768
1878
|
const result = await this._applyContextVerbatimCompaction({
|
|
1769
|
-
|
|
1770
|
-
|
|
1879
|
+
resolvePlannerAuth: async () => {
|
|
1880
|
+
const authResult = await this._modelRegistry.getApiKeyAndHeaders(model);
|
|
1881
|
+
if (!authResult.ok || !authResult.apiKey) {
|
|
1882
|
+
return undefined;
|
|
1883
|
+
}
|
|
1884
|
+
return { apiKey: authResult.apiKey, headers: authResult.headers };
|
|
1885
|
+
},
|
|
1771
1886
|
abortController: this._autoCompactionAbortController,
|
|
1772
1887
|
backupLabel: reason === "overflow" ? "overflow-auto-compact" : "auto-compact",
|
|
1773
1888
|
mode: reason === "overflow" ? "critical_overflow" : "standard",
|
|
1889
|
+
reason,
|
|
1774
1890
|
});
|
|
1775
1891
|
if (!result) {
|
|
1776
1892
|
this._emit({
|
|
@@ -1974,7 +2090,7 @@ export class AgentSession {
|
|
|
1974
2090
|
compact: (options) => {
|
|
1975
2091
|
void (async () => {
|
|
1976
2092
|
try {
|
|
1977
|
-
const result = await this.compact(
|
|
2093
|
+
const result = await this.compact();
|
|
1978
2094
|
options?.onComplete?.(result);
|
|
1979
2095
|
}
|
|
1980
2096
|
catch (error) {
|