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.314"
VERSION = "0.261.315"
IS_DEVELOPMENT = is_development_env_enabled()

# Opt-out for deployments where App Service Easy Auth is active but the platform
Expand Down
36 changes: 36 additions & 0 deletions application/single_app/functions_orchestration_planner.py
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,42 @@
words such as "this week" can stay relative.
- optionally "alerts" {"mode":"every_run"|"failures_only","severity":"info"|"low"}, "run_as"
"self"|"none", and "durable": true.
Those legacy alert modes are quiet, bell-only run-status notifications. For native conditional
monitoring alerts instead use "alerts":{"mode":"rules","rules":[...]} (1 to 20 rules).
Each rule has "severity":"info"|"low"|"medium"|"high"|"critical" and "condition"; optionally
"name", "enabled" (boolean), "delivery":"default"|"notify_only"|"popup",
"require_acknowledgment" (boolean), "sound":"off"|"once"|"repeat", "size":"small"|"medium"|"large",
and "scope":{"type":"final"|"any_task"} or {"type":"task","task":N}, where N is the 1-based
position of a task in this blueprint, not a stored id. Default scope is final.
Conditions: {"type":"run_status","statuses":[...]} (completed, failed, cancelled,
completed_with_task_errors); {"type":"task_status","statuses":[...]} (succeeded, failed);
{"type":"text_match","mode":"contains_any"|"contains_all"|"not_contains","values":[...],
"case_sensitive":false}, or {"type":"text_match","mode":"regex","pattern":"..."};
{"type":"model_evaluation","prompt":"..."}; {"type":"agent_signal","signal_name":"...",

Check warning on line 324 in application/single_app/functions_orchestration_planner.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.
"min_severity":"info"|"low"|"medium"|"high"|"critical"}; {"type":"no_output"};
or {"type":"file_sync","outcome":"changes_found"|"no_changes"|"sync_failed"}.
run_status, file_sync and agent_signal conditions must use final scope.

Check warning on line 327 in application/single_app/functions_orchestration_planner.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.
Native alerts require no email action or Microsoft 365 connection. Normally info/low go to the
bell, medium/high/critical pop up. Acknowledgment, sound and larger size require pop-up delivery;
repeat sound requires acknowledgment. These settings respect device sound preferences.
When the user explicitly requests strongest/highest attention, propose critical, delivery popup,
require_acknowledgment true, sound repeat, size large, unless their constraints say otherwise.
Disclose these attention options for approval; never make them the default for ordinary alerts.
A personal workflow alerts its owner, not arbitrary recipients or everyone in a group.
Monitor external data using an offered read-capable agent, then alert inside SimpleChat on adverse

Check warning on line 335 in application/single_app/functions_orchestration_planner.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.
output. This is different from changing an external system's alarm configuration: do not request
external writes unless that is what the user asks. A successful monitoring run may find failures.
run_status/task_status failures detect workflow execution errors, not domain problems in telemetry.

Check warning on line 338 in application/single_app/functions_orchestration_planner.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.

Check warning on line 338 in application/single_app/functions_orchestration_planner.py

View workflow job for this annotation

GitHub Actions / malicious-pr-security-review

Important - Changed line contains external connection or remote asset marker. Recommendation%3A Review whether changed code can send prompts, files, credentials, cookies, settings, logs, or user data to a new sink.
Prefer model_evaluation for semantic findings, explicitly excluding healthy/negated findings
("no active alerts"); text_match is for defined literal signals, and agent_signal needs an agent

Check warning on line 340 in application/single_app/functions_orchestration_planner.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.
known to produce supported signals. Do not infer signal support from an agent's name.

Check warning on line 341 in application/single_app/functions_orchestration_planner.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.
For example, ongoing vehicle monitoring can read telemetry and use a critical model_evaluation

Check warning on line 342 in application/single_app/functions_orchestration_planner.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.

Check warning on line 342 in application/single_app/functions_orchestration_planner.py

View workflow job for this annotation

GitHub Actions / malicious-pr-security-review

Important - Changed line contains external connection or remote asset marker. Recommendation%3A Review whether changed code can send prompts, files, credentials, cookies, settings, logs, or user data to a new sink.
rule for actual active faults, while "email me the findings" needs a mail-capable agent.

Check warning on line 343 in application/single_app/functions_orchestration_planner.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.
"Configure the source system's alarms" is an external configuration request, not native alerting.
Use the native rules for "create a workflow that monitors and alerts me"; ask for missing cadence
rather than inventing a schedule. Do not turn a one-time alert/configuration request into recurring
monitoring. If native workflow proposals are unavailable, explain the limitation rather than
claiming an external read-only integration cannot support SimpleChat alerting.
- A task can merge files with code instead of a model by adding "merge": {"kind","files",
"output_format","file_name","options"} and no agent runner. kind "tabular" (the default) appends
the rows of CSV and Excel files into one "csv" or "xlsx" file; "workbook" puts each CSV or Excel
Expand Down
5 changes: 4 additions & 1 deletion application/single_app/functions_orchestration_registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -1485,7 +1485,10 @@ def generate_image_arguments_schema(options=None):
),
'when_to_use': (
'Use one step when the user asks for work to repeat on a schedule, run when File Sync '
'finds changes, or be saved to run later. Write the blueprint from the request and the '
'finds changes, or be saved to run later, including monitoring external data and issuing '
'native SimpleChat alerts on findings. Native alerts can pop up with critical severity, '
'require acknowledgment, repeat sound and use full-screen size; they are not email or '
'changes to the external source alarm configuration. Write the blueprint from the request and the '
'workflow_planning catalog alone: this step takes no depends_on and no inputs, and no '
'other step may bind its output. When the request also wants a result now, answer it '
'once with the usual steps and select that answer as final_response.'
Expand Down
4 changes: 2 additions & 2 deletions application/single_app/functions_orchestration_workflows.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
from functions_workflow_drafts import (
BLUEPRINT_TASK_TITLE_MAX_LENGTH,
WORKFLOW_ORIGIN_SOURCE_ORCHESTRATION,
blueprint_alert_summary,
check_workflow_blueprint,
dry_run_workflow_blueprint,
validate_workflow_blueprint,
Expand Down Expand Up @@ -500,7 +501,6 @@ def _proposal_summary(blueprint, task_actions, planning, used, request_time_zone
m365_sources.update(entry.get('m365_sources') or ())
can_send = can_send or entry.get('can_send') is True
required = required or entry.get('needs_run_as') is True
alerts = blueprint.get('alerts') if isinstance(blueprint.get('alerts'), dict) else {}
return {
'name': clean_catalog_text(blueprint.get('name'), NAME_MAX_LENGTH * 2),
'description': clean_catalog_text(blueprint.get('description'), 1000),
Expand All @@ -516,7 +516,7 @@ def _proposal_summary(blueprint, task_actions, planning, used, request_time_zone
'run_as': blueprint.get('run_as') or 'none',
'required': required,
},
'alerts': {'mode': alerts.get('mode') or 'every_run', 'severity': alerts.get('severity') or 'info'},
'alerts': blueprint_alert_summary(blueprint),
'durable': True,
}, stored_type, normalized

Expand Down
85 changes: 85 additions & 0 deletions application/single_app/functions_workflow_alert_authoring.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# functions_workflow_alert_authoring.py
"""Closed, ID-free alert schemas shared by workflow AI authoring surfaces."""

from functions_workflow_alerts import (
WORKFLOW_ALERT_DELIVERIES,
WORKFLOW_ALERT_EVALUATION_PROMPT_MAX_LENGTH,
WORKFLOW_ALERT_FILE_SYNC_OUTCOMES,
WORKFLOW_ALERT_MAX_TEXT_VALUES,
WORKFLOW_ALERT_REGEX_MAX_LENGTH,
WORKFLOW_ALERT_RULE_NAME_MAX_LENGTH,
WORKFLOW_ALERT_RUN_STATUSES,
WORKFLOW_ALERT_SEVERITY_ORDER,
WORKFLOW_ALERT_SIZE_ORDER,
WORKFLOW_ALERT_SOUND_ORDER,
WORKFLOW_ALERT_TASK_STATUSES,
WORKFLOW_ALERT_TEXT_MATCH_MODES,
WORKFLOW_ALERT_TEXT_VALUE_MAX_LENGTH,
)


def _text(limit, minimum=1):
return {'type': 'string', 'minLength': minimum, 'maxLength': limit, **({'pattern': r'\S'} if minimum else {})}


def _values(options):
return {'type': 'array', 'minItems': 1, 'maxItems': len(options), 'uniqueItems': True,
'items': {'enum': sorted(options)}}


def alert_condition_schema(*, file_sync=True):
"""Native conditions without storage IDs or free-form fields."""
variants = []
fields = {
'run_status': ({'statuses': _values(WORKFLOW_ALERT_RUN_STATUSES)}, ['statuses']),
'task_status': ({'statuses': _values(WORKFLOW_ALERT_TASK_STATUSES)}, ['statuses']),
'model_evaluation': ({'prompt': _text(WORKFLOW_ALERT_EVALUATION_PROMPT_MAX_LENGTH)}, ['prompt']),
'agent_signal': ({
'signal_name': _text(WORKFLOW_ALERT_RULE_NAME_MAX_LENGTH, 0),
'min_severity': {'enum': list(WORKFLOW_ALERT_SEVERITY_ORDER)},
}, []),
'no_output': ({}, []),
}
if file_sync:
fields['file_sync'] = ({'outcome': {'enum': sorted(WORKFLOW_ALERT_FILE_SYNC_OUTCOMES)}}, ['outcome'])
for kind, (properties, required) in fields.items():
variants.append({
'type': 'object', 'additionalProperties': False, 'required': ['type', *required],
'properties': {'type': {'const': kind}, **properties},
})
for mode in sorted(WORKFLOW_ALERT_TEXT_MATCH_MODES):
properties = (
{'pattern': _text(WORKFLOW_ALERT_REGEX_MAX_LENGTH)} if mode == 'regex' else {
'values': {'type': 'array', 'minItems': 1, 'maxItems': WORKFLOW_ALERT_MAX_TEXT_VALUES,
'items': _text(WORKFLOW_ALERT_TEXT_VALUE_MAX_LENGTH)},
'case_sensitive': {'type': 'boolean'},
}
)
variants.append({
'type': 'object', 'additionalProperties': False,
'required': ['type', 'mode', 'pattern' if mode == 'regex' else 'values'],
'properties': {'type': {'const': 'text_match'}, 'mode': {'const': mode}, **properties},
})
return {'oneOf': variants}


def alert_rule_properties(task_reference, *, file_sync=True):
"""Editable personal rule fields; the caller supplies its local task-reference schema."""
return {
'name': _text(WORKFLOW_ALERT_RULE_NAME_MAX_LENGTH, 0),
'enabled': {'type': 'boolean'},
'severity': {'enum': list(WORKFLOW_ALERT_SEVERITY_ORDER)},
'delivery': {'enum': sorted(WORKFLOW_ALERT_DELIVERIES)},
'require_acknowledgment': {'type': 'boolean'},
'sound': {'enum': list(WORKFLOW_ALERT_SOUND_ORDER)},
'size': {'enum': list(WORKFLOW_ALERT_SIZE_ORDER)},
'scope': {
'oneOf': [
{'type': 'object', 'additionalProperties': False, 'required': ['type', 'task'],
'properties': {'type': {'const': 'task'}, 'task': task_reference}},
{'type': 'object', 'additionalProperties': False, 'required': ['type'],
'properties': {'type': {'enum': ['final', 'any_task']}}},
],
},
'condition': alert_condition_schema(file_sync=file_sync),
}
6 changes: 5 additions & 1 deletion application/single_app/functions_workflow_assist.py
Original file line number Diff line number Diff line change
Expand Up @@ -495,11 +495,15 @@ def parse_assist_request(body, user_id):

RULES
1. Change only what the instruction asks for, and keep everything else as it is.
2. You can't change whether the workflow is enabled, who it runs as (Run as), sharing, ownership, URL access, approval settings, IDs or the definition version, and you can't set up File Sync. When asked, explain that the user can change it in the editor.
2. You can't change whether the workflow is enabled, who it runs as (Run as), sharing, ownership, URL access, task approval settings, IDs or the definition version, and you can't set up File Sync. Alert acknowledgment is different from task approval and IS editable through alert operations. When asked for unsupported changes, explain that the user can change them in the editor.
3. For each and If blocks can't be added, removed or restructured yet. When draft.format is "flow", tasks can't be added, removed, reordered or given inputs, but you can rename a task and change its instructions, runner and documents. Explain anything else.
4. Parts of the draft marked "editable": false, a publication task's runner and documents, and a task's approval can't change. Explain instead.
5. Schedules: "every day at", "on weekdays at", "every Monday at" and "on the 1st at" are calendar schedules (set_schedule_calendar). "Every N minutes" and "every N hours" are intervals (set_schedule_interval). time_of_day is a 24-hour HH:MM time. Leave "timezone" out unless the user names a time zone; the schedule then keeps its current time zone or uses time_zone. An interval can't be shorter than choices.minimum_interval_seconds.
6. Alerts: mode "every_run" alerts after every run at a priority. Mode "rules" alerts only when a rule matches, so "only alert me when..." means mode "rules" plus a rule for that condition: a model_evaluation rule whose prompt states the condition, or a text_match rule for exact words. Match the severity to the wording; urgent or critical means high or critical. Mode "off" turns alerts off.
These are native SimpleChat alerts, not email and not changes to an external system's alarms. A task can read external telemetry with a read-only agent and a rule can alert on its findings even when the run succeeds. run_status/task_status failures mean workflow execution failed, not that the monitored system failed. Use model_evaluation for semantic findings, explicitly distinguishing actual problems from "no active alerts" or healthy results; use text_match only for defined literal signals. Use agent_signal only when the agent actually emits supported alert signals.
A file_sync alert condition can watch changes_found, no_changes or sync_failed in an existing File Sync workflow; editing that rule does not configure the File Sync trigger. Run status, File Sync and agent signals watch the whole run (final scope).
Info/low normally go to the bell; medium/high/critical normally pop up. Rules support require_acknowledgment (boolean), sound ("off", "once", "repeat"), and size ("small", "medium", "large"). Acknowledgment keeps the pop-up returning across pages/devices until acknowledged. Pop-up options need resolved pop-up delivery; repeat sound needs acknowledgment. These settings do not override device sound preferences. Update an existing rule by its alert handle with update_alert_rule, preserving everything not requested. "Require acknowledgment on Rule 2" changes that rule, not sound, size, other rules, or task approvals; also set delivery "popup" if needed and explain it. If the target is ambiguous, ask.
When the user explicitly requests the highest/strongest attention possible, propose critical severity, delivery "popup", require_acknowledgment true, sound "repeat", size "large", unless their other constraints say otherwise. Explain the acknowledgment, repeating sound, and full-screen consequences in the reply for review. Otherwise keep quieter defaults and unrequested options unchanged. Do not substitute an email task for native alerting unless email is explicitly requested. These are personal workflows; alerting "us" does not grant group audience or new recipients. Changes remain draft-only until saved.
7. Runners: choose agents and models only from "choices". A task inherits the workflow's runner unless it has its own agent or model. A task that sends email needs an agent with the Microsoft 365 action.
8. "attached_documents" are documents the user attached with #. Place each one by what the instruction asks:
- Read now to shape the workflow ("use #X to design the steps"): don't place it. Say in the reply that it was read as context.
Expand Down
Loading
Loading