Skip to content

feat(session-create): expose terminal_launch_args on sys_session_create - #4345

Open
javiermontescarrera wants to merge 1 commit into
omnigent-ai:mainfrom
javiermontescarrera:feat/session-create-terminal-launch-args
Open

feat(session-create): expose terminal_launch_args on sys_session_create#4345
javiermontescarrera wants to merge 1 commit into
omnigent-ai:mainfrom
javiermontescarrera:feat/session-create-terminal-launch-args

Conversation

@javiermontescarrera

Copy link
Copy Markdown

Problem

sys_session_create did not forward terminal_launch_args, so top-level sessions launched via agent_id or config_path could not declare a native-terminal bypass stance. A headless cursor-native worker uploaded via config_path therefore ran without --yolo even when its bundle declared executor.config.yolo: true, and stalled on cursor-agent's in-terminal approval prompts — surfaced as web elicitation cards that no human is present to answer.

Root cause

The --yolo auto-derivation (_derive_terminal_launch_args_from_spec) only fires for named sub-agent creates (body.sub_agent_name set) — not for top-level config_path/agent_id sessions (sub_agent_name is null). Those take the else branch (orchestration.py:5842) which reads caller-supplied body.terminal_launch_args. The bundle's yolo: true is silently ignored for top-level sessions — by design (a caller cannot inject launch wiring by smuggling args through a spawn body; the flat-list + bounds-check is the security boundary).

So the bypass stance must be declared at the launch call, not derived from an uploaded bundle — exactly what the web UI's permission-mode selector already does for top-level sessions.

Fix (surgical, additive)

The server already accepts and validates terminal_launch_args on both create paths:

  • JSON → SessionCreateRequest.model_validate
  • multipart → _parse_session_create_metadataSessionCreateMetadata_validate_terminal_launch_args

The only gap was the tool surface. This PR:

  • Adds a terminal_launch_args param to the sys_session_create schema.
  • Forwards it verbatim into the JSON body (_build_session_create_body) and the multipart metadata (_upload_config_bundle).
  • The server keeps owning validation/bounds-checking — no security-boundary change.
  • Restores UI ↔ API parity (the web permission-mode selector already sets body.terminal_launch_args for top-level sessions; the programmatic API now can too).

Why not derive --yolo for top-level sessions instead?

That would collapse the security boundary: any uploaded bundle with yolo: true would auto-bypass approvals, and it would be a cursor-native special case. Declaring the stance at the (trusted) call site is the correct layer separation and generalizes across cursor/codex/claude-native.

Tests

  • Adds test_sys_session_create_forwards_terminal_launch_args — asserts the field reaches the create body verbatim.
  • All 8 existing sys_session_create tests pass (no regression).

sys_session_create did not forward terminal_launch_args, so top-level
sessions launched by agent_id/config_path could not declare a native-
terminal bypass stance. The server already accepts and validates the
field on BOTH create paths (JSON SessionCreateRequest.model_validate and
multipart SessionCreateMetadata via _parse_session_create_metadata ->
_validate_terminal_launch_args); only the tool surface omitted it.

Effect: a headless cursor-native worker uploaded via config_path ran
WITHOUT --yolo even with executor.config.yolo: true, because the
--yolo auto-derivation (_derive_terminal_launch_args_from_spec) only
fires for NAMED sub-agent creates (body.sub_agent_name set), not for
top-level/config_path sessions. The worker then stalled on cursor-
agent's in-terminal approval prompts, surfaced as web elicitation
cards that a headless run has no human to answer.

Fix (surgical, additive): add a terminal_launch_args param to the
sys_session_create schema and forward it verbatim into the JSON body
(_build_session_create_body) and the multipart metadata
(_upload_config_bundle). The server keeps owning validation/bounds-
checking; this restores UI<->API parity (the web permission-mode
selector already sets body.terminal_launch_args for top-level sessions).

Adds a regression test asserting the field reaches the create body.
@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

@javiermontescarrera Thanks for the PR! It doesn't reference an issue yet.

We require an issue for every PR, so the work can be prioritized before it's reviewed. Add one to the description:

  • Closes #123 if this PR finishes the issue. That links it, gives your PR the issue's priority, and closes the issue when this merges. You can also link it from the Development section of the sidebar.
  • Part of #123 if this is one step towards it. Related to, Towards, and Refs work the same way, and leave the issue open.

No issue exists for this yet? Open one first, then reference it. That's how we track what's worth doing, and it's usually quicker than it sounds. Note a reference has to point at an issue: naming another PR doesn't count.

The only exceptions are changes with no user-visible behaviour: pure Refactor / chore, Docs, or Test / CI work. If that's genuinely what this is, check that box under Type of change. Anything that fixes a bug, adds a feature, or changes the UI needs an issue, even when it also touches docs or tests.

See CONTRIBUTING.md for the full policy.

No action is taken beyond this comment.

@github-actions github-actions Bot added the size/M Pull request size: M label Aug 7, 2026
@github-actions
github-actions Bot requested a review from dbczumar August 7, 2026 11:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/M Pull request size: M

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants