Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion application/single_app/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@
EXECUTOR_TYPE = 'thread'
EXECUTOR_MAX_WORKERS = 30
SESSION_TYPE = 'filesystem'
VERSION = "0.261.340"
VERSION = "0.261.341"
IS_DEVELOPMENT = is_development_env_enabled()

# Opt-out for deployments where App Service Easy Auth is active but the platform
Expand Down
6 changes: 6 additions & 0 deletions application/single_app/functions_diagram_operations.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,12 @@
- `classDiagram` for types, fields, and inheritance.
- `gantt` for scheduled work, `mindmap` for hierarchies of ideas, `journey` for user journeys.

For a schedule or two-lane event timeline, use `flowchart TB` with a labelled subgraph for each

Check warning on line 89 in application/single_app/functions_diagram_operations.py

View workflow job for this annotation

GitHub Actions / malicious-pr-security-review

Important - Changed line contains secret or sensitive data source marker. Recommendation%3A Pair this source with any nearby network, logging, serialization, or process execution sink before approving.
activity lane and `direction LR` inside each lane. Keep the supplied relative times in the
event labels (for example before, during, and after an activity); do not invent calendar dates,
measurements, or events to fill a lane. This shows event order, not a quantitatively scaled
time axis. Use a native data chart instead when the user needs plotted numerical values.

Keep the source valid so it renders on the first attempt:
- Give every node a quoted label, for example `app["Simple Chat App Service"]`. Unquoted parentheses, braces, angle brackets, colons, `#`, and quotes inside a label break the parser.
- Never use `end`, `graph`, `class`, `style`, `subgraph`, or `click` as a node id: they are reserved words and the diagram will not parse. Write `end_state` or `graph_node` instead.
Expand Down
93 changes: 65 additions & 28 deletions application/single_app/functions_orchestration_composition.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# functions_orchestration_composition.py
"""Explicit one-call content preparation from named authorized result readers.
"""Explicit content preparation from named authorized result readers.

Version: 0.261.305
Version: 0.261.341
Refusals for a missing signed-in session reported as their own failure in: 0.261.209
Charts drawn upstream reach the model as their placement tokens in: 0.261.293
No retrieval, file-format inference, upload, publication, or implicit sibling inputs.
Expand All @@ -12,9 +12,10 @@
proposal cards). In a turn that may propose a workflow they also receive the user's local
time, worded as the workflow's scheduled runs will receive theirs.

JSON preparation states each declared output's exact shape, asks the endpoint for a JSON
object, and makes one corrective call when a reply breaks a declared rule. Neither reply is
logged; the log records only application codes and hashed identifiers.
JSON preparation states each declared output's exact shape and asks for a JSON object.
Preparation makes at most one corrective call for a broken output rule or an omitted
explicit chart/diagram. Continued visual omission keeps usable content for finalization's
partial-delivery report. Neither reply is logged; logs contain codes and hashed identifiers.

When an input carries citation values, such as the Microsoft 365 sources an action step lists,
the step is told to copy them verbatim after the claims they support (0.261.303).
Expand All @@ -29,12 +30,13 @@

from content_screening.contracts import ScreeningError
from functions_appinsights import log_event, workflow_log_context
from functions_chart_operations import normalize_inline_chart_markdown
from functions_chart_operations import INLINE_CHART_BLOCK_LANGUAGE, normalize_inline_chart_markdown
from functions_diagram_operations import MERMAID_BLOCK_LANGUAGE
from functions_m365_citations import M365_ANSWER_STYLE_INSTRUCTIONS
from functions_mixed_source_orchestration import MixedSourceCancellationError
from functions_orchestration_context import conversation_reference_messages
from functions_orchestration_deliverables import (
compose_deliverable_guidance, place_deck_images, place_image_tokens,
compose_deliverable_guidance, missing_compose_visuals, place_deck_images, place_image_tokens,

Check warning on line 39 in application/single_app/functions_orchestration_composition.py

View workflow job for this annotation

GitHub Actions / malicious-pr-security-review

Important - Changed line contains secret or sensitive data source marker. Recommendation%3A Pair this source with any nearby network, logging, serialization, or process execution sink before approving.
)
from functions_orchestration_memory import OrchestrationMemoryError
from functions_orchestration_registry import (
Expand Down Expand Up @@ -199,6 +201,14 @@
))


def _compose_visual_rules(step, values):
languages = {VISUAL_CHART: INLINE_CHART_BLOCK_LANGUAGE, VISUAL_DIAGRAM: MERMAID_BLOCK_LANGUAGE}
return ' '.join(
f'Include the explicitly requested {kind} in a ```{languages[kind]}``` block.'
for kind in missing_compose_visuals(step, values)
)


def validate_prepared_output(specification, value, *, profile_validator=None):
"""Validate public prepared data; profile validators are injected server code."""
kind = specification['kind']
Expand Down Expand Up @@ -328,10 +338,10 @@


def adapter_compose(step, context, *, settings, user_id, emit=None, cancel_requested=None):
"""Prepare all declared outputs in one content-generation call.
"""Prepare all declared outputs, with at most one corrective content-generation call.

A JSON reply that breaks a rule stated by the declared outputs gets exactly one
corrective call naming that rule. Any other failure, or a second bad reply, fails the step.
Output-contract errors and omitted explicit visuals share that allowance. An unusable
correction fails; usable content still missing its visual reaches final delivery checks.
"""
service = require_result_service(context)
producer = context.result_producer(step)
Expand Down Expand Up @@ -548,12 +558,25 @@
recheck()
response = invoke(messages, stage='orchestration_compose', metadata=metadata)
recheck()
reply_error = None
try:
values = prepared_values(response)
except ValueError as error:
correction = None if plain_text else _compose_correction(error, outputs)
if correction is None:
raise
reply_error = error
correction = ' '.join(part for part in (correction, _compose_visual_rules(step, {})) if part)
else:
visual_rules = _compose_visual_rules(step, values)
correction = ' '.join((
'Your previous reply omitted an explicitly requested visual.', visual_rules,
'Use only the supplied context; do not invent values or events to fill a visual.',
'Return only the complete prepared text.' if plain_text else ' '.join((
JSON_OUTPUT_POLICY, *(_output_shape(output) for output in outputs),

Check warning on line 576 in application/single_app/functions_orchestration_composition.py

View workflow job for this annotation

GitHub Actions / malicious-pr-security-review

Important - Changed line contains security control, sanitization, or audit marker. Recommendation%3A Confirm the change does not weaken auth, CSRF, CSP, XSS defenses, settings sanitization, redaction, audit logging, or tests.
)),
)) if visual_rules else None
if correction:
# One corrective call, told which declared rule the reply broke. The reply itself
# stays in the model conversation only; it is never logged.
retry_messages = [
Expand All @@ -565,24 +588,38 @@
output_tokens=getattr(invoke, 'output_tokens', None),
)
if retry_audit['decision'] != 'full_input':
raise
log_event(
'[ORCHESTRATION_EXECUTOR] Prepared content did not match its declared outputs; asking once more.',
level=logging.INFO,
extra={
**workflow_log_context(
run_id=context.run_id, conversation_id=getattr(context, 'conversation_id', None),
step_id=step['step_id'],
),
'capability_id': step['capability_id'], 'reason': 'compose_output_retry',
'error_type': type(error).__name__,
**({'execution_code': error.code} if isinstance(error, ResultContractError) else {}),
},
)
recheck()
response = invoke(retry_messages, stage='orchestration_compose', metadata=metadata)
recheck()
values = prepared_values(response)
if reply_error is not None:
raise reply_error
log_event(

Check warning on line 593 in application/single_app/functions_orchestration_composition.py

View workflow job for this annotation

GitHub Actions / malicious-pr-security-review

Important - Changed line contains security control, sanitization, or audit marker. Recommendation%3A Confirm the change does not weaken auth, CSRF, CSP, XSS defenses, settings sanitization, redaction, audit logging, or tests.
'[ORCHESTRATION_EXECUTOR] Visual correction exceeds the context budget; retaining prepared content.',
level=logging.INFO,
extra={
**workflow_log_context(
run_id=context.run_id, conversation_id=getattr(context, 'conversation_id', None),

Check warning on line 598 in application/single_app/functions_orchestration_composition.py

View workflow job for this annotation

GitHub Actions / malicious-pr-security-review

Important - Changed line contains AI, plugin, agent, or workspace boundary marker. Recommendation%3A Check whether prompts, chat history, uploaded documents, embeddings, citations, settings, or identity can cross a new boundary.

Check warning on line 598 in application/single_app/functions_orchestration_composition.py

View workflow job for this annotation

GitHub Actions / malicious-pr-security-review

Moderate - Changed line contains obfuscation, dynamic loading, or hidden payload marker. Recommendation%3A Confirm the changed code is not hiding behavior, decoding payloads, or bypassing normal review.
step_id=step['step_id'],
),
'capability_id': step['capability_id'], 'reason': 'compose_visual_retry_budget',
},
)
else:
log_event(

Check warning on line 605 in application/single_app/functions_orchestration_composition.py

View workflow job for this annotation

GitHub Actions / malicious-pr-security-review

Important - Changed line contains security control, sanitization, or audit marker. Recommendation%3A Confirm the change does not weaken auth, CSRF, CSP, XSS defenses, settings sanitization, redaction, audit logging, or tests.
'[ORCHESTRATION_EXECUTOR] Prepared content did not match its declared requirements; asking once more.',
level=logging.INFO,
extra={
**workflow_log_context(
run_id=context.run_id, conversation_id=getattr(context, 'conversation_id', None),

Check warning on line 610 in application/single_app/functions_orchestration_composition.py

View workflow job for this annotation

GitHub Actions / malicious-pr-security-review

Important - Changed line contains AI, plugin, agent, or workspace boundary marker. Recommendation%3A Check whether prompts, chat history, uploaded documents, embeddings, citations, settings, or identity can cross a new boundary.

Check warning on line 610 in application/single_app/functions_orchestration_composition.py

View workflow job for this annotation

GitHub Actions / malicious-pr-security-review

Moderate - Changed line contains obfuscation, dynamic loading, or hidden payload marker. Recommendation%3A Confirm the changed code is not hiding behavior, decoding payloads, or bypassing normal review.
step_id=step['step_id'],
),
'capability_id': step['capability_id'],
'reason': 'compose_output_retry' if reply_error is not None else 'compose_visual_retry',
**({'error_type': type(reply_error).__name__} if reply_error is not None else {}),
**({'execution_code': reply_error.code} if isinstance(reply_error, ResultContractError) else {}),
},
)
recheck()
response = invoke(retry_messages, stage='orchestration_compose', metadata=metadata)
recheck()
values = prepared_values(response)
partial = any(reader.completeness.status == 'partial' for reader in readers.values())
limitations = tuple(dict.fromkeys(
limitation for reader in readers.values() for limitation in reader.completeness.limitations
Expand Down
29 changes: 27 additions & 2 deletions application/single_app/functions_orchestration_deliverables.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
# functions_orchestration_deliverables.py
"""What the user asked to receive, and whether the plan can actually deliver each part.

Version: 0.261.293
Version: 0.261.341
Implemented in: 0.261.138
Document merge recipes added in: 0.261.245
One-sheet or sheet-per-file question for spreadsheet merges added in: 0.261.246
Gathered results and charts must reach the answer or a file, with chart delivery notes, in: 0.261.293
Explicit compose visual omission checks shared with final delivery in: 0.261.341

The planner lists its plan's deliverables first: the answer, files, images, charts, and
diagrams the user asked for (``requested: explicit``) and anything it adds on its own
Expand Down Expand Up @@ -1589,6 +1590,30 @@ def _draws_charts(step):
)


def has_visual_block(text, kind):
"""The same format-presence check for compose correction and final answer delivery."""
return _VISUAL_FENCES[kind] in text


def missing_compose_visuals(step, values):
"""Explicit visuals this enabled compose step owes but its Markdown does not include.

The compiled brief contains planned deliverables only. Unavailable, suggested and
separately produced images are not requirements for a corrective content call.
"""
if not step.get('enabled', True):
return []
text = '\n'.join(
values[name] for name in _markdown_outputs(step) if type(values.get(name)) is str
)
required = {
entry['kind'] for entry in step.get('deliverable_context') or ()
if entry.get('relation') == 'delivers' and entry.get('requested') == REQUESTED_EXPLICIT
and entry.get('enabled', True) and entry.get('kind') in _VISUAL_FENCES
}
return [kind for kind in _VISUAL_FENCES if kind in required and not has_visual_block(text, kind)]


def gathered_charts(plan, task_results, read_value):
"""The charts each charting gather step drew from its exact rows, by step id in plan order.

Expand Down Expand Up @@ -1671,7 +1696,7 @@ def visual_delivery(plan, statuses, answer, charts):
elif step['step_id'] in answer_steps:
if not finished:
reasons.append('step_not_completed')
elif _VISUAL_FENCES[kind] in answer:
elif has_visual_block(answer, kind):
shown = True
else:
reasons.append('not_in_answer')
Expand Down
7 changes: 6 additions & 1 deletion application/single_app/functions_orchestration_planner.py
Original file line number Diff line number Diff line change
Expand Up @@ -661,7 +661,12 @@ def resolve_planner_client(settings):
capability_availability.visual_outputs.image_proposals is true, image proposal cards the user
approves before an AI image is generated. Decide from the request whether a visual materially
helps, even unasked, and list it in compose "visuals" (chart, diagram, image_proposal); a chart or
diagram the user asked for is also a chart or diagram deliverable. Plan the gathering each
diagram the user asked for is also a chart or diagram deliverable. A schedule or event timeline
with lanes for activities (such as eating and drinking before, during, and after a ride) is a
diagram, even if the user calls it a chart: declare a diagram deliverable and set compose
"visuals" to ["diagram"]. Preserve the supplied events and relative times; do not invent
measurements or calendar dates to turn a schedule into a numerical plot. Use native charts
for measured values, numerical trends, and category comparisons instead. Plan the gathering each
visual needs: exact values for a chart, entities and relationships for a diagram, and concrete
visual details for an image. When a chart needs rows an action retrieves, set that
action_invoke step's visuals to ["chart"]; it charts the exact rows, and the compose step that
Expand Down
128 changes: 128 additions & 0 deletions docs/explanation/fixes/ORCHESTRATION_TIMELINE_VISUAL_DELIVERY_FIX.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
# Orchestration Timeline Visual Delivery Fix

**Version: 0.261.341**

Fixed in version: **0.261.341**, recorded in
`application/single_app/config.py`.

## Issue

An Orchestrate request asked to turn an earlier gravel-ride nutrition plan into a
two-lane schedule: eating and fueling in one lane, drinking and hydration in the
other, from before the ride through recovery. The answer-writing task completed,
but the plan panel marked the chart **Not delivered** with the reason
"The answer did not include it."

## Root cause

The planner could classify an event schedule as a numerical chart because the
user called it a chart. That selected analytical-chart instructions, which

Check warning on line 19 in docs/explanation/fixes/ORCHESTRATION_TIMELINE_VISUAL_DELIVERY_FIX.md

View workflow job for this annotation

GitHub Actions / malicious-pr-security-review

Important - Changed line contains AI, plugin, agent, or workspace boundary marker. Recommendation%3A Check whether prompts, chat history, uploaded documents, embeddings, citations, settings, or identity can cross a new boundary.
discourage charts for purely textual material and forbid substituting Mermaid
for numerical data charts. A schedule is better represented as a structural
diagram with event labels than as invented numerical series.

Separately, compose accepted any nonempty Markdown as prepared content. Its
single corrective call covered malformed JSON outputs, not an omitted explicit
visual. Finalization correctly detected the missing chart, but only after the
answer-writing task had finished. A Mermaid schedule declared as a chart also
failed delivery: charts require a `simplechart` fence, whereas diagrams require
a `mermaid` fence.

The screenshot did not include the complete generated answer, saved plan, or
model response. The investigation reproduced this delivery path locally; it
does not establish precisely why the deployed model omitted the chart.

## Technical changes

- `functions_orchestration_planner.py` distinguishes activity schedules and
event timelines from measured numerical plots. Schedule requests use diagram
deliverables and the structured `diagram` visual flag, even when called charts.
- `functions_diagram_operations.py` explains a two-lane representation using
`flowchart TB`, labelled subgraphs, and `direction LR` within each lane.
Relative times remain event labels, without invented calendar dates or values.
- `functions_orchestration_deliverables.py` shares the existing visual-format
presence rule between compose omission checks and final answer delivery.
Compiled deliverable context identifies which explicit, enabled visuals the
compose step owes.
- `functions_orchestration_composition.py` makes at most one application-level
corrective call for either an output-shape problem or a missing explicit chart
or diagram. Correction must still satisfy the declared output kinds and
schemas. Charts already placed from upstream results satisfy the check without
another model call.

The retry preserves context-budget checks, authorization, cancellation, named
inputs, and hashed logging. Neither generated answer text nor source content is
included in corrective-call logs. No integration action or retrieval is repeated
to correct the prepared answer.

## Delivery behavior

Before this fix, a prose-only Markdown reply immediately finished the compose
step and reached finalization with its chart missing.

After this fix, the step requests a complete corrected answer once. A successful
correction carries the renderable visual into the answer and its delivery state
becomes **Delivered**. Suggested visuals do not cause retries.

If correction cannot fit the context budget, the original usable answer is kept.
If a schema-valid correction still omits the visual, the corrected usable answer
is kept. Existing finalization reports partial completion and **Not delivered**
for an explicit visual missing from the final answer. Invalid correction output,
provider failures, and revoked access retain their existing explicit failure
paths rather than masquerading as successful correction.

Saved plans are not silently relabelled. A schedule already declared as a chart
needs replanning to become a diagram. True numerical charts continue to require
their native chart format.

## Validation

The regression harness supplies the earlier nutrition plan as conversation
reference data and runs the real schema, executor, result retention, compose,
and final publication services with offline model replies. It covers:

- omission followed by a delivered two-lane diagram;
- repeated omission retaining a usable answer and partial delivery;
- native-chart correction without accepting Mermaid as a numerical chart;
- JSON-shape and visual corrections sharing one allowance, without a third call;
- malformed corrections, context-budget refusal, and access/cancellation changes
immediately before correction;
- suggested visuals, already-present visuals, and upstream charts avoiding
unnecessary model calls;
- correction logs containing codes and hashed identifiers, not private replies.

Coverage lives in `test_orchestration_compose_output_retry.py`,
`test_orchestration_visual_outputs.py`,
`test_orchestration_action_chart_delivery.py`, and the existing
`test_mermaid_diagram_prompt_guidance.py` suite. The shared deliverables fixture
also supports retained conversation history for this scenario.

These four suites passed together: **84 tests passed**. Eight additional
deliverables-contract regressions passed, including shared fixture use, CSV
delivery, visual flag derivation, and answer binding behavior. Documentation
surface coverage passed all seven checks and site quality passed all six checks.
The regression failed before the implementation with the same failed-run/partial-
outcome combination as the reported missing visual. A headless Chromium probe
rendered the two-lane example using the pinned local Mermaid 11.17.2 bundle,
confirmed both lanes and relative-time labels, and made no network requests.

The local system Python had an incompatible OpenSSL dependency combination;
validation used a separate virtual environment without changing shared packages.
Additional broad deliverables runs encountered native PyMuPDF access violations
in existing Office-renderer tests. Those unrelated renderer paths are not
changed or claimed as validated by this fix.

## Limitations

Visual selection and the corrective answer remain model-generated. One correction
is not a guarantee that a visual will be produced, and it must not invent source
data to force success. Format presence is not complete Mermaid syntax validation,
chart semantic validation, or proof that every distinct requested visual appears.
The final answer's existing delivery check remains authoritative.

The two-lane flowchart shows event sequence and relative-time labels, not exact
time-scaled duration. This fix adds no browser library, chart type, setting,
capability, route, or deployment requirement.

See [Review and edit orchestration plans](../../guides/review-and-edit-orchestration-plans.md)
for the user-facing behavior.
Loading
Loading