Skip to content

Honour a hand-picked agent in orchestration steps while agents are off - #1696

Merged
Paul Lizer (paullizer) merged 7 commits into
paullizer-react-v2-uifrom
paullizer-literate-engine
Oct 7, 2026
Merged

Paul Lizer (paullizer) merged 7 commits into
paullizer-react-v2-uifrom
paullizer-literate-engine

Conversation

@paullizer

@paullizer Paul Lizer (paullizer) commented Oct 7, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • Problem: An orchestration "Ask an agent" step for an agent the user picked (or tagged with @) failed with "This step's agent or action isn't available to you right now, so it didn't run." It was first reported in a shared conversation, but sharing isn't the cause. Failure telemetry showed OrchestrationInvocationDeniedError with sc_authority_reason=result_external_capability_unavailable for agent_invoke.

  • Root cause: The user's saved Enable Agents preference (enable_agents) was off. V2 has no control for it, and update_user_settings writes enable_agents=False when it saves settings without that key, so V2 users can end up with it off and no way to change it. The planner and harness count a picked (seeded) agent as permission. But OrchestrationExternalSourceProvider._capability() used the raw preference and an un-narrowed catalog, so _agent_request_gate refused the step when it ran. The same agent worked in a private chat only because that plan used an action step, and action steps don't check this preference.

  • Fix: For agent sources only, the provider now reads the run's seeded agent and resolves the agent catalog narrowed to that seed (seeds={"agent": ...}). It then counts the seed as permission for the agent gate. It fails closed:

    • A seed that no longer resolves (selected_agent_unavailable) is refused as result_external_source_unavailable.
    • Any other catalog error is re-raised.
    • A narrowed catalog with more than one agent is refused.

    Action sources never see seeds. A user with agents off and no seed is still denied, as before.

  • Impact: Users with agents off can now run steps for the agent they picked. The seed only satisfies the user-preference gate. Deployment settings (Semantic Kernel, allow_user_agents) and the scope, governance and record checks still apply. Until this ships, affected users can turn agents on with the agents button on the classic chat page (/chats).

Linked issue

N/A. No issue was filed for this fix.

Release Notes & Latest Features

  • New Feature
  • Bug Fix
  • UI Enhancement
  • Breaking Change
  • Internal only

Is this visible to end users?

  • Yes
  • No

Is this admin-facing (Admin Settings, governance, deployment, config)?

  • Yes
  • No

Should this become a Latest Feature card?

  • Yes
  • No
  • Already added

Screenshot needed for the card?

  • Yes
  • No
  • Attached

Version bump

  • application/single_app/config.py VERSION third segment bumped, or not needed because this is docs-only
  • deployers/version.txt bumped, or not needed because deployers/ was not changed

This fix is version 0.261.282. The branch first used 0.261.279, but paullizer-react-v2-ui had already used that for the V2 user settings release, so config.py conflicted. I merged the base (f1c3ddab0) in 46f019279 and resolved VERSION to 0.261.282. Then 2b2d06edf renumbered every other reference to the fix:

  • the docstring of functions_orchestration_external_sources.py
  • the fix doc
  • the feature doc
  • docs/admin/orchestration.md: the "Actions and agents" paragraph and the troubleshooting row
  • the regression test: its header, assert_app_version_at_least, and two docs assertions

If another PR into the base takes 0.261.282 first, renumber the same places to the next free version. The test's docs assertions fail if the docs are renumbered without the test.

Testing / validation

All of these ran on the merged tree (head 2b2d06edf, base f1c3ddab0).

  • python -m pytest functional_tests/test_orchestration_seeded_agent_preference_fix.py functional_tests/test_orchestration_external_sources.py functional_tests/test_orchestration_session_trusted_sources.py functional_tests/test_orchestration_external_identity.py functional_tests/test_orchestration_external_bootstrap.py functional_tests/test_orchestration_external_pre_effect.py functional_tests/test_orchestration_external_preflight_adapter.py functional_tests/test_orchestration_agent_selection.py functional_tests/test_orchestration_v2_plan_backend.py -q -p no:cacheprovider: passed, 506 passed and 282 subtests passed. I ran this in a venv with cryptography==46.0.7. With cryptography 50.0.0 and pyOpenSSL 25.3.0, OpenSSL.crypto fails to import and two of these suites can't be collected. That's an environment issue, not this change.

  • New regression test functional_tests/test_orchestration_seeded_agent_preference_fix.py (29 tests): with the base's functions_orchestration_external_sources.py swapped in, 16 fail and 13 pass, including a reproduction of the reported case. With the fix, all 29 pass.

  • Local runs of the PR checks, on the two changed application/ Python files (application/single_app/config.py, application/single_app/functions_orchestration_external_sources.py):

    • python scripts\check_broken_access_control.py --base-sha f1c3ddab0a99fe4c5a5725c6e16802d56e4c1f82 --head-sha 2b2d06edfe617ae7da63549ecac16665146eda63 <files>: passed for 2 files.
    • python scripts\check_xss_sinks.py --base-sha f1c3ddab0a99fe4c5a5725c6e16802d56e4c1f82 --head-sha 2b2d06edfe617ae7da63549ecac16665146eda63 <files>: passed for 2 files.
    • python scripts\check_swagger_routes.py <files>: passed. It skips the check because neither file defines a Flask route.
    • python functional_tests\route_tests\test_route_blueprint_policy_inventory.py, test_route_unauthenticated_policy_contract.py and test_route_policy_test_coverage.py: passed, 12/12, 7/7 and 2/2.
    • python -m py_compile on each application/single_app/*.py: passed, 0 failures.
  • python scripts\check_malicious_pr_security_review.py --base-sha f1c3ddab0a99fe4c5a5725c6e16802d56e4c1f82 --head-sha 2b2d06edfe617ae7da63549ecac16665146eda63 --report-file <report> --verify-release-age: passed, no blocker findings.

    • No dependency, CI-policy or external-URL findings.
    • The 223 "Important - Needs investigation" items are keyword markers on changed lines that mention agents, permissions or audit, which is the subject of this change.
    • The two "sensitive data source" markers are a test-support import and a sentinel string the test uses to prove internal diagnostics don't leak.
  • python functional_tests\test_docs_site_quality.py: passed, 6/6.

  • python functional_tests\test_docs_app_surface_coverage.py: passed, 7/7.

  • Investigation of the failed run used App Insights / Log Analytics telemetry and read-only Cosmos reads. They confirmed that:

    • the run seeded the user's personal agent and the user's enable_agents was off;
    • the agent is local, owned by the user and enabled;
    • the deployment allows Semantic Kernel, user agents and agent_invoke.

    So with this fix the step passes the remaining checks. It hasn't been deployed or re-tested end to end in the app yet.

Documentation

  • Release notes updated, or not needed: not added; skipped at the author's request.
  • Feature documentation updated, or not needed:
    • docs/explanation/features/ORCHESTRATION_EXTERNAL_SOURCE_ACCESS.md: seeded-agent catalog narrowing, the enable_agents caveat, and a corrected description of how agent_invoke and action_invoke refusals surface as integration_unavailable.
    • docs/admin/orchestration.md: a note in "Actions and agents", a clarified "Plans never propose an agent" row, and a new troubleshooting row.
  • Fix documentation updated, or not needed: new docs/explanation/fixes/ORCHESTRATION_SELECTED_AGENT_DISABLED_PREFERENCE_FIX.md.

Security checklist

  • New Flask routes include @swagger_route(security=get_auth_security()) (N/A, no new routes)
  • Settings sent to non-admin frontends use sanitize_settings_for_user() (N/A, no settings sent to the frontend)
  • Browser JavaScript is served from local SimpleChat static assets only; no CDN-hosted JS (N/A, no frontend changes)
  • No secrets, keys, connection strings, or local-only artifacts are included

Paul Lizer (paullizer) and others added 7 commits October 7, 2026 11:25
An Ask an agent step for an agent the user picked failed with "This step's
agent or action isn't available to you right now" whenever the user's
enable_agents preference was off, which is the stored default for V2 users.
Planning and execution treat a pick as permission and narrow the catalog to
it, but OrchestrationExternalSourceProvider rechecked the step with the raw
preference and an un-narrowed catalog, so _agent_request_gate refused
agent_invoke (result_external_capability_unavailable). It looked like a
shared-conversation failure only because the personal request had no pick.

The provider now narrows the agent catalog to the run's seeded agent and
counts the pick as permission for that agent only. Scope, membership,
governance and enabled state are still rechecked on every run and read.

Version 0.261.279.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
…lizer-literate-engine

Resolve the VERSION conflict in application/single_app/config.py with 0.261.282, the next free version after the base's 0.261.281.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
The base branch already uses 0.261.279 for the Control Center dashboard and V2 user settings releases. Move this fix's version references in the provider docstring, regression test, and fix, feature and admin docs to 0.261.282, the version config.py now carries.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
…lizer-literate-engine

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
The base branch now uses 0.261.282 through 0.261.287, so the fix moves to the next free version.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
…lizer-literate-engine

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
The base branch now uses 0.261.288 for Ask AI in the agent and action editors, so the fix and VERSION move to the next free version.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@paullizer
Paul Lizer (paullizer) merged commit d4cfde7 into paullizer-react-v2-ui Oct 7, 2026
11 checks passed
Paul Lizer (paullizer) added a commit to paullizer/simplechat that referenced this pull request Oct 7, 2026
Brings in V2 at d4cfde7 (microsoft#1694, microsoft#1696, VERSION 0.261.289).

Conflicts:
- application/single_app/config.py: only the VERSION line. Took V2's
  file (0.261.289).
- docs/explanation/release_notes.md: V2's file byte-for-byte, with this
  branch's own (v0.261.288) section inserted at the very top, above V2's
  first section, its own (v0.261.288). Every V2 section is unchanged.

docs/admin/orchestration.md merged cleanly: V2's edits and this branch's
two lines don't touch each other.

The next commit renumbers this branch's section and VERSION to
0.261.290, above V2's 0.261.289.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Paul Lizer (paullizer) added a commit to paullizer/simplechat that referenced this pull request Oct 7, 2026
V2 now uses 0.261.289 (microsoft#1694, microsoft#1696) and has its own 0.261.288 release
notes section, so this branch's version moves above both. Renumbers the
same 20 lines in 15 files as the previous bump: config.py, this branch's
release-notes section, the documentation version notes and the new
tests' headers. V2's own (v0.261.288) release-notes section is
untouched. The tests' version floor stays 0.261.253.

Refs microsoft#1549

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
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