`ctx.inject_message` could only reach an existing gateway session (`session_key`), so an
orchestrator plugin that opens a chat/thread itself (a bot-authored Discord forum post never
comes back as an inbound message) had no way to get an agent turn there.
`origin` takes the SessionSource.to_dict() shape. The gateway creates (or continues) that chat's
session through the adapter's normal message path, in the profile whose plugin manager loaded the
plugin, and the reply goes back to the origin chat:
- Profile: resolved from the manager's immutable home, never an ambient one. The origin may not
name another profile, the gateway's own routing for that chat through that profile's adapter
must land in the plugin's profile, and the profile needs its own connected adapter for the
platform (another profile's bot is never borrowed). Refusals are synchronous False + one log line.
- Authorization: same current-allowlist check as the session_key path (no bypass for host code).
- Multiplex: handle_message runs inside the profile's runtime scope so the spawned turn AND the
reply send after it inherit that profile's home and secrets (applies to the session_key path too,
which used to send from the default loop context).
- allow_gateway_injection is read from the plugin's own profile config.
- Plugin/system turns (event.internal) skip the human first-contact notes (onboarding intro and
the "no home channel" nudge), which were posted into the plugin's fresh thread.
Requested by canonicle-desk in #132609.
Closes#132609