Skip to content

feat(chat): bind the steward channel defaults to the operator credential - #4417

Closed
huangruiteng wants to merge 4 commits into
codex/managed-executor-readback-20260915from
codex/steward-channel-binding-20260915
Closed

huangruiteng wants to merge 4 commits into
codex/managed-executor-readback-20260915from
codex/steward-channel-binding-20260915

Conversation

@huangruiteng

@huangruiteng huangruiteng commented Sep 15, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

The steward (manager) chat channel now binds its own executor and model defaults
to the operator credential, for the same reason the governed Turn surface does:
a configured operator credential must not silently fall back to one individual's
CLI login. Stacked on the managed executor readback change.

Changes

  • loopx/control_plane/operator_credential.py holds the operator credential
    facts once; the Turn host binding re-uses it instead of keeping a second copy.
  • manager_channel_binding() projects the resolved executor endpoint, its
    source, a typed transport reason, the resolved model with its source, and the
    credential env var name (never its value).
  • manager_model_config() defaults the model to the operator provider
    (deepseek-flash) when a credential is configured and keeps the vendor default
    otherwise; LOOPX_MANAGER_MODEL still wins.
  • open_manager_session() resolves its endpoint only when the caller did not set
    one; the Lark routing fallbacks resolve the same default.
  • A session request for a managed host that has no Chat transport now fails as
    the typed managed_host_chat_transport_unsupported host-tool gate (Chat 424
    with gate, Lark 400 with gate) instead of unknown Agent endpoint.
  • The manager per-turn context projects channel_binding next to
    model_defaults.

Validation

  • tests/test_manager_channel_binding.py (10 cases: defaults, credential
    binding, blank credential, override precedence, process environment,
    endpoint resolution, typed gate, unknown endpoint, capability projection with
    and without a binding) plus tests/test_chat_manager_context.py: 22 tests
    green.
  • Re-validated on the committed head: 142 tests green across the manager
    channel, chat manager context/details/inspection, Lark API contract, manager
    context handoff/roundtrip/tracking, Turn default host, and Turn executor
    suites.
  • examples/loopx-steward-channel-binding-smoke.py proves the binding, the
    override, the no-credential default, and the typed gate.

Boundaries

  • No provider calls; no credential values appear in any projection or test.
  • The managed host still cannot hold an interactive session; this change makes
    that limit explicit instead of half-connecting the steward channel.

Review notes

  • The typed managed-transport gate now lives with the chat-agent error contract
    (chat_agent.agent_endpoint_error), so chat_runtime.py does not grow
    (1498 lines, limit 1500) and chat_server.py stays at its reviewed 1513-line
    ceiling; the unused OPERATOR_CREDENTIAL_ENV_VARS import is removed.
  • The packaged Personal Workspace bundle is rebuilt from the changed dashboard
    source (loopx/web/chat/index.html, asset-retention.json, hashed assets),
    which is what Verify packaged Personal Workspace is current compares.
  • Validation: maintainability ratchet green on the touched modules, 38
    manager-channel/context tests, 68 Turn tests, and
    examples/loopx-steward-channel-binding-smoke.py green.

The steward (manager) channel still defaulted to one individual's CLI login: executor endpoint `codex` plus the vendor model `gpt-6-astra`, overridable only by `LOOPX_MANAGER_MODEL`.

Quote the operator credential facts from one shared module (`loopx/control_plane/operator_credential.py`) so the governed Turn surface and the chat channel cannot drift, and resolve the steward defaults from it: with a credential configured the steward model follows the operator provider (`deepseek-flash`) instead of the vendor default, without one it keeps `gpt-6-astra`, and `LOOPX_MANAGER_MODEL` still wins.

The interactive chat transport is a separate fact from the credential. A resolved endpoint without one reports the typed `dsh_chat_transport_unsupported` reason instead of silently downgrading, and a session request that names such a host fails as the typed `managed_host_chat_transport_unsupported` host-tool gate rather than an untyped unknown-endpoint error.

Readback: `manager_channel_binding` reaches the Chat capabilities `manager` block, the manager context, the dashboard schema, and the Lark routing fallback. The credential variable name is reported, never its value.
Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
…port gate

Record the resolved executor/model, their source, the chat-transport reason, and the capabilities readback the frontend can show, plus the host-tool gate a managed host without a chat transport raises.

Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
…tract

Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
@huangruiteng
huangruiteng force-pushed the codex/steward-channel-binding-20260915 branch from ea96161 to 90f4f2f Compare September 15, 2026 06:47
huangruiteng added a commit that referenced this pull request Sep 15, 2026
The steward channel now selects its executor and its model, and a configured
operator credential re-points neither. The previous rule resolved the channel
onto the managed host when DEEPSEEK_API_KEY was present while the endpoint
stayed codex, because dsh has no interactive Chat transport -- so the executor
and the model disagreed, and the swapped model was handed to the Codex adapter.

- manager_channel_binding resolves the endpoint from explicit configuration
  only; `codex` is the shipped default and LOOPX_MANAGER_ENDPOINT re-points it.
- The steward model follows the selected executor, so the shipped CLI endpoint
  keeps the vendor default and manager_model_config no longer reads the
  credential.
- The managed Turn host fails closed as the typed
  managed_host_chat_transport_unsupported host-tool gate instead of an unknown
  endpoint ValueError, in the Chat service and Lark routing.
- The three hardcoded endpoint fallbacks now resolve through the one function
  that owns the rule, and Chat capabilities carry the binding for frontend
  readback.

Replaces the steward half of the stacked chain (#4417).

Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
@huangruiteng

Copy link
Copy Markdown
Collaborator Author

Superseded by #4446 (feat(chat): select the steward channel executor explicitly).

The value here is kept: the steward channel binding, the typed managed_host_chat_transport_unsupported gate, the single endpoint resolver replacing the hardcoded codex fallbacks, and the capabilities readback. The rule is corrected: the steward channel selects its executor, and a configured credential no longer resolves the endpoint or silently swaps the model.

Concretely, the previous shape could resolve an endpoint of codex while setting the model to the operator model, and that model was then passed to the Codex adapter -- an executor and a model that disagreed. The replacement keeps codex + the vendor model default unless the operator changes them explicitly, and reports the credential as a fact (operator_credential_configured, variable name only).

The dashboard schema and packaged loopx/web/chat assets from this PR are not carried here; the frontend consumer is refreshed onto the corrected channel_binding shape in the sibling frontend/docs slice. Closing this one to compress the delivery chain.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant