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
3 changes: 3 additions & 0 deletions .github/workflows/full-public-smokes.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ jobs:
with:
node-version: "24"

- name: Install the shell used by launch-agent contract checks
run: sudo apt-get update && sudo apt-get install -y zsh

- name: Install smoke runtime dependencies
run: python -m pip install --disable-pip-version-check "jsonschema>=4.23,<5"

Expand Down
11 changes: 5 additions & 6 deletions loopx/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -814,12 +814,11 @@ def main(argv: list[str] | None = None) -> int:
output_format,
)

native_child_result = handle_native_child_command(
args, registry_path, effective_runtime_root(registry_path, args.runtime_root),
print_payload, output_format,
)
if native_child_result is not None:
return native_child_result
if args.command == "native-child":
return handle_native_child_command(
args, registry_path, effective_runtime_root(registry_path, args.runtime_root),
print_payload, output_format,
)

if args.command == "agent-directory":
return handle_agent_directory(
Expand Down
52 changes: 5 additions & 47 deletions loopx/cli_commands/turn.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@
inspect_loopx_turn_journal,
selected_turn_todo,
)
from ..control_plane.turn_driver.host_binding import managed_executor_binding
from ..control_plane.operator_provider import operator_provider_environ
from ..quota import spend_quota_slot
from ..state_refresh import refresh_state_run
Expand All @@ -67,7 +66,7 @@
render_loopx_turn_execution_markdown as _render_loopx_turn_execution_markdown,
render_loopx_turn_plan_markdown as _render_loopx_turn_plan_markdown,
)
from .turn_selection import resolve_turn_resume_session_binding
from .turn_selection import managed_executor_cli_binding, resolve_turn_resume_session_binding
from .turn_todo_writeback import (
write_turn_repair_update,
write_turn_validated_completion,
Expand Down Expand Up @@ -129,9 +128,7 @@ def handle_turn_command(
goal_id=args.goal_id,
planned_goal_ref=goal_ref,
)
strict_goal_admission = (
goal_admission if goal_admission.enabled else None
)
strict_goal_admission = goal_admission if goal_admission.enabled else None
# Planning and dry-run execution inspect existing admitted intents.
# Only an executing wake may sync inboxes or reserve a calendar window.
turn_start_hook_dispatch = {}
Expand Down Expand Up @@ -202,46 +199,9 @@ def handle_turn_command(
iteration_context_policy=args.iteration_context.replace("-", "_"),
goal_ref=goal_ref,
)
# The executor readback names where this Turn's model work runs and
# whether that host can launch here, so a caller never has to infer it
# from the host id. The explicit runner hook is the one launchability
# fact only this command layer knows.
# Goal state and machine authentication have different owners. A Goal
# runtime override must not select a different credential store.
# Resolve machine authentication once for the readback and host launch.
operator_environ = operator_provider_environ()
payload["managed_executor"] = managed_executor_binding(
args.host,
# The credential a managed Turn authenticates with is this
# machine's resolved pair, not whatever the invoking shell happens
# to export: the readback above the launch and the launch itself
# have to name the same credential.
environ=operator_environ,
dsh_runner_configured=bool(getattr(args, "dsh_runner", None)),
provider=(
getattr(args, "dsh_provider", None)
if args.host == "dsh"
else None
),
model=(
getattr(args, "dsh_model", None)
if args.host == "dsh"
else getattr(args, "codex_model", None)
if args.host == "codex-cli"
else None
),
reasoning_effort=(
getattr(args, "dsh_reasoning_effort", None)
if args.host == "dsh"
else getattr(args, "codex_reasoning_effort", None)
if args.host == "codex-cli"
else None
),
max_tokens=(
getattr(args, "dsh_max_tokens", None)
if args.host == "dsh"
else None
),
)
payload["managed_executor"] = managed_executor_cli_binding(args, environ=operator_environ)
if (
args.turn_command == "run-once"
and args.execute
Expand Down Expand Up @@ -326,9 +286,7 @@ def handle_turn_command(
goal_id=args.goal_id,
planned_goal_ref=payload.get("goal_ref"),
)
strict_goal_admission = (
goal_admission if goal_admission.enabled else None
)
strict_goal_admission = goal_admission if goal_admission.enabled else None
if strict_goal_admission is not None:
strict_goal_admission.require_current()
if payload.get("route", {}).get("kind") == "capability_action_required":
Expand Down
47 changes: 47 additions & 0 deletions loopx/cli_commands/turn_selection.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
from __future__ import annotations

import argparse
from collections.abc import Mapping
from typing import Any

from ..control_plane.turn_driver import LOOPX_TURN_SESSION_BINDING_SCHEMA_VERSION
from ..control_plane.turn_driver.host_binding import managed_executor_binding


def resolve_turn_resume_session_binding(
Expand Down Expand Up @@ -79,3 +81,48 @@ def turn_controller_advisory_primary(
):
raise ValueError("Turn advisory action portfolio has no bindable primary")
return todo_id, dict(portfolio)


def managed_executor_cli_binding(
args: argparse.Namespace, *, environ: Mapping[str, str],
) -> dict[str, Any]:
"""Adapt parsed CLI host options to the existing executor read-model owner.

The readback names where model work runs and whether the host can launch.
An explicit runner is a launchability fact owned by this CLI adapter.
Machine authentication is resolved by the caller independently of any
Goal runtime override and shared with the eventual host launch.
"""
return managed_executor_binding(
args.host,
# The credential a managed Turn authenticates with is this
# machine's resolved pair, not whatever the invoking shell happens
# to export: the readback above the launch and the launch itself
# have to name the same credential.
environ=environ,
dsh_runner_configured=bool(getattr(args, "dsh_runner", None)),
provider=(
getattr(args, "dsh_provider", None)
if args.host == "dsh"
else None
),
model=(
getattr(args, "dsh_model", None)
if args.host == "dsh"
else getattr(args, "codex_model", None)
if args.host == "codex-cli"
else None
),
reasoning_effort=(
getattr(args, "dsh_reasoning_effort", None)
if args.host == "dsh"
else getattr(args, "codex_reasoning_effort", None)
if args.host == "codex-cli"
else None
),
max_tokens=(
getattr(args, "dsh_max_tokens", None)
if args.host == "dsh"
else None
),
)
1 change: 1 addition & 0 deletions loopx/help_surface.py
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,7 @@
"import-doc-registry-authority",
"lark-inbox",
"migrate-state",
"native-child",
"ml-experiment",
"opencode2-goal-worker",
"operator-gate",
Expand Down
Loading