Repository navigation
Conversation
Every Portal grant is refused until the egress-admission gate exists, so a declared remote endpoint can never answer even when its operator intends it. Add `allow_dispatch` to Portal runes (default false, requires probe = true). An opted-in Portal is granted like any warm capability once its probe lists the declared model; every other Portal is refused exactly as before. - The opted-in probe authenticates with the Portal's own secret, since a credentialed gateway answers an anonymous `/models` with 401. A missing secret leaves the capability COLD with a reason naming the secret. - Among equally ready candidates a local Soulstone still outranks a Portal. - Archive, semantic, Scout and Creation workflows keep their Soulstone-only checks.
The conversation profile was frozen to one local model (`Qwen3.8-27B` on `night-qwen38`) at one literal loopback endpoint, so using any other model required an adapter that impersonated it. - `animator_id` and `model_id` are closed, validated strings defaulting to the previous values; existing profiles keep their digest. - `--model-endpoint` admits a loopback HTTP origin (as before, any port) or any HTTPS endpoint with an optional path prefix. Credentials, queries, fragments and plain remote HTTP are refused. The Podman transport stays loopback-only. - `--model-api-key-file` reads one bearer credential from a private file. - A remote endpoint has no standard /health, so its /v1/models inventory is the probe. A catalogue larger than the wire bound reports only the selected model to the worker. - A completion may report the bare model a gateway reached for a routed id (`vendor/model` -> `model`); a different model is still refused. - reach_probe.py accepts the same endpoint and credential options.
2 tasks done
Capture probe headers through a typed respx side effect instead of the untyped call log, and validate the identifier cases from a dict.
Contributor
|
Please keep both the direct Reach API path and the per-Portal Follow-up in #25: route both Bridge Portal calls and direct Reach calls through the Egress Gate. The gate should authorize the exact destination and payload before sending. Apply and verify the required privacy transformation, including redaction or anonymization where policy requires it, before the payload is admitted. |
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Change and scope
Two hardcoded bindings stop an operator from using a model they already run or pay for. This PR lets each be configured, leaves the defaults unchanged, and keeps the existing refusals for anyone who doesn't opt in.
1. Opt one Portal into dispatch (
allow_dispatch)Every Portal grant is refused until the egress-admission gate exists, so a declared remote endpoint can't answer even when its operator intends it to.
allow_dispatch(defaultfalse, requiresprobe = true). An opted-in Portal is granted like any warm capability once its probe lists the declared model; every other Portal is refused exactly as before (portal egress admission is not configured)./modelswith 401. A missing secret leaves the capability COLD with a reason naming the secret. Un-opted Portals keep the unauthenticated probe.This is an operator's explicit choice, not the egress gate from State of Work: none of the privatization, secure-mode, local-before-paid or spend gates exist, and the Portal doc says so next to the flag.
2. Reach operator conversation: any model and endpoint
The conversation profile was frozen to
Qwen3.8-27Bonnight-qwen38at the literalhttp://127.0.0.1:28000, so any other model needed a local adapter that impersonated that name.animator_idandmodel_idbecome closed, validated strings defaulting to the previous values. Existing profiles keep their digest (the legacy-digest test is unchanged and passes).--model-endpointadmits a loopback HTTP IP literal with any explicit port (as before), or any HTTPS endpoint with an optional path prefix. Credentials, queries, fragments, trailing slashes and plain remote HTTP are refused.--model-transport podmanstays loopback-only.--model-api-key-filereads one bearer credential from a private file; it never appears in argv./health, so its/v1/modelsinventory is the probe. A catalogue larger than the 32-entry wire bound reports only the selected model to the worker.vendor/model→model). That exact suffix is the only accepted alias; any other model is still refused, on both the host broker and the worker side.reach_probe.pyaccepts the same endpoint and credential options.Verification
test_portals.py); endpoint admission and refusal cases, remote gateway probe/inventory/routed-model flow with bearer auth, different-model refusal, credential validation (cli/test_reach_operator_model.py); configurable binding with unchanged legacy digest, routed-suffix matching, identifier validation (compositions/test_reach_operator_model.py).pytest tests/unit/interface tests/unit/cli tests/unit/compositions tests/unit/domain/animation tests/unit/domain/cortexagainst this branch and against unmodifieddev, both with--basetempoutside any Git checkout: identical failure set (22 failed in both, environment-dependent mount/transmute and Reach portability/research-image suites), 39 more passing here.ruff checkandruff format --checkclean on changed files.allow_dispatchPortal pointed at a credentialed OpenAI-compatible gateway registered WARM and answered a real Bridge message.reach_probe.py --model-transport http --model-endpoint https://<gateway> --model-api-key-file <file>with a routedvendor/modelid passed: probe and generation succeeded against the remote endpoint with no local adapter.Documentation and delivery claims
docs/sepulcher/animator/portal.md: documentsallow_dispatchand what it does not provide.docs/compositions/reach/operator.md: documents the configurable binding, the endpoint rules, the credential file, and that the remote road sends conversation, persona and context to that provider.Author review