(input: {
policy: GoalInterventionPolicy;
})
| 1265 | } |
| 1266 | |
| 1267 | private async applyManualUserMessageGoalSafety(input: { |
| 1268 | policy: GoalInterventionPolicy; |
| 1269 | }): Promise<void> { |
| 1270 | const goalService = this.workspaceGoalService; |
| 1271 | if (!goalService) { |
| 1272 | return; |
| 1273 | } |
| 1274 | |
| 1275 | assert( |
| 1276 | input.policy === "steer" || input.policy === "pause", |
| 1277 | `invalid goal intervention policy: ${input.policy}` |
| 1278 | ); |
| 1279 | |
| 1280 | // Accepted manual user turns acknowledge / clear crash-recovery gates, but |
| 1281 | // they are no longer goal-continuation turns. The goal mode is locked to the |
| 1282 | // chat tail: a real `goal_continuation` user message means running; |
| 1283 | // anything manually typed by the user pauses until Resume appends a fresh |
| 1284 | // continuation. Legacy clients may still send the old "steer" policy; treat |
| 1285 | // it as pause so the invariant holds at this backend boundary. |
| 1286 | goalService.clearPendingContinuationForManualUserMessage(this.workspaceId); |
| 1287 | const goal = await goalService.acknowledgeUser(this.workspaceId); |
| 1288 | if (goal?.status !== "active") { |
| 1289 | return; |
| 1290 | } |
| 1291 | |
| 1292 | try { |
| 1293 | const result = await goalService.setGoal({ |
| 1294 | workspaceId: this.workspaceId, |
| 1295 | status: "paused", |
| 1296 | initiator: "auto", |
| 1297 | }); |
| 1298 | if (!result.success) { |
| 1299 | log.warn("Failed to auto-pause goal for manual user message", { |
| 1300 | workspaceId: this.workspaceId, |
| 1301 | error: result.error, |
| 1302 | }); |
| 1303 | } |
| 1304 | } catch (error) { |
| 1305 | log.warn("Failed to auto-pause goal for manual user message", { |
| 1306 | workspaceId: this.workspaceId, |
| 1307 | error: getErrorMessage(error), |
| 1308 | }); |
| 1309 | } |
| 1310 | } |
| 1311 | |
| 1312 | private async getWorkspaceMetadataForRetry(): Promise<WorkspaceMetadata | undefined> { |
| 1313 | const aiService = this.aiService as Partial<Pick<AIService, "getWorkspaceMetadata">>; |
no test coverage detected