Skip to content

feat: return ordered Astra response parts - #727

Merged
thomasluizon merged 5 commits into
redesign/mainfrom
thomasluizon/ticket-1475-astra
Oct 17, 2026
Merged

thomasluizon merged 5 commits into
redesign/mainfrom
thomasluizon/ticket-1475-astra

Conversation

@thomasluizon

@thomasluizon thomasluizon commented Oct 17, 2026 •

Copy link
Copy Markdown
Owner

Closes thomasluizon/orbit-tickets#1475.

Clients advertising SupportsParts receive text and block parts in the model's reading order, with at most three blocks. Repeated directives emit one block at their first position. AiMessage joins the text parts with a blank line. Parts clients get null legacy card fields; other clients keep the existing serialized response and prompt strings. Cached FAQ answers and early replies omit parts.

FollowUpDirective.cs preserves the ordered text and directives without changing stream deltas. ProcessUserChatCommand.cs builds each directive through the existing card builders, so client capabilities, tool-success checks, and feature flags still apply. It also keeps card events and adds part_count and ordered block_kinds. The append-only capabilities live in AgentContracts.cs; the response union and regenerated openapi.json expose only text and block as outer types. The AI command and card builders select separate parts prompt instructions, limited to declared kinds. FeatureFlagKeys.cs adds astra_parts_disabled, which restores the legacy response and prompt without a deploy.

Deploy this API contract before thomasluizon/orbit-tickets#1479. No client rendering or card payload fields change here.

Assumptions

  • Omit the JSON parts property when its C# value is null, rather than serializing an extra null field, to satisfy byte-identical legacy responses.
  • Match declared kind names exactly and deduplicate directive tokens case-insensitively, rather than merging distinct directives sharing an outer kind; separate record-list directives remain separate parts.
  • Count successfully built blocks toward the limit of three, rather than counting dropped directives as blocks.
  • Shared block-kind constants remain private to the partial handler rather than becoming a public contract type.

Test evidence

  • dotnet build Orbit.slnx: passed with zero errors.
  • dotnet test: 9,470 passed, zero failed or skipped (Domain 661, Application 5,478, Infrastructure 3,299, Analyzers 32).
  • dotnet test tests/Orbit.Application.Tests --no-restore --filter 'FullyQualifiedName~ProcessUserChatCommandHandlerTests|FullyQualifiedName~ChatStreamEventTests|FullyQualifiedName~FollowUpDirectiveTests' --nologo: 196 passed. Covers ordering, unsupported kinds, missing or failed tools, capability and feature flag gates, duplicate and fourth directives, two record-list parts, truncation, follow-up tails, early replies, stream serialization, and complete prompts for both client shapes.
  • git diff --exit-code -- src/Orbit.Api/openapi.json: passed after the full build and suite; the generated schema matches the committed file.
  • node tools/check-timeless.mjs --base 0a32fab3, whitespace checks, dash checks, and all commit hooks passed.

This is a new feature, so the work order exempts red regression reproduction. Before changing response assembly, dotnet test tests/Orbit.Application.Tests --no-restore --filter FullyQualifiedName~Handle_LegacyMixedDirectives_MatchesSerializedGolden --nologo passed against the original handler (one case). The same golden passed after the implementation for absent, false, and server-disabled parts support (three cases), also included in the full suite.

  • dotnet build Orbit.slnx: exit 0, zero errors.
  • Baseline handler tests: 182 passed; focused tests: 208 passed.
  • Application project: 5,498 passed.
  • dotnet test --no-build: exit 0, all 9,490 passed.
  • Local changed-line coverage: 98.8%, 171/173 executable application lines. Hosted SonarCloud confirmation remains pending.
  • OpenAPI stale check and commit hooks passed.
  • Turbo type-check exited 1: Turbo is absent, and this repository has no JavaScript package manifest.
  • No behavioral defect was changed, so no red regression reproduction applies.

Eval scenarios for #26

  • "what is left today and how is my week" gives text, habitList, text, metrics in that order.
  • A plain question gives one text part.
  • A parts client that does not declare a kind gets no block of that kind.

Manual steps

  • Orchestrator pushes the commits to existing PR feat: return ordered Astra response parts #727 and verifies SonarCloud Code Analysis clears its quality gate.
  • Deploy through GitHub Actions > Release API before #1479. Verify a capable request returns ordered parts.
  • No new configuration, secrets, migrations, or backfills.

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ No new issues found.

Reviewed changes Reviewed ordered Astra response assembly, prompt selection, serialization, and compatibility with the existing mobile and web consumers.

  • Ordered parts: Preserves text and directive positions, deduplicates repeated directives, limits responses to three built blocks, and retains existing card eligibility checks.
  • Append-only contract: Adds opt-in capabilities and the text/block response union without changing existing card payloads; clients without parts support retain legacy responses.
  • Prompts and fallback: Selects reading-order instructions for declared kinds and restores legacy prompts and responses through astra_parts_disabled.
  • Response handling: Preserves follow-up and truncation behavior, prevents block responses from entering the shared FAQ cache, and adds ordered-part analytics.
  • Verification: Solution build completed with zero errors, all 9,470 unit tests passed, and the sibling repository's current client context does not opt into parts. Live model output and client rendering were not exercised.

Pullfrog  | View workflow run | Using gpt-6.1-sol | 𝕏

@sonarqubecloud

Copy link
Copy Markdown

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ No new issues found.

Reviewed changes Reviewed the changes since 3add73c5, focusing on prompt-assembly equivalence, shared block-kind identifiers, and expanded ordered-parts coverage.

  • Extracted prompt groups: Separated period and status instructions while preserving capability checks, feature flags, declared-kind filtering, and instruction order.
  • Consolidated block kinds: Reused private constants across prompt selection, directive mapping, block assembly, and analytics without changing wire values.
  • Expanded behavioral tests: Added coverage for undeclared and unknown kinds, status-block payloads and kill flags, insight/account ordering and analytics, and missing record-list payloads.
  • Verified compatibility and tests: Confirmed current sibling clients remain on the legacy path; the solution built with zero errors, all 208 focused chat tests passed, and all 9,490 unit tests passed. Live model output and client rendering were not exercised.

Pullfrog  | View workflow run | Using gpt-6.1-sol | 𝕏

@thomasluizon
thomasluizon merged commit c8877ee into redesign/main Oct 17, 2026
26 checks passed
@thomasluizon
thomasluizon deleted the thomasluizon/ticket-1475-astra branch October 17, 2026 17:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant