* Derives auto-resume send options (agentId, model, thinkingLevel) from durable * conversation metadata, so synthetic resumes preserve the parent's active agent. * * Precedence: stream-end event metadata → last assistant message in history → workspace AI settings → defaults.
(
parentWorkspaceId: string,
parentEntry: {
workspace: {
aiSettingsByAgent?: Record<string, ResolvedWorkspaceAiSettings>;
aiSettings?: ResolvedWorkspaceAiSettings;
};
},
fallbackModel: string,
hint?: ParentAutoResumeHint
)
| 1631 | * Precedence: stream-end event metadata → last assistant message in history → workspace AI settings → defaults. |
| 1632 | */ |
| 1633 | private async resolveParentAutoResumeOptions( |
| 1634 | parentWorkspaceId: string, |
| 1635 | parentEntry: { |
| 1636 | workspace: { |
| 1637 | aiSettingsByAgent?: Record<string, ResolvedWorkspaceAiSettings>; |
| 1638 | aiSettings?: ResolvedWorkspaceAiSettings; |
| 1639 | }; |
| 1640 | }, |
| 1641 | fallbackModel: string, |
| 1642 | hint?: ParentAutoResumeHint |
| 1643 | ): Promise<{ model: string; agentId: string; thinkingLevel?: ThinkingLevel }> { |
| 1644 | // 1) Try stream-end hint metadata (available in handleStreamEnd path) |
| 1645 | let agentId = hint?.agentId; |
| 1646 | |
| 1647 | // 2) Fall back to latest assistant message metadata in history (restart-safe) |
| 1648 | if (!agentId) { |
| 1649 | try { |
| 1650 | const historyResult = await this.historyService.getLastMessages(parentWorkspaceId, 20); |
| 1651 | if (historyResult.success) { |
| 1652 | for (let i = historyResult.data.length - 1; i >= 0; i--) { |
| 1653 | const msg = historyResult.data[i]; |
| 1654 | if (msg?.role === "assistant" && msg.metadata?.agentId) { |
| 1655 | agentId = msg.metadata.agentId; |
| 1656 | break; |
| 1657 | } |
| 1658 | } |
| 1659 | } |
| 1660 | } catch { |
| 1661 | // Best-effort; fall through to defaults |
| 1662 | } |
| 1663 | } |
| 1664 | |
| 1665 | // 3) Default |
| 1666 | // Keep task auto-resume recovery on exec even if the workspace default agent changes. |
| 1667 | // This path needs a deterministic editing-capable fallback for legacy/incomplete metadata. |
| 1668 | agentId = agentId ?? TASK_RECOVERY_FALLBACK_AGENT_ID; |
| 1669 | |
| 1670 | const aiSettings = this.resolveWorkspaceAISettings(parentEntry.workspace, agentId); |
| 1671 | return { |
| 1672 | model: aiSettings?.model ?? fallbackModel, |
| 1673 | agentId, |
| 1674 | thinkingLevel: aiSettings?.thinkingLevel, |
| 1675 | }; |
| 1676 | } |
| 1677 | |
| 1678 | private async isPlanLikeTaskWorkspace(entry: { |
| 1679 | projectPath: string; |
no test coverage detected