Skip to content

File Sync prompt context never reaches the model in task-based workflows #1285

Description

@paullizer

Issue

File Sync's prompt context — the block that tells the workflow what actually changed — is silently dropped for every task-based workflow. Since the workflow builder always creates at least one task, that is effectively every workflow.

Worse, the context is written into the conversation's user message, so the run transcript shows the changed-document list as though the model received it. The transcript looks correct while the model was never told anything.

What File Sync is supposed to do

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

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

What actually happens

Item 2 works. Item 1 never reaches the model.

Root Cause

_apply_file_sync_context_to_workflow() (functions_workflow_runner.py:7052) appends the context to the workflow-leveltask_prompt:

prepared_workflow=dict(workflow)
file_sync_context=_format_workflow_file_sync_context(file_sync_result)
iffile_sync_context:
prepared_workflow['task_prompt'] =f"{workflow.get('task_prompt', '')}\n\n{file_sync_context}".strip()

_build_workflow_task_execution_workflow() (functions_workflow_runner.py:9110) expects it on a different key, and then overwrites task_prompt with the task's own instructions:

file_sync_context=str(workflow.get('file_sync_prompt_context') or'').strip() # always ''ifinclude_document_actionandfile_sync_context: # never firestask_instructions=f'{task_instructions}\n\n[Workflow input context]\n{file_sync_context}'
...
prepared_workflow['task_prompt'] =task_instructions# discards the appended context

file_sync_prompt_context is read in exactly one place and written nowhere:

$ git grep -n "file_sync_prompt_context"
application/single_app/functions_workflow_runner.py:9110: file_sync_context = str(workflow.get('file_sync_prompt_context') or '').strip()
functional_tests/test_workflow_task_sequence.py:470: "file_sync_prompt_context": "File Sync context for this workflow run.",

The producer line did exist. It was added in 79148c84 ("Add stepped workflow builder and task sequences") alongside the consumer:

 if file_sync_context:
prepared_workflow['task_prompt'] = f"{workflow.get('task_prompt', '')}\n\n{file_sync_context}".strip()
+ prepared_workflow['file_sync_prompt_context'] = file_sync_context

It was later lost in a merge resolution on a long-lived branch (git log -m -S points at the fix/1031-tabular-row-orchestration-scale / PR #1145 merge lineage). The consumer survived; the producer did not.

Why no test caught it

functional_tests/test_workflow_task_sequence.py::test_ordered_tasks_chain_context_and_apply_documents_once hand-injects file_sync_prompt_context directly into the workflow dict (line 470) and then asserts [Workflow input context] appears in the dispatched prompt. It exercises the consumer with a value production never supplies, so it passes while the feature is broken.

Steps to Reproduce

  1. Create a workflow with File Sync enabled and at least one sync source.
  2. Set Document action to No document action (or Search), so the changed-documents path is not involved.
  3. Write task instructions such as "List the documents that changed in this sync and summarize each one."
  4. Change a file in the synced source and run the workflow.

Expected Behavior

The task's prompt includes the [Workflow input context] block with the sync counts and the list of new or changed documents, so the model can act on what changed.

Actual Behavior

The model receives only the raw task instructions. It has no idea which files changed, and typically responds that it has no information about any documents. The conversation's user message, however, does show the full changed-document list, because _create_user_message() (functions_workflow_runner.py:5634) reads the workflow-level task_prompt that still carries it.

Impact

  • Monitor File Sync Changes workflows — an entire trigger type whose purpose is reacting to what changed — cannot see what changed unless they happen to use Analyze with Use changed documents.
  • Workflows with Search or No document action get nothing at all from File Sync.
  • Workflows with Use changed documents disabled get nothing.
  • The failure is silent and actively misleading: the run transcript displays the context, so it looks like the model was given it and simply ignored it.

Notes

Suggested fix:

  1. Restore the producer in _apply_file_sync_context_to_workflow():
    prepared_workflow['file_sync_prompt_context'] =file_sync_context
  2. Decide which tasks should receive it. The consumer is currently gated on include_document_action, which used to mean "task 1". After Fix workflow document picker loading and make workspace documents per-task #1284 (per-task workspace documents) that flag only means "this is a legacy record without a task-level document action", so the gate no longer expresses the intent. The context arguably belongs on the first task, or on every task, and that should be an explicit decision rather than a side effect of the document-action flag.
  3. Replace the injected-key assertion in test_workflow_task_sequence.py with a test that drives _apply_file_sync_context_to_workflow() into _execute_workflow_task_sequence(), so the producer is actually covered and this cannot silently regress in a merge again.

Related: #1282 / #1284 touched _apply_file_sync_context_to_workflow() and _build_workflow_task_execution_workflow() for per-task document actions, and deliberately left this pre-existing bug alone.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    Status
    Released

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions