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
9 changes: 9 additions & 0 deletions docs/integrations/deepseek-harness-connector.md
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,15 @@ line, `deepseek-v4-flash@high` in the shipped shape, with the provider prepended
only when it is not the shipped one -- it is one line because every plan carries
it, and the agent-facing output budget is a contract.

`runtime_probe` distinguishes an import probe (`scope: "probing_interpreter"`,
`module: "deepseek_harness"`) from an injected runner (`scope: "configured_runner"`,
`module: null`, no import attempted). Availability applies to the answering
interpreter or runner, not the whole machine, and does not prove provider
authentication. The Chat refusal directs the operator to run `loopx doctor`
in the service environment, check `python.executable`, and install the SDK in
that same environment before restarting. Interpreter paths stay in local doctor
output, outside the Turn payload.

`run-once --execute` fails closed on that verdict: status `unavailable`, no host
invocation, no journal write, and no quota spend, with
`dsh_runtime_unavailable`, `operator_credential_unconfigured`, or
Expand Down
1 change: 1 addition & 0 deletions examples/loopx-managed-turn-operator-flow-smoke.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ def main() -> None:
machine_defaults=MANAGED_DEFAULTS,
credential_source="machine_store",
session=None,
module_probe=_runtime_installed,
)
if channel.get("executor_endpoint") != "dsh":
fail(f"the channel must resolve the machine's executor: {channel}")
Expand Down
58 changes: 49 additions & 9 deletions examples/loopx-turn-managed-executor-binding-smoke.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,20 +27,24 @@
from loopx.cli import main as cli_main # noqa: E402
from loopx.control_plane.turn_driver import executor as turn_executor # noqa: E402
from loopx.control_plane.turn_driver.host_binding import ( # noqa: E402
DSH_RUNTIME_MODULE,
DSH_RUNTIME_UNAVAILABLE,
EXECUTOR_KIND_INDIVIDUAL,
EXECUTOR_KIND_MANAGED,
MANAGED_RUNTIME_PROBE_SCHEMA_VERSION,
OPERATOR_CREDENTIAL_UNCONFIGURED,
REMEDY_CONFIGURE_DSH_RUNTIME,
REMEDY_CONFIGURE_OPERATOR_CREDENTIAL,
REMEDY_SELECT_INDIVIDUAL_HOST,
RUNTIME_PROBE_SCOPE_INTERPRETER,
)


GOAL_ID = "loopx-turn-managed-executor-fixture"
AGENT_ID = "codex-managed-executor-fixture"
TODO_ID = "todo_managedexec01"
CREDENTIAL_ENV = "DEEPSEEK_API_KEY"
CREDENTIAL_VALUE = "sk-fixture-operator"
RUNTIME_MODULE = "deepseek_harness"


Expand Down Expand Up @@ -239,6 +243,29 @@ def _managed_binding(payload: dict[str, Any]) -> dict[str, Any]:
return binding


def _expect_probe(binding: dict[str, Any], *, available: bool) -> None:
"""Pin the scope of the launchability verdict at the CLI boundary.

``managed_executor_binding`` answers from the interpreter that probes, and
one machine can hold a service environment where the dsh SDK resolves and a
checkout environment where it does not. The verdict is only actionable when
the readback says which environment answered, so the public payload this
smoke reads has to carry it -- for the plan, for the fail-closed refusal,
and for every executor kind, so no reader branches on the field's absence.
"""

probe = binding["runtime_probe"]
assert probe["schema_version"] == MANAGED_RUNTIME_PROBE_SCHEMA_VERSION, probe
assert probe["module"] == DSH_RUNTIME_MODULE, probe
assert probe["scope"] == RUNTIME_PROBE_SCOPE_INTERPRETER, probe
assert probe["available"] is available, probe
# This readback is carried into the Turn execution payload, so it stays
# public-safe: no absolute path and no credential value.
serialized = json.dumps(probe)
assert "/" not in serialized, serialized
assert CREDENTIAL_VALUE not in serialized, serialized


def main() -> int:
with tempfile.TemporaryDirectory(
prefix="loopx-turn-managed-executor-"
Expand All @@ -254,17 +281,17 @@ def main() -> int:
assert exit_code == 0, payload
assert payload["host"]["kind"] == "codex-cli", payload
uncredentialed_default = payload["managed_executor"]
assert (
uncredentialed_default["executor_kind"] == EXECUTOR_KIND_INDIVIDUAL
), uncredentialed_default
assert uncredentialed_default["executor_kind"] == EXECUTOR_KIND_INDIVIDUAL, (
uncredentialed_default
)
assert uncredentialed_default["operator_credential_bound"] is False, (
uncredentialed_default
)
assert uncredentialed_default["available"] is None, uncredentialed_default

# 2. The credential resolves and authenticates the managed default.
with (
_operator_credential("sk-fixture-operator"),
_operator_credential(CREDENTIAL_VALUE),
_harness_runtime(available=True),
):
exit_code, payload = _run_cli(_plan_command(registry, runtime, project))
Expand All @@ -274,23 +301,27 @@ def main() -> int:
assert bound["credential_env"] == CREDENTIAL_ENV, bound
assert bound["operator_credential_bound"] is True, bound
assert bound["available"] is True, bound
_expect_probe(bound, available=True)

# 3. With the runtime genuinely missing the same plan reports the other
# typed reason rather than promising a launch.
# typed reason rather than promising a launch, and the unchanged
# verdict travels with the scope it was answered at.
with (
_operator_credential("sk-fixture-operator"),
_operator_credential(CREDENTIAL_VALUE),
_harness_runtime(available=False),
):
exit_code, payload = _run_cli(_plan_command(registry, runtime, project))
assert exit_code == 0, payload
missing = _managed_binding(payload)
assert missing["available"] is False, missing
assert missing["unavailable_reason"] == DSH_RUNTIME_UNAVAILABLE, missing
_expect_probe(missing, available=False)

# 4. An explicit individual host stays selected even while the operator
# credential is configured, and makes no launch claim.
# credential is configured, and makes no launch claim. It probes no
# runtime, and the field is still present as an explicit ``None``.
with (
_operator_credential("sk-fixture-operator"),
_operator_credential(CREDENTIAL_VALUE),
_harness_runtime(available=True),
):
exit_code, payload = _run_cli(
Expand All @@ -302,6 +333,7 @@ def main() -> int:
assert individual["executor_kind"] == EXECUTOR_KIND_INDIVIDUAL, individual
assert individual["available"] is None, individual
assert individual["operator_credential_bound"] is False, individual
assert individual["runtime_probe"] is None, individual

# 5. Executing an explicitly selected managed host without the
# credential fails closed: typed status, no host invocation, no
Expand All @@ -328,12 +360,16 @@ def main() -> int:
], refusal
assert refusal["remediation_host"] == "codex-cli", refusal
assert refusal["remediation_env_vars"] == [CREDENTIAL_ENV], refusal
# The operator reads the refusal, so the refusal is where the scope has
# to be visible: this environment answered "the credential is missing",
# not "the runtime is missing".
_expect_probe(refusal["managed_executor"], available=True)
_expect_no_effects(refusal)
_expect_no_journal(refusal, runtime)

# 6. The same refusal covers a provably unlaunchable runtime.
with (
_operator_credential("sk-fixture-operator"),
_operator_credential(CREDENTIAL_VALUE),
_harness_runtime(available=False),
):
exit_code, refusal = _run_cli(
Expand All @@ -353,6 +389,10 @@ def main() -> int:
REMEDY_CONFIGURE_DSH_RUNTIME,
REMEDY_SELECT_INDIVIDUAL_HOST,
], refusal
# The refusal that sends an operator to provision a runtime names the
# environment that could not import it, so the same readback cannot be
# taken for a machine-level fact.
_expect_probe(refusal["managed_executor"], available=False)
_expect_no_effects(refusal)
_expect_no_journal(refusal, runtime)

Expand Down
17 changes: 16 additions & 1 deletion examples/operator-provider-credential-smoke.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,19 @@ def fail(message: str) -> None:
raise SystemExit(f"operator provider credential smoke failed: {message}")


def _runtime_installed(*_args: object, **_kwargs: object) -> bool:
"""Report the optional managed runtime as installed.

This smoke is about which credential authenticates the managed host, not
about whether this host happens to have that runtime on disk, so it must not
read the machine it runs on. The typed ``dsh_runtime_unavailable`` refusal is
covered by ``examples/loopx-turn-managed-executor-binding-smoke.py`` and
``tests/test_turn_managed_executor_binding.py``.
"""

return True


class _Handler(OperatorProviderRequestMixin):
"""Drive the real request mixin without opening a socket."""

Expand Down Expand Up @@ -133,7 +146,9 @@ def main() -> None:
fail("an unconfigured machine must keep the individual default host")

refused = managed_executor_binding(
"dsh", environ=operator_provider_environ(runtime_root)
"dsh",
environ=operator_provider_environ(runtime_root),
module_probe=_runtime_installed,
)
if refused.get("unavailable_reason") != OPERATOR_CREDENTIAL_UNCONFIGURED:
fail(f"the managed host must name the missing credential: {refused}")
Expand Down
5 changes: 3 additions & 2 deletions loopx/chat_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,9 @@ def _host_tool_gate(summary: str, next_action: str) -> dict[str, str]:
AGENT_ENDPOINT_UNAVAILABLE = "agent_endpoint_unavailable"
AGENT_ENDPOINT_NEXT_ACTIONS = {
"dsh_runtime_unavailable": (
"Install the DeepSeek Harness runtime (`python -m pip install "
"'loopx[deepseek-harness]'`) and restart LoopX Chat."
"The LoopX Chat service interpreter cannot import deepseek_harness. "
"Run `loopx doctor` in that service environment and check python.executable; "
"install `loopx[deepseek-harness]` in the same environment, then restart LoopX Chat."
),
"operator_credential_unconfigured": (
"Set the managed executor credential (DEEPSEEK_API_KEY, with "
Expand Down
9 changes: 7 additions & 2 deletions loopx/chat_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

import hashlib
from pathlib import Path
from typing import Any, Mapping
from typing import Any, Callable, Mapping

from .control_plane.operator_credential import (
env_text,
Expand Down Expand Up @@ -451,6 +451,7 @@ def manager_channel_binding(
session: Mapping[str, Any] | None = None,
machine_defaults: Mapping[str, Any] | None = None,
credential_source: str | None = None,
module_probe: Callable[[str], bool] | None = None,
) -> dict[str, Any]:
"""Project the steward channel's resolved executor, model, and their source.

Expand Down Expand Up @@ -485,12 +486,15 @@ def manager_channel_binding(
executor_kind = MANAGER_ENDPOINT_KINDS.get(endpoint, "")
credential_env = ""
execution_profile: str | None = None
runtime_probe: dict[str, Any] | None = None
if executor_kind == MANAGER_EXECUTOR_KIND_MANAGED:
managed = managed_executor_binding(endpoint, environ=environ)
managed = managed_executor_binding(endpoint, environ=environ, module_probe=module_probe)
credential_env = str(managed.get("credential_env") or "")
execution_profile = managed.get("execution_profile")
available: bool | None = managed.get("available")
unavailable_reason: str | None = managed.get("unavailable_reason")
if isinstance(managed.get("runtime_probe"), Mapping):
runtime_probe = dict(managed["runtime_probe"])
else:
available, unavailable_reason = None, None
model, model_source = manager_model_resolution(
Expand Down Expand Up @@ -523,6 +527,7 @@ def manager_channel_binding(
"execution_profile": execution_profile,
"available": available,
"unavailable_reason": unavailable_reason,
"runtime_probe": runtime_probe,
"model": model,
"model_source": model_source,
**manager_channel_session_mode_readback(session),
Expand Down
16 changes: 16 additions & 0 deletions loopx/control_plane/turn_driver/host_binding.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,9 @@
# launchability fact this projection checks without side effects.
DSH_RUNTIME_MODULE = "deepseek_harness"
DSH_RUNTIME_UNAVAILABLE = "dsh_runtime_unavailable"
# Module availability is scoped to this interpreter, not the whole machine.
MANAGED_RUNTIME_PROBE_SCHEMA_VERSION = "managed_runtime_probe_v0"
RUNTIME_PROBE_SCOPE_INTERPRETER = "probing_interpreter"
# A managed host is billed to the operator's own endpoint. Without the operator
# credential (or an explicit injected runner) LoopX cannot authenticate that
# endpoint, so it refuses instead of letting the managed default consume
Expand Down Expand Up @@ -175,6 +178,10 @@ def managed_executor_binding(
with it, the provider claims to authenticate. It is ``None`` for every
non-managed executor because neither the profile nor the credential belongs
to an individual or generic host.

``runtime_probe`` states what the ``dsh_runtime_unavailable`` verdict is a
claim about, so a reader does not take a process-level answer for a
machine-level fact.
"""

if host == MANAGED_HOST:
Expand Down Expand Up @@ -212,6 +219,12 @@ def managed_executor_binding(
"unavailable_remediation": _managed_unavailable_remediation(
unavailable_reason
),
"runtime_probe": {
"schema_version": MANAGED_RUNTIME_PROBE_SCHEMA_VERSION,
"scope": "configured_runner" if dsh_runner_configured else RUNTIME_PROBE_SCOPE_INTERPRETER,
"module": None if dsh_runner_configured else DSH_RUNTIME_MODULE,
"available": runtime_available,
},
}
return {
"schema_version": MANAGED_EXECUTOR_BINDING_SCHEMA_VERSION,
Expand All @@ -228,6 +241,9 @@ def managed_executor_binding(
"available": None,
"unavailable_reason": None,
"unavailable_remediation": [],
# The same field exists for every executor kind so a reader never
# branches on its presence; only a managed executor probes a runtime.
"runtime_probe": None,
}


Expand Down
14 changes: 12 additions & 2 deletions tests/test_manager_channel_binding.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@
from loopx.chat_server import ChatHTTPServer, ChatRequestHandler
from loopx.chat_store import ChatSessionStore
from loopx.control_plane.turn_driver import host_binding
from loopx.control_plane.turn_driver.host_binding import (
RUNTIME_PROBE_SCOPE_INTERPRETER,
)
from loopx.extensions.lark.cli_resolution import LarkCliResolution


Expand Down Expand Up @@ -563,7 +566,7 @@ def test_a_managed_host_without_a_credential_raises_the_credential_gate(
assert "DEEPSEEK_API_KEY" in error.gate["next_action"]


def test_a_managed_host_without_its_runtime_names_the_install_step(
def test_missing_runtime_gate_identifies_the_service_environment(
tmp_path, monkeypatch
):
# The credential is configured and the runtime is missing, so the launch is
Expand All @@ -575,7 +578,10 @@ def test_a_managed_host_without_its_runtime_names_the_install_step(

assert error.error_code == "agent_endpoint_unavailable"
assert error.gate["kind"] == "host_tool_gate"
assert "pip install" in error.gate["next_action"]
assert "service interpreter" in error.gate["next_action"]
assert "loopx doctor" in error.gate["next_action"]
assert "python.executable" in error.gate["next_action"]
assert "same environment" in error.gate["next_action"]


def test_unknown_endpoint_keeps_the_untyped_lookup_error(tmp_path):
Expand Down Expand Up @@ -651,6 +657,10 @@ def test_a_channel_without_a_session_reads_as_unbound(monkeypatch):
MANAGER_CHANNEL_SESSION_MODE_SOURCE_UNBOUND
)
assert binding["session_status"] is None
# The channel quotes the governed Turn surface's probe scope, so a surface
# showing `dsh_runtime_unavailable` can say which environment answered.
assert binding["runtime_probe"]["scope"] == RUNTIME_PROBE_SCOPE_INTERPRETER
assert binding["runtime_probe"]["available"] is True


def test_an_unrecognized_session_mode_is_named_rather_than_coerced():
Expand Down
Loading