Skip to content

Deliver File Sync prompt context to the first workflow task - #1287

Merged
Paul Lizer (paullizer) merged 1 commit into
Developmentfrom
paullizer-file-sync-task-context
Aug 18, 2026
Merged

Deliver File Sync prompt context to the first workflow task#1287
Paul Lizer (paullizer) merged 1 commit into
Developmentfrom
paullizer-file-sync-task-context

Conversation

@paullizer

Copy link
Copy Markdown
Collaborator

Fixes #1285

Problem

File Sync's prompt context — the block that tells a workflow what actually changed — never reached the model in any task-based workflow, which is every workflow the builder creates.

The failure was silent and actively misleading. The context was written into the conversation's user message, so the run transcript displayed the changed-document list as though the model had received it. In practice the model got only the raw task instructions and typically replied that it had no information about any documents.

What File Sync is supposed to do

Before a run, File Sync scans the configured sources and hands the workflow two separate things:

  1. Prompt context — the sync counts (Scanned / Created / Updated / Unchanged / Skipped / Failed) plus a numbered list of each new or changed document (relative_path, action, document_id, source_name). This is what makes instructions like "summarize the documents that changed since the last run" work.
  2. Document targets — when Use changed documents is on and the action is Analyze, the action is repointed at exactly the changed document ids.

Item 2 worked. Item 1 did not.

Root cause

_apply_file_sync_context_to_workflow() appended the context to the workflow-level task_prompt. _build_workflow_task_execution_workflow() expected it on a different key, then overwrote task_prompt with the task's own instructions:

file_sync_context = str(workflow.get('file_sync_prompt_context') or '').strip()  # always ''
if include_document_action and file_sync_context:                                # never fired
    task_instructions = f'{task_instructions}\n\n[Workflow input context]\n{file_sync_context}'
...
prepared_workflow['task_prompt'] = task_instructions   # discarded the appended context

file_sync_prompt_context was read in exactly one place and written nowhere. The producer line was added in 79148c84 alongside the consumer and later lost in a merge on a long-lived branch (the fix/1031-tabular-row-orchestration-scale / PR #1145 lineage). The consumer survived; the producer did not.

Who was affected: Monitor File Sync Changes workflows — an entire trigger type whose purpose is reacting to what changed — unless they happened to use Analyze with Use changed documents. Also any workflow using Search or No document action, and any workflow with Use changed documents disabled.

Changes

1. Restored the producer

prepared_workflow['file_sync_prompt_context'] = file_sync_context

2. Gave the document search query a clean source

This was the blocking discovery, and the reason the fix is more than one line.

_prepare_workflow_search_context() used workflow['task_prompt'] verbatim as the Azure AI Search query, and that single query value feeds all four search call sites. Restoring the injection without this would have turned a Search task's query into 50 lines of file paths and sync counters.

The prepared workflow now carries task_search_query, captured from the task's instructions before any context blocks are appended:

query = str(workflow.get('task_search_query') or workflow.get('task_prompt') or '').strip()

The fallback to task_prompt means every caller without the key behaves exactly as before.

3. Made the first-task gate explicit

The injection was gated on include_document_action, which used to mean "task 1". After #1284 that flag means "legacy record with no task-level document action", so it no longer expressed the intent. A dedicated include_file_sync_context parameter now carries it, passed task_index == 0.

Later tasks receive the information indirectly through task one's response, which is already chained forward as bounded context.

4. Bounded the context block

WORKFLOW_FILE_SYNC_CONTEXT_MAX_CHARS = 8000 with head/tail truncation and a [File Sync context truncated] marker, mirroring the existing treatment of previous-task output. It is applied inside _format_workflow_file_sync_context() rather than at the injection site, so the conversation transcript and the prompt the model receives stay identical — that mismatch is exactly what made this bug invisible.

Behavior change worth flagging

Scoping the search query to the task's own instructions also means a task-2-or-later Search action no longer uses the previous task's reply as query text. That only became reachable in #1284, and a full prior answer is far more likely to dilute retrieval than help it, so this is the intended behavior — but it is a change, not just a fix. Retrieved content and context still reach the model exactly as before; only the query is scoped.

Why no test caught the original bug

test_workflow_task_sequence.py hand-injected file_sync_prompt_context into the workflow dict and asserted [Workflow input context] appeared in the dispatched prompt. It exercised the consumer with a value production never supplied, so it passed while the feature was broken. It now builds the context through _apply_file_sync_context_to_workflow() instead.

Validation

  • New functional_tests/test_workflow_file_sync_prompt_context.py — 8/8. Covers the producer, first-task-only injection, the legacy no-tasks path, search-query isolation for both paths, the truncation notice (including a realistic 50-document sync with deeply nested paths), the "nothing changed" wording, and that Use changed documents targeting is unaffected.
  • test_workflow_task_sequence.py — 10/10. test_workflow_task_document_actions.py — 16/16.
  • Mutation-verified. Removing the restored producer line makes 4 of 8 and 1 of 10 tests fail respectively, so this regression cannot silently return through another merge.
  • Full test_workflow* sweep against a clean git archive export of the base commit: 21 pre-existing failures on both sides, identical file sets, and per-file output diffs contain only traceback path differences.
  • functional_tests/route_tests/ all pass. The personal and group document picker harnesses from Fix workflow document picker loading and make workspace documents per-task #1284 still pass.

Version

0.250.2250.250.226, with fix documentation, an index entry, and release notes.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@paullizer
Paul Lizer (paullizer) merged commit a2eaa3f into Development Aug 18, 2026
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