feat(escalations): magic-moment 3-option CTA + claim 500 fix

- HandoffContextScreen: 3-option layout (Continue/AI analysis/Own thing)
  with hasTaskLane, activeOptionKey, spinner/disabled states
- AssistantChatPage: wire up handleContinue, handleAIAnalysis, handleOwnThing
  handlers; chip detail expansion inline with copy-button fix; post-escalation
  redirect to dashboard on ConcludeSessionModal close
- TaskLane: fix async copy button (await + execCommand fallback + copiedKey
  visual feedback); whitespace-pre-wrap on command blocks
- Fix 500 on claim: Pydantic v2 model_validate() + model_copy(update={})
  (was passing update= kwarg directly which v2 rejects)
- HandoffResponse schema: handed_off_by_name field

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-30 00:05:02 -04:00
parent fb2dc222fd
commit db717b0b3f
11 changed files with 673 additions and 207 deletions

View File

@@ -15,16 +15,15 @@ def stub_ai_assessment():
"""Keep handoff tests focused on handoff behavior, not external AI calls."""
with patch.object(
HandoffManager,
"_generate_ai_assessment",
"_generate_handoff_summary",
new=AsyncMock(
return_value=(
"Stub escalation assessment",
{
"likely_cause": "Stub",
"suggested_steps": [],
"confidence": "medium",
},
)
return_value={
"summary_prose": "Stub escalation assessment",
"what_we_know": [],
"likely_cause": "Stub",
"suggested_steps": [],
"confidence": "medium",
}
),
):
yield
@@ -120,9 +119,9 @@ async def test_create_escalate_handoff_does_not_wait_on_slow_ai_assessment(
test_db.add(session)
await test_db.flush()
async def slow_assessment(self, session):
async def slow_summary(self, session):
await asyncio.sleep(0.2)
return "too slow", {"confidence": "medium"}
return {"summary_prose": "too slow", "confidence": "medium"}
monkeypatch.setattr(
"app.services.handoff_manager.settings."
@@ -131,8 +130,8 @@ async def test_create_escalate_handoff_does_not_wait_on_slow_ai_assessment(
)
with patch.object(
HandoffManager,
"_generate_ai_assessment",
new=slow_assessment,
"_generate_handoff_summary_inner",
new=slow_summary,
):
manager = HandoffManager(test_db)
handoff = await manager.create_handoff(

View File

@@ -23,16 +23,15 @@ def stub_ai_assessment():
"""Endpoint tests should not wait on the external AI assessment path."""
with patch.object(
HandoffManager,
"_generate_ai_assessment",
"_generate_handoff_summary",
new=AsyncMock(
return_value=(
"Stub escalation assessment",
{
"likely_cause": "Stub",
"suggested_steps": [],
"confidence": "medium",
},
)
return_value={
"summary_prose": "Stub escalation assessment",
"what_we_know": [],
"likely_cause": "Stub",
"suggested_steps": [],
"confidence": "medium",
}
),
):
yield