Skip to content

Microsoft 365 Copilot

The most constrained provider in the set.

streaming structured output (prompt-only) tool calls health (no-op) discovery

Setup

pip install "anyinfer[azure]"
client = ai.Client(
    [
        ai.ProviderSettings.of(
            "m365-copilot",
            options={"tenant_id": "...", "client_id": "..."},
        ),
    ]
)
result = client.generate(prompt, target="m365-copilot:m365-copilot")

Alias: m365.

Interactive Authentication

There is no client-credential or daemon flow for this API. Sign-in opens a browser. Consequently:

  • It cannot run headless, in CI, or in a container without a human present.
  • It is exempt from live conformance testing.
  • health() does not trigger a sign-in: a health probe that opens a browser window would be a hostile surprise, and the router calls it speculatively.

If a token is already held, supply it and skip the interactive flow:

ai.ProviderSettings.of("m365-copilot", api_key="env://M365_TOKEN")

This is the only workable path for automated use.

Supported

Behavior Support
Streaming No (a whole response, emitted as one delta)
Structured output Prompt-injected only
Tools No
Sampling controls Ignored by the service
Usage Generally absent
Schema repair Capped at one round trip

Ignored Parameters

Temperature, top-p, max tokens, stop sequences, tools, and reasoning effort are declared on the descriptor as ignored, so requesting them emits a ParameterDropped telemetry event rather than silently doing nothing:

class Watch:
    def on_event(self, event):
        if isinstance(event, ai.ParameterDropped):
            log.warning("%s ignored %s", event.target, event.parameter)

That event matters: a temperature=0 that had no effect is otherwise indistinguishable from one that worked.

Schema Repair

The descriptor caps schema repair at a single round trip, since every request here is an interactively-authenticated Graph call against service-kept conversation state (the most expensive request shape in the registry). Asking for more is clamped rather than refused, and the clamp is reported the same way an ignored parameter is:

result = client.generate(
    prompt,
    target="m365-copilot:default",
    schema=PERSON,
    repair=ai.Repair(max_attempts=3),
)
# ParameterDropped(parameter="repair.max_attempts", reason="... at most 1 ... 3 requested")

Prompt-only schema enforcement plus one repair is a real failure rate. Validate result.structured defensively, and prefer a provider with a native structured-output mode when the shape matters more than the M365 grounding does.

Notes

  • Citations and attributions are retained on result.raw rather than normalized: build the client with retain_raw=True to keep them, since raw payloads are discarded by default. v1 has no typed model for them, and inventing one would freeze a shape before it is understood.
  • A 401/403 hints at both re-authentication and the tenant licensing and admin-consent requirements, because those are the usual real causes.
  • For automation, streaming, tools, or sampling control, use another provider; GitHub Copilot covers the subscription-billed case with fewer constraints. This adapter is for applications with a genuine M365 Copilot requirement.

Wire Contract

For the exact request/response fields this adapter depends on, see contracts/m365-copilot.md.

See Also