Skip to content

fix(artifacts): give every generated file format the same row resolution - #1312

Merged
Paul Lizer (paullizer) merged 1 commit into
microsoft:Developmentfrom
paullizer:fix/structured-artifact-parity-across-formats
Aug 19, 2026
Merged

Paul Lizer (paullizer) merged 1 commit into
microsoft:Developmentfrom
paullizer:fix/structured-artifact-parity-across-formats

Conversation

@paullizer

Copy link
Copy Markdown
Contributor

Summary

Follow-up to #1308. That PR fixed CSV; this one gives the sibling formats the same behavior and tidies a loose end it left.

Stacked on #1308. Merge that first, then this diff reduces to its own commit.

Gap 1: JSON and XML could never use action rows

JSON and XML are built by a separate path, maybe_create_assistant_file_generated_output, which only parses a payload out of the assistant reply. It never looked at action results, so make that a json failed exactly the way create a csv used to: if the model did not re-emit the payload as text, nothing was published.

build_structured_artifact_rows_payload() now serializes authorized action rows whenever the reply carries no payload of its own, using the same earlier-turn reach-back and the same passthrough contract as CSV.

Case Result
create a json of that data, rows in this turn 30 rows, JSON array
create an xml of that data, rows in this turn 30 rows, <GeneratedRows> root
create a json, rows only in an earlier turn 30 rows, earlier action result
analyze and summarize each sample as JSON refused, derived output needs a transform
csv / docx / pdf untouched, they keep their own renderers

Gap 2: the clarification gate only covered CSV

It lived inside the if output_format == GENERATED_FILE_FORMAT_CSV: branch, so a turn that asked a clarifying question could still publish a DOCX or PDF built from incidental rows. It now runs before the format branch.

csv   clarification turn -> no artifact
docx  clarification turn -> no artifact
pdf   clarification turn -> no artifact

Ordinary DOCX and PDF requests still publish normally, with rows embedded, covered by test_docx_and_pdf_still_publish_a_normal_answer.

Gap 3: DOCX and PDF guidance never forbade refusing

Their guidance covered over-claiming (do not invent rows or claim an attachment exists before the file-output finalizer publishes it) but not under-claiming. I cannot create files is the exact sentence that produced the 3-row CSV in #1308, so DOCX and PDF now state the same publication contract as CSV, JSON, and XML.

Tidy: reason code dropped on earlier-turn rows

The DOCX and PDF return compared one row-source literal:

passthrough_reason_code=(... if row_source == 'structured function result' else None)

Once #1308 introduced earlier action result, that silently dropped the reason code. It now uses the FUNCTION_RESULT_ROW_SOURCES set that _build_structured_rows_heading already used. Metadata only, no user-visible effect, but it was a loose end from those commits.

Changes

  • application/single_app/functions_generated_file_exports.py - build_structured_artifact_rows_payload(), hoisted clarification gate, DOCX/PDF guidance, reason-code tidy
  • application/single_app/route_backend_chats.py - JSON/XML fallback wiring plus function_results at all three call sites
  • application/single_app/config.py - version 0.260.010
  • functional_tests/test_generated_structured_artifact_parity.py - new
  • functional_tests/test_assistant_table_csv_artifact.py - call-site count assertions updated for the two new export call sites

Validation

Suite Result
test_generated_structured_artifact_parity.py (new) 8/8
test_generated_csv_uses_authorized_action_rows.py 15/15
test_assistant_table_csv_artifact.py 36/36
test_generated_json_xml_exports.py 7/7
test_tabular_background_generated_exports.py 8/8
test_tabular_passthrough_heterogeneous_rows.py 4/4
route blueprint policy 6/6
route unauthenticated policy 4/4

py_compile, diagnostics, and Windows-safe git diff --check clean.

One test assertion changed rather than being added: test_chat_route_wires_assistant_table_artifacts pinned function_results=agent_citations_list to an exact count of 2, which is now 4 because the JSON/XML path also receives action results. The assertion still pins an exact count so it keeps catching dropped wiring, and the message now names both export paths.

Coverage after this PR

Behavior CSV DOCX / PDF JSON / XML
Action grouping and dominance yes yes yes
Earlier-turn reach-back yes yes yes
Publication contract in guidance yes yes yes
Clarification gate yes yes n/a, no clarification flow
Excerpt-aware precedence yes not needed, already action-first n/a, payload-first
Pending-format carry-forward yes no no

Pending-format carry-forward is still CSV only, because the one-clarification flow is a CSV behavior. Worth extending if the other formats ever grow the same flow.

The CSV work left three gaps in the sibling formats and one loose end.

JSON and XML were built only by parsing a payload out of the assistant reply,
so they could never use authorized action rows and never reached back to rows
an earlier turn already gathered. "make that a json" failed exactly the way
"create a csv" used to. build_structured_artifact_rows_payload() now
serializes authorized rows, with the same earlier-turn reach-back and the same
passthrough contract, whenever the reply carries no payload of its own.

The schema clarification gate lived inside the CSV branch, so a turn that
asked a clarifying question could still publish a DOCX or PDF. It now runs
before the format branch and covers every generated file format.

DOCX and PDF guidance never forbade claiming that files cannot be created,
which is the exact sentence that produced the truncated CSV. It now states the
publication contract the other formats already state.

The DOCX and PDF passthrough reason code compared a single row-source literal,
so it was dropped once rows could come from an earlier turn. It now uses the
named row-source set.

Version: 0.260.010
@paullizer
Paul Lizer (paullizer) merged commit 818dd32 into microsoft:Development Aug 19, 2026
11 of 12 checks passed
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