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

# Opt-out for deployments where App Service Easy Auth is active but the platform
Expand Down
3 changes: 2 additions & 1 deletion application/single_app/functions_agent_delegation.py
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,8 @@


def _canonical_agent(record, scope_type, scope_id):
result = deepcopy(record)
# A Cosmos point read returns CosmosDict, a dict subclass that deepcopy keeps.

Check warning on line 229 in application/single_app/functions_agent_delegation.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.
result = deepcopy(dict(record))
if scope_type == "personal" and result.get("user_id") != scope_id:
raise PermissionError(UNAVAILABLE_MESSAGE)
if scope_type == "group" and result.get("group_id") != scope_id:
Expand Down
163 changes: 117 additions & 46 deletions application/single_app/functions_orchestration_external_sources.py

Large diffs are not rendered by default.

13 changes: 12 additions & 1 deletion docs/admin/orchestration.md
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,11 @@ setting is the agents button on the classic chat page (`/chats`). V2 has no cont
it, and it's saved as off for a user whose settings were saved before they turned agents
on, so many V2 users have it off. It still applies to agents the user didn't choose.

Before **0.261.291**, every Ask an agent step was refused just before the agent ran, with
"This step's agent or action isn't available to you right now". The step's access check
accepted only a plain dictionary, and Cosmos DB returns a stored agent as an SDK subclass
of one. Chat without Orchestrate was unaffected.

The opt-in adds no second action allowlist or approval system. Existing scope,
ownership, group membership, enablement and governance rules still determine which actions
are available, and access is checked again when work runs. An action removed or revoked
Expand Down Expand Up @@ -693,6 +698,11 @@ run ID to correlate its hashed identifier in
The HTTP status alone is insufficient: a planning stream can return HTTP 200 and
then report a rejected proposal.

Since **0.261.291**, when a web search, linked-page, deep research, agent, action or
memory step is refused, `[ORCHESTRATION_EXTERNAL_SOURCES] A step's source was refused.`
names the check that failed in `sc_reason`. It shares `sc_run_id_hash` and
`sc_step_id_hash` with the step's failure event.

| Symptom | Likely cause | Fix |
| --- | --- | --- |
| No orchestration control appears in chat | The setting is off, or the user is in the classic interface. | Confirm Enable Chat Orchestration is on, and that the user is on a V2 chat page. |
Expand All @@ -716,7 +726,8 @@ then report a rejected proposal.
| A Microsoft 365 step says plans can only read Microsoft 365 data | The action enables only send, invitation or mark-as-read functions, which plans never run. | Enable a read function on the action, or use it from chat without a plan. |
| Before 0.261.270, a Microsoft 365 step said plans can't use Microsoft 365 in a shared conversation | Earlier versions refused Microsoft 365 steps in shared conversations. | Upgrade to 0.261.270 or later. The user's own request now counts as consent to share what the step reads. See [Microsoft 365 actions in plans](#microsoft-365-actions-in-plans). |
| Before 0.261.270, every action or agent step failed with "A required retained result is unavailable or changed", while the same request worked with Orchestrate off | The step's configuration check refused it. For Microsoft 365 actions, the check couldn't see the action's Microsoft 365 selection. Local agents were refused outright. Failure events log `sc_authority_reason=external_configuration_unavailable` for `action_invoke` or `agent_invoke`. | Upgrade to 0.261.270 or later. Agent and action steps now trust the signed-in session, as manual chat does. See [Retained external-source authorization](#retained-external-source-authorization). |
| Before 0.261.289, an 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" | The user's own agents setting was off. Planning offered the picked agent, but the step's access check didn't count the pick as permission. Failure events log `sc_authority_reason=result_external_capability_unavailable` for `agent_invoke`. It isn't specific to shared conversations: a request without a picked agent can still work because its plan uses an action instead. | Upgrade to 0.261.289 or later. Before upgrading, the user can turn agents on with the agents button on the classic chat page (`/chats`). See the [selected agent with agents turned off fix]({{ '/explanation/fixes/ORCHESTRATION_SELECTED_AGENT_DISABLED_PREFERENCE_FIX/' | relative_url }}). |
| Before 0.261.289, an 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" | The user's own agents setting was off. Planning offered the picked agent, but the step's access check didn't count the pick as permission. Failure events log `sc_authority_reason=result_external_capability_unavailable` for `agent_invoke`. It isn't specific to shared conversations: a request without a picked agent can still work because its plan uses an action instead. | Upgrade to 0.261.291 or later. 0.261.289 fixed this check, but the step still failed at a later one until 0.261.291, so turning agents on doesn't help before then; see the next row. See the [selected agent with agents turned off fix]({{ '/explanation/fixes/ORCHESTRATION_SELECTED_AGENT_DISABLED_PREFERENCE_FIX/' | relative_url }}). |
| Before 0.261.291, every Ask an agent step failed with "This step's agent or action isn't available to you right now", while the same agent answered with Orchestrate off | Cosmos DB returns a stored agent as an SDK subclass of a dictionary, and the step's access check accepted only a plain dictionary, so it refused every agent. Failure events log `sc_authority_reason=result_external_source_unavailable` for `agent_invoke`. | Upgrade to 0.261.291 or later. No setting or data change is needed. Before upgrading, turn Orchestrate off to use the agent. See the [agent document type fix]({{ '/explanation/fixes/ORCHESTRATION_AGENT_DOCUMENT_TYPE_FIX/' | relative_url }}). |
| Before 0.261.270, an @mention of a person in a shared conversation was sent to the model when Orchestrate was on | Orchestrate planned every message without applying the shared conversation's send rule. | Upgrade to 0.261.270 or later. See [Shared conversations](#shared-conversations). |
| A participant sees "Only the person who started this shared conversation can use Orchestrate here" | A request reached the planner from someone other than the person who started the shared conversation. The V2 composer normally answers their requests the classic way instead. | Turn off Orchestrate for that request, or ask the person who started the conversation to ask it. |
| The person who started a shared conversation sees "Orchestrate can't be used in this shared conversation because an earlier version kept another participant's private copy of it" | Before 0.261.270, Orchestrate saved a private copy for whoever used it first, under the shared conversation's ID. Only one record can have that ID. | Turn off Orchestrate to ask the assistant. To restore Orchestrate, remove that participant's record from the conversations container: its ID is the shared conversation's ID. The `[ORCHESTRATION]` warning logs `sc_reason=shared_conversation_stale_copy`. |
Expand Down
23 changes: 23 additions & 0 deletions docs/explanation/features/ORCHESTRATION_EXTERNAL_SOURCE_ACCESS.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,13 @@ agent failed while the preference was off, even though planning and execution
accepted it. See the
[selected agent with agents turned off fix](../fixes/ORCHESTRATION_SELECTED_AGENT_DISABLED_PREFERENCE_FIX.md).

**Updated in version: 0.261.291.** The provider accepts the stored agent as any
dictionary, because a Cosmos DB point read returns a dictionary subclass, and still
requires its exact scoped reference to match. Before this, every Ask an agent step was
refused just before it ran. Each refusal is now logged with the check that failed.
See the [agent document type fix](../fixes/ORCHESTRATION_AGENT_DOCUMENT_TYPE_FIX.md)
([#1699](https://github.com/microsoft/simplechat/issues/1699)).

## Purpose and scope

An external Gather result is the content an authorized adapter actually returned,
Expand Down Expand Up @@ -65,6 +72,10 @@ Membership in a catalog alone is insufficient: the provider also calls
`resolve_delegation_agent` or `resolve_action_manifest` for the exact stored
integration. These existing APIs recheck scope membership, governance, enablement,
and identity without invoking a model or plugin.
`resolve_delegation_agent` returns the stored agent as a plain dictionary. The
provider accepts any dictionary from an agent resolver, copies it into a plain one,
and requires its scoped reference (ID, scope type and scope ID) to equal the catalog
selection's. The mapping's own type is never treated as proof of identity.
An injected action resolver must retain the real `ScopedActionManifest` origin;
matching fields in a plain dictionary are not proof of a scoped authorized read.

Expand Down Expand Up @@ -348,6 +359,18 @@ Every other refusal stays `result_unavailable`. Exception text is never
read, and the reason code is never shown to the user. Step, saved-wait,
finalization and composition failure events log it as `sc_authority_reason`.

Since 0.261.291, the provider also logs each refusal once, as
`[ORCHESTRATION_EXTERNAL_SOURCES] A step's source was refused.`, before the
invocation capture normalizes it. The event carries `sc_stage`
(`external_source_preflight`, `external_source_admission` or
`external_source_read`), `sc_authority_reason`, `sc_capability_id`, the hashed
conversation, run and step identifiers, and `sc_reason`, the check that failed,
such as `integration_not_found` or `capability_not_available`. Reads log at
Information level, because saved results are rechecked whenever they're opened.
Only the refusal code crosses the invocation capture; the check stays in this
event. See the [orchestration failure diagnostics](../../reference/logging-tags.md#orchestration-failure-diagnostics)
for the full list of checks.

### Invocation failure classification

`ExternalIdentityServiceError` and `ExternalConfigurationServiceError` inherit
Expand Down
Loading
Loading