Ctrl K
ComunidadGuías…

feature-map/session-orchestration.md

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
# Session orchestration

An agent in a session that is private or shared read-only can send work to
another session owned by the same user, then read its status/history. It can also create private sibling
workers grouped in the left sidebar on its host or a new managed sandbox when
`sibling_sessions` is enabled in `OMNIGENT_FEATURES`; otherwise workers appear
as standalone sessions. Peer messaging is enabled
by default; `-session_orchestration` is its server kill switch and also blocks
MCP independent creation.

## Sub-features

- `message`: sender without edit-level sharing, same owner and workspace; shared destinations are
  allowed and their readers see the message. Normal queue/steering applies.
- `sender-attribution`: a delivered message starts with `[Message from session <id>]`.
  The destination's Chat drops that line from the user bubble and shows "From
  @<sender>" as a session pill that opens the sender; the agent still receives
  the prefix. The title comes from sessions the sidebar, the viewed session's
  subagents or the session cache already hold, else one lookup; an unreadable
  sender reads "From another session". The prefix is a label, not proof of origin.
- `read-results`: the manager reads history/status; replies are not forwarded.
  Existing owner-authorized reads remain allowed when a session is shared.
- `created-by`: independent workers record their creating session. The worker's
  Chat/Terminal header rechecks access when opened, hides attribution during the
  lookup, and links to the creator when accessible; otherwise it says "Created by
  another session". `sys_session_list` and `sys_session_get_info` expose
  `created_by_session_id` so managers can identify their workers across restarts;
  `sys_session_list` with `include_archived` also lists archived workers, each
  marked `archived`.
- `list-scope`: `sys_session_list`'s global `sessions` view lists only the
  caller's own sessions by default, like the sidebar's My view. Sessions other
  users shared with the caller appear only with `visibility: "shared"` (or
  `"all"` for both), and those rows carry `owner`. `include_archived` applies to
  every scope. Runner coverage: `tests/runner/test_discovery_list_pagination.py`;
  the route's scopes: `tests/server/routes/test_sessions_shared_projects.py`.
- `kill-switch`: an explicit disable refuses new peer sends and independent
  creates, even if an enable is also listed, and hides the Automations page's
  trigger templates (`/v1/info` reports `features.session_orchestration`). Restart every server replica to
  apply it. Already accepted tasks may finish; ordinary reads and child work remain.
- `messaging-control`: Settings → Sharing → Agent messaging controls new peer
  sends immediately and persists across restarts. `-peer_session_messaging` in
  the server's `OMNIGENT_FEATURES` also refuses them and locks the admin switch;
  in the host/runner environment it hides the tool and refuses calls locally.
  Neither side can override a disable on the other. Child messaging and already
  accepted work continue; session creation keeps its separate orchestration gate.
- `create`: `sys_session_create` retains child creation by default; `same_host`
  and `managed` placements create independent, initially private sessions.
  With `sibling_sessions` enabled they share one sidebar family and do not appear
  as child agents; with it disabled they remain standalone.
  Managed creation uses the server's configured default sandbox provider. A
  sibling stays in its creator's project; a different requested project or an
  unavailable source project is rejected before creation. Project defaults do
  not override the worker's agent or placement.
- `destinations`: Settings → Admin → General → **Nested agent destinations** limits new
  agents to the current host, the current host or a fresh managed sandbox, or
  any available host. The server enforces the same choice for the composer,
  uploaded custom agents, direct API calls, MCP, later host launches, and runner reassignment. Failed
  relaunches retain the prior host so restricted sessions can retry. Any available host is the
  behavior-preserving default.
- `sharing`: sharing the sender with edit (or higher) access, including public
  edit, blocks subsequent sends and independent creates. Read-only grants,
  including public read and default-public sessions, do not: viewers cannot add
  input, so they cannot steer the owner's other sessions through the sender.
  Side chats and their children also inherit restrictions from the source chain.
  Accepted work, including tasks saved while a worker starts, continues.
  Downgrading or revoking every edit grant restores eligibility.
- `scheduled`: scheduled runs, their forks and children use the new sends and
  independent creates like any private session their owner owns, so an
  automation can message the owner's other sessions or start workers. The
  Automations page's Jira/Slack/GitHub trigger templates rely on this: their
  kept session starts one worker per match (`docs/AUTOMATIONS.md`).
- `projects`: `sys_project_list` pages the owner's projects oldest first and
  their own sessions with each one's project, marking the calling session; a
  legacy label folder shows only as a session's project.
  `sys_session_update` files one of those sessions into a project by name,
  creating a missing project only once the session can move, or unfiles it
  with `""`, through the sidebar's move request; agents call it once per
  session, and `project` is its only field. An open sidebar regroups without a
  reload; a collapsed folder stays collapsed. Changing the project changes only
  folder membership, so running sessions, including the caller, keep their
  turn. Sub-agents follow their parent and a family follows its
  representative; each refusal names the session to update instead. An
  edit-shared caller cannot change a project or create one through the update,
  while listing stays an ordinary owner read. A session shared with the caller
  but owned by someone else is refused, even when it is already in the target
  project. Updates refuse to run against a server that does not advertise
  `session_move_source_checks` in `/v1/info`. `tool_groups.projects: false`
  drops both tools. Covered by
  `tests/server/integration/test_session_orchestration_projects.py::test_project_tools_list_and_file_running_sessions`
  and the browser journeys in
  `tests/e2e_ui/sessions/test_agent_files_sessions_into_projects.py`.
- `refusal`: disabled orchestration, another owner, edit-shared sender or wrong runner binding
  refuses the operation. Unsupported servers reject independent creation without
  falling back to ordinary creation. Timeouts, 408/429/5xx responses and invalid
  acknowledgements are uncertain and must not auto-retry. After uncertain
  creation, inspect existing sessions before creating another worker.

## How to get to it (user POV)

- As an admin on desktop or mobile web, open Settings → Sharing → Agent
  messaging, or `/settings/sharing`, and toggle **Message other sessions**.
- In an SDK session's Chat, ask the agent to send a task using
  `sys_session_message`, then inspect the destination's history. Its new user
  bubble shows "From @<sender>"; click the pill to open the sender.
- In a native session's Chat or agent terminal, ask for the same operation;
  the native MCP relay supplies the tools.
- In a session with creation tools enabled, ask for a worker with
  `sys_session_create` and `placement="same_host"` or `placement="managed"`.
  Pass `sandbox_provider`, `sandbox_profile_id`, and `sandbox_profile_revision`
  to choose an authorized profile/revision from the
  [provider catalog](../docs/extending/provider_profiles.md).
- In a session's Chat, ask the agent to list your projects and file some
  sessions, including itself, into an existing or new project. The sidebar folders
  update while the agent keeps running.
- In a native Claude Code session's Chat or agent terminal, ask the same; the
  relay exposes `mcp__omnigent__sys_project_list` and
  `mcp__omnigent__sys_session_update`, and the session lands in its folder
  mid-turn (`test_native_claude_files_itself_into_a_project`, nightly).
- Use the existing Share dialog to share the sender or receiver, then repeat.
  A read-only share of the sender keeps both tools working; an edit share
  refuses them.
- As an admin, open Settings → Admin → General and change **Nested agent destinations**.
  Open **Add nested agent** from a session and inspect its host picker, then try the
  same disallowed destination through the API or MCP.
- Open an independent worker in Chat or Terminal and follow its "Created by"
  link. On mobile web, the same link is in the header. Ask the manager to list
  its sessions and match `created_by_session_id` to its own session ID.
- On Automations, pick a _Jira tickets_, _Slack messages_, or _GitHub issues_
  card from suggestions on **Your automations** or the **Templates** tab at
  `/tasks?view=templates`. Suggestions appear below saved automations or the
  empty-state message with All selected and search cleared. The old
  `/tasks/templates` URL redirects to the Templates tab.
  Pick a template, fill in the trigger builder, and save: the polling automation's kept session starts one worker per new match
  with `sys_session_create`. Covered by
  `tests/e2e_ui/scheduled/test_scheduled_tasks_page.py::test_scheduled_task_trigger_template_creates_polling_manager_task`.

## Driving it with the repro environment

Preconditions: use an isolated test server with `OMNIGENT_FEATURES=sibling_sessions`
for nested creation journeys; peer messaging and standalone creation use the default settings.
Own both sessions. Same-host creation requires a connected
owned host/workspace. Managed creation requires a launch-capable provider in the
server's sandbox configuration (for example, Modal or Daytona). Other deployments
can supply their own provider through the existing launcher interface.

For `created-by`, extend the creation journey below: open the worker, reload,
and follow its creator link. Share only the worker with a second viewer and
verify they see "Created by another session" with no creator link or title.
Also revoke creator access after that viewer has visited the creator, then open
the worker through in-app navigation: no cached creator title or link should appear.
Fork the worker and verify the fork has no "Created by" label. The API/runner
contract is covered by `tests/server/integration/test_session_orchestration.py`;
the header states are covered by `web/src/shell/ChatHeader.test.tsx`.

- Own environment: `uv run --no-sync pytest
tests/e2e/test_private_session_orchestration.py --reruns 0` uses real local
  host, server, SDK and Codex processes with a scripted model. It submits chat
  requests over HTTP and checks send, history reads, same-host creation, and
  sharing refusal. It also checks that unconfigured managed creation gives a clear
  refusal without creating a session. Codex and tmux are required for the native row.
  Both harnesses also exercise a server restart with the explicit kill switch:
  existing runners remain opted in, but their subsequent peer sends and independent
  creates are refused without writes; session-info reads still work.
  It also fires an owner-created schedule through the real server/host and checks
  that the resulting worker cannot message a peer or create an independent worker.
- Component integration: `uv run --no-sync pytest
tests/server/integration/test_session_orchestration.py --reruns 0` checks the
  authenticated routes, ownership stores, refusal matrix and managed request /
  durable startup contract with simulated provisioning. It covers default provider
  selection for OSS and embedding configurations. Runner tests cover an absent
  orchestration route without falling back to ordinary creation.
  Two ASGI replicas sharing a database verify host routing for root, child and
  side-chat destinations with the production runner client/auth and a simulated
  ingress. Same-host creation covers root/child managers, inherited host routing,
  legacy keyless routing and refusal before writes on the wrong replica. A tunnel
  loss after workspace validation leaves one discoverable worker and reports
  uncertainty without retrying creation. Queue tests check refusal before saving
  and replay after sharing. Scheduled-origin tests cover sends and
  creates from a scheduled run, its full fork after schedule-history deletion,
  and its children. Off/on/off request-scoped flag changes verify that MCP and
  the orchestration endpoint create private standalone roots when nesting is off
  and siblings when on; explicit sibling requests still refuse while off.
- Browser/terminal manual check: send a distinctive task to a second session;
  open its Chat and confirm the source label and result. Ask the manager to
  read it. Share the manager read-only and repeat: the task must still arrive.
  Share it with edit access and repeat: the tool must report refusal and the
  destination must contain no new task. API runs do not prove these UI actions.
  Append `-session_orchestration` to the isolated server's feature settings and
  restart it, then repeat from a private manager: expect a disabled error, no new
  task and no independent worker. Read history/info to confirm reads still work.
- For `messaging-control`, turn the admin switch off, reload, and confirm a new
  peer send is refused. Turn it back on and confirm delivery resumes. Check that
  child work and a task accepted before disabling still finish. With the server
  flag disabled, the switch stays off and unavailable; with only the runner flag
  disabled, a new SDK/native session omits `sys_session_message`. Restart the
  affected server or host/runner after environment changes. Component coverage is
  in `web/src/pages/SharingPage.test.tsx`, `tests/tools/test_manager.py`,
  `tests/runner/test_session_orchestration.py`, and
  `tests/server/integration/test_session_orchestration.py`; persisted settings and
  storage failures are covered by `tests/server/routes/test_sessions_sharing_mode.py`.
- Live sandbox provisioning and native terminal-entered prompts require separate
  verification; local process checks do not cover them.
- Admin/UI component tests cover all three destination modes; server integration
  tests cover the matching current/other/managed/unbound admission matrix, and
  runner tests cover MCP refusal before creation.

## Gotchas

- "Created by" records origin only: workers remain independent and have their own
  permissions and lifecycle. Sharing a worker does not share its creator; the
  opaque creator ID remains in worker metadata, but the UI resolves its title
  through a separate authorized read. Forks drop the creator label. Older
  workers have no label; there is no backfill or automatic completion reply.

- Same host also means the same workspace, inherited together from the host-bound
  ancestor for child managers. Separate sessions do not isolate filesystem edits.
  Managed creation reserves its routing host ID when supported by the server.
  If the same-host worker is created but its first task is not confirmed, the
  result includes a top-level error and the created session ID. Inspect that
  session before continuing; do not automatically create a replacement or resend.
  A policy-denied first task also returns an error with the policy reason, while
  retaining the worker ID. Message acknowledgements require a boolean `queued`;
  `queued: false` alone means synchronous handling, not denial.
- Unconfirmed creation includes the requested agent ID/title and any reserved
  managed host ID. Use `sys_session_list`'s `sessions` results to discover candidate
  session IDs, then `sys_session_get_info` to inspect their metadata. A host ID is
  not a session ID; these hints do not prove creation or uniquely identify a worker.
  Same-host `wrong_replica`/409 responses can occur before persistence or during
  launch afterward, so the runner treats them as uncertain and never auto-retries.
  An early wrong-replica refusal creates no row; a late launch failure may leave
  one that the owner can inspect. Keyless legacy routing must be configured on
  the runner; independent creation has no automatic routing fallback.
- Independent creation uses `/v1/sessions/orchestrated`, which requires a source;
  older servers cannot silently accept the request as ordinary session creation.
- A fresh managed sandbox is distinct from reusing an existing managed host.
  Even the most permissive setting offers only the clicked session's existing
  managed host; another family's managed host remains unavailable.
- Project moves skip the source check in no-auth and single-user local mode,
  where nobody else can hold an edit grant. A move only ever applies to the
  owner's own sessions; the PATCH remains owner-gated per session and family member.
- A receiver shared with edit access can continue working but cannot message
  back while shared that way. A read-only share does not stop it.
- Privacy checks govern these tools. They do not confine arbitrary code holding
  owner credentials or sanitize shared content the manager reads.
- The source token authenticates its runner, not an exact session within that
  runner. Runners are trusted for every session they host: another private owned
  session on the same runner can be named as the source. Stable-ID runner pools
  using allow-listed tunnel tokens are unsupported;
  this gate requires token-derived runner IDs and refuses other bindings.
- Side chats must have no edit-level grants and an owned, available source chain
  with none either to send work or create independent workers. Nested side chats
  and their children inherit this restriction. Missing or cyclic source chains are
  refused. Ordinary reads and incoming work remain available; removing the edit
  grants restores eligibility without erasing copied history.
- Read-only viewers of a manager see its transcript, including orchestration
  tool calls, worker session IDs and history it reads from the owner's other
  sessions. Owner-authorized reads already reach shared transcripts, so this
  adds no new disclosure path; workers still start private. The check uses stored
  grant levels, so a public grant capped below its stored level still refuses.
- Peer messages carry only task text and owner attribution. They do not forward
  per-event model/tool overrides or a caller-supplied delivery ID.
  The textual source prefix is a display hint, not an authorization credential
  or authenticated provenance. Other users can copy it into ordinary messages.
  V1 deliberately keeps this advisory text instead of adding structured provenance.
- Admission is the final source check before delivery or saving a startup task.
  A queued result means acceptance, not execution; destination policy may still
  deny the task during startup replay. Successfully queued tasks can finish after
  the sender is shared with edit access; replay retains
  normal destination permissions and policy checks. The check and subsequent
  dispatch/save are not one atomic transaction. Unsharing does not erase history.
- For peer messages, an explicit wrong-replica refusal permits a bounded re-address.
  If the subsequent host lookup fails, the task was not delivered. A successful
  lookup with no host may still attempt legacy keyless delivery; uncertainty on
  that POST remains uncertain. Timeouts,
  other refusals and unparseable delivery acknowledgements are never retried.
- Scheduled origin is recorded before launch, cannot be edited by clients, and
  survives deletion of the schedule and full forks. It no longer limits
  orchestration: an unattended run messages and creates sessions under the same
  owner, privacy and sharing checks as an interactive turn. The release flag
  still turns all orchestration off.
- Existing child creation and `sys_session_send` keep their parent/completion
  semantics. Independent workers use `sys_session_message` for later work.
  The names also preserve different native approval scopes; see
  [why the messaging tools remain separate](../docs/session-messaging-tool-boundary.md).
- The server enforces the flag even though tool schemas are discoverable while
  it is disabled. Peer messaging has no additional per-agent opt-in; creation
  retains its existing `spawn` advertisement gate. Deploy the sibling-session
  schema before the application; peer messaging needs no schema migration.
  V1 treats eligible private agents as delegates across the owner's sessions.
  Unlike sharing, messaging does not grant another user access, but untrusted
  content can still influence an agent to steer other owned sessions. Enabling
  the flag accepts that broader trust; hiding a tool is not authorization.