Commit b4305cf
Phase 8 task #92 (D8.5-BE) — first-cut backend migration of the
non-agent chat path to the canonical ``UIMessage`` shape, scoped per
architect msg=01918929 + Weston msg=df87fe24 + earayu2 msg=f20d5034
hard-cut acceptance:
The inventory revealed the production "non-agent chat path" the
original D8.5 design assumed has already converged on the agent
runtime (``chat_completion_service.openai_chat_completions`` already
delegates to ``runtime_manager.turn_service.create_or_get_turn`` and
``ChatService.create_chat`` rejects non-AGENT bots). So the actual
#92 work is A+B+C only — adding the discriminator column for future
non-agent paths and migrating the user-visible chat history shape to
canonical UIMessage. The translator extension (``chat.text.delta`` /
``chat.completed``) and the ``StoredChatMessagePart`` /
``RedisChatMessageHistory`` deletion are deferred per architect /
Weston canonical lock.
Changes:
A. ``runtime_kind`` discriminator on ``agent_message`` table
- ``aperag/domains/agent_runtime/db/models.py``: new
``runtime_kind: str`` ORM column with values
``agent_runtime`` / ``direct_chat`` / ``rag_chat`` (mutually
exclusive enum); existing rows backfill via
``server_default="agent_runtime"``. ``role`` keeps speaker
semantics independent of the runtime that produced the message.
- ``aperag/migration/versions/...c8f2d34a51e7_add_agent_message_runtime_kind.py``:
additive migration; downgrade drops the column.
B. ``ChatService._build_v3_chat_history`` rewrite
- Returns ``list[AgentTurnSnapshot]`` (one snapshot per assistant
turn) instead of the legacy ``list[list[ChatMessage]]`` shape.
- Reuses ``snapshot_assembler.assemble_parts_from_artifacts`` (the
#90 D8.4d projection) so historical turns expose the same
``UIMessagePart`` shape the FE consumes from the live SSE stream
(D8 §2 wire/at-rest byte-equal).
- ``error_text`` for FAILED / CANCELLED turns surfaces an
``error_summary`` artifact's message, falling back to
``turn.error_message`` — mirrors the snapshot endpoint contract.
- The turn's user query lives at ``input_text`` on the snapshot
envelope (rather than as a separate ``role=human`` ChatMessage)
so the FE renders user/assistant from a single object per turn.
- Legacy ``_extract_artifact_text`` / ``_extract_references`` /
``_map_reference_item`` / ``_artifact_type_value`` /
``_coerce_timestamp`` helpers are retired alongside the legacy
shape.
C. ``ChatDetails.history`` schema
- ``aperag/domains/conversation/schemas.py``: ``history`` is now
``Optional[list[AgentTurnSnapshot]]`` with explicit description
citing D8 §2 byte-equal canonical and the new shape.
- The ``conversation.schemas`` ↔ ``agent_runtime.uimessage``
↔ ``agent_runtime.schemas`` ↔ ``conversation.schemas`` cycle is
broken via ``TYPE_CHECKING`` import + a module-level
``ChatDetails.model_rebuild()`` hook at the bottom of
``conversation/schemas.py``. Pydantic resolves the forward ref at
load time so the OpenAPI schema is fully populated.
- ``aperag/domains/agent_runtime/uimessage.py``: ``AgentTurnSnapshot``
gains ``runtime_kind: RuntimeKind`` (default ``"agent_runtime"``)
and ``input_text: Optional[str]`` so historical turns can render
the user query without a separate envelope round-trip.
- ``TurnService.get_turn_snapshot`` writes both new fields on the
live snapshot endpoint so live and historical reload paths match.
D. (deferred) Translator extension for ``chat.text.delta`` /
``chat.completed`` and ``StoredChatMessagePart`` /
``RedisChatMessageHistory`` deletion stay out of #92 per
Weston msg=df87fe24 / PM msg=01918929. The non-agent live path the
extension would have served does not exist in the current
codebase; reintroducing it is a feature task, not a refactor.
Tests:
- ``tests/unit_test/chat/test_chat_service.py`` rewritten:
* ``test_get_chat_returns_canonical_uimessage_history`` pins the
new shape (snapshot per turn with text + source-url +
data-citation parts, runtime_kind, input_text)
* ``test_get_chat_history_surfaces_error_text_for_failed_turn``
pins the error_text contract for FAILED turns
* ``test_get_chat_history_does_not_expose_legacy_chatmessage_shape``
regression-guard against revert to ``list[list[ChatMessage]]``
- ``tests/unit_test/agent_runtime/test_agent_runtime_v3.py`` updated
to import ``AgentTurnSnapshot`` from ``agent_runtime.uimessage``
(the back-compat re-export through ``agent_runtime.schemas`` was
retired to break the new cycle).
Per D10 §G hard gate 1 (comprehensive grep sweep) ran across
``aperag/`` + ``tests/unit_test/`` + ``tests/e2e_http/hurl/`` +
``tests/e2e_http/scripts/``: only the FE
``web/src/components/chat/chat-messages.tsx`` reads ``chat.history``
in the old shape — that is the explicit hand-off seam for #93
huangheng (per architect msg=6e53a7c4).
Gates: full unit suite 833 / 29 skip / 0 fail; ruff check + format
clean.
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
1 parent 3f9303c commit b4305cf
10 files changed
Lines changed: 312 additions & 157 deletions
File tree
- aperag
- domains
- agent_runtime
- api
- db
- conversation
- service
- migration/versions
- tests/unit_test
- agent_runtime
- chat
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
43 | 43 | | |
44 | 44 | | |
45 | 45 | | |
46 | | - | |
47 | 46 | | |
48 | 47 | | |
49 | 48 | | |
50 | 49 | | |
51 | 50 | | |
52 | 51 | | |
53 | 52 | | |
| 53 | + | |
54 | 54 | | |
55 | 55 | | |
56 | 56 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
153 | 153 | | |
154 | 154 | | |
155 | 155 | | |
156 | | - | |
| 156 | + | |
157 | 157 | | |
158 | 158 | | |
159 | 159 | | |
| |||
163 | 163 | | |
164 | 164 | | |
165 | 165 | | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
166 | 173 | | |
167 | 174 | | |
168 | 175 | | |
| |||
179 | 186 | | |
180 | 187 | | |
181 | 188 | | |
| 189 | + | |
182 | 190 | | |
183 | 191 | | |
184 | 192 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
44 | 44 | | |
45 | 45 | | |
46 | 46 | | |
47 | | - | |
48 | 47 | | |
49 | 48 | | |
50 | 49 | | |
| |||
88 | 87 | | |
89 | 88 | | |
90 | 89 | | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
91 | 102 | | |
92 | 103 | | |
93 | 104 | | |
| |||
176 | 187 | | |
177 | 188 | | |
178 | 189 | | |
179 | | - | |
180 | | - | |
181 | | - | |
182 | | - | |
183 | | - | |
184 | | - | |
185 | | - | |
186 | | - | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
187 | 198 | | |
188 | 199 | | |
189 | 200 | | |
| |||
236 | 247 | | |
237 | 248 | | |
238 | 249 | | |
239 | | - | |
240 | 250 | | |
241 | 251 | | |
242 | 252 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
24 | 24 | | |
25 | 25 | | |
26 | 26 | | |
27 | | - | |
28 | 27 | | |
29 | 28 | | |
30 | 29 | | |
| |||
36 | 35 | | |
37 | 36 | | |
38 | 37 | | |
| 38 | + | |
39 | 39 | | |
40 | 40 | | |
41 | 41 | | |
| |||
489 | 489 | | |
490 | 490 | | |
491 | 491 | | |
| 492 | + | |
492 | 493 | | |
493 | 494 | | |
494 | 495 | | |
| |||
497 | 498 | | |
498 | 499 | | |
499 | 500 | | |
| 501 | + | |
500 | 502 | | |
501 | 503 | | |
502 | 504 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
299 | 299 | | |
300 | 300 | | |
301 | 301 | | |
| 302 | + | |
| 303 | + | |
| 304 | + | |
302 | 305 | | |
303 | | - | |
| 306 | + | |
304 | 307 | | |
305 | 308 | | |
306 | 309 | | |
| |||
310 | 313 | | |
311 | 314 | | |
312 | 315 | | |
| 316 | + | |
| 317 | + | |
| 318 | + | |
| 319 | + | |
| 320 | + | |
313 | 321 | | |
314 | 322 | | |
315 | 323 | | |
| |||
327 | 335 | | |
328 | 336 | | |
329 | 337 | | |
| 338 | + | |
| 339 | + | |
330 | 340 | | |
331 | 341 | | |
332 | 342 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
45 | 45 | | |
46 | 46 | | |
47 | 47 | | |
48 | | - | |
| 48 | + | |
49 | 49 | | |
50 | 50 | | |
51 | 51 | | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
52 | 61 | | |
53 | 62 | | |
54 | 63 | | |
| |||
169 | 178 | | |
170 | 179 | | |
171 | 180 | | |
172 | | - | |
| 181 | + | |
173 | 182 | | |
174 | | - | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
175 | 191 | | |
176 | 192 | | |
177 | 193 | | |
| |||
219 | 235 | | |
220 | 236 | | |
221 | 237 | | |
| 238 | + | |
| 239 | + | |
| 240 | + | |
| 241 | + | |
| 242 | + | |
| 243 | + | |
| 244 | + | |
| 245 | + | |
| 246 | + | |
| 247 | + | |
| 248 | + | |
| 249 | + | |
| 250 | + | |
| 251 | + | |
| 252 | + | |
222 | 253 | | |
223 | 254 | | |
224 | 255 | | |
| |||
0 commit comments