(options: CompactionOptions)
| 1517 | * Returns the actual message text (summarization request), metadata, and options |
| 1518 | */ |
| 1519 | export function prepareCompactionMessage(options: CompactionOptions): { |
| 1520 | messageText: string; |
| 1521 | metadata: MuxMessageMetadata; |
| 1522 | sendOptions: SendMessageOptions; |
| 1523 | } { |
| 1524 | // followUpContent is the content that will be auto-sent after compaction. |
| 1525 | // For forced compaction (no explicit follow-up), we inject a short resume sentinel ("Continue"). |
| 1526 | // Keep that sentinel out of the *compaction prompt* (summarization request), otherwise the model can |
| 1527 | // misread it as a competing instruction. We still keep it in metadata so the backend resumes. |
| 1528 | // Only treat it as the default resume when there's no other queued content (images/reviews). |
| 1529 | // |
| 1530 | // Convert CompactionFollowUpInput to CompactionFollowUpRequest by adding model/agentId. |
| 1531 | // Compaction uses its own agentId ("compact") and potentially a different model for |
| 1532 | // summarization, so we capture the user's original settings for the follow-up message. |
| 1533 | // |
| 1534 | // In compaction recovery (retrying a failed /compact), followUpContent may already be |
| 1535 | // a CompactionFollowUpRequest with preserved model/agentId. Only fill in missing fields |
| 1536 | // to avoid overwriting the original settings when the user changes model/agent before retry. |
| 1537 | let fc: CompactionFollowUpRequest | undefined; |
| 1538 | if (options.followUpContent) { |
| 1539 | // Check if already a CompactionFollowUpRequest (has model/agentId from previous compaction) |
| 1540 | const existingModel = |
| 1541 | "model" in options.followUpContent && |
| 1542 | typeof options.followUpContent.model === "string" && |
| 1543 | options.followUpContent.model |
| 1544 | ? options.followUpContent.model |
| 1545 | : undefined; |
| 1546 | const existingAgentId = |
| 1547 | "agentId" in options.followUpContent && |
| 1548 | typeof options.followUpContent.agentId === "string" && |
| 1549 | options.followUpContent.agentId |
| 1550 | ? options.followUpContent.agentId |
| 1551 | : undefined; |
| 1552 | |
| 1553 | fc = { |
| 1554 | ...options.followUpContent, |
| 1555 | model: existingModel ?? options.sendMessageOptions.model, |
| 1556 | agentId: existingAgentId ?? options.sendMessageOptions.agentId ?? WORKSPACE_DEFAULTS.agentId, |
| 1557 | ...pickPreservedSendOptions(options.sendMessageOptions), |
| 1558 | }; |
| 1559 | } |
| 1560 | |
| 1561 | // Build compaction message with optional continue context. |
| 1562 | // Shared helper is also used by backend-triggered idle compaction. |
| 1563 | const messageText = buildCompactionMessageText({ |
| 1564 | maxOutputTokens: options.maxOutputTokens, |
| 1565 | followUpContent: fc, |
| 1566 | }); |
| 1567 | |
| 1568 | // Handle model preference (sticky globally) |
| 1569 | const effectiveModel = resolveCompactionModel(options.model); |
| 1570 | |
| 1571 | const commandLine = formatCompactionCommandLine(options); |
| 1572 | const continueText = getFollowUpContentText(fc); |
| 1573 | const fullRawCommand = continueText ? `${commandLine}\n${continueText}` : commandLine; |
| 1574 | |
| 1575 | const compactData: CompactionRequestData = { |
| 1576 | model: effectiveModel, |
no test coverage detected