feat: add versioned execution profiles
This commit is contained in:
parent
641e85f5a8
commit
1cd890d871
34 changed files with 2087 additions and 471 deletions
|
|
@ -1,76 +1,34 @@
|
|||
# Channel contract
|
||||
|
||||
How an external invocation reaches the gateway, per `GLAS-WP-0003`.
|
||||
Mirrors `docs/harness-contract.md`'s `Rein` at a different layer: `Rein`
|
||||
governs how a session runs once glas-harness has decided to run one; a
|
||||
`Channel` governs how an external caller (CLI today; a future Slack
|
||||
message, HTTP request, or scheduled trigger) gets translated into that
|
||||
decision in the first place, and how the result gets translated back.
|
||||
|
||||
## Interface
|
||||
A channel translates an external invocation into profile-driven gateway input;
|
||||
it does not select a rein class or execute a provider itself.
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class GatewayInvocation:
|
||||
"""Everything run_task_through_rein needs, channel-agnostic."""
|
||||
sandbox_profile: str
|
||||
harness_profile: str
|
||||
repo: str
|
||||
title: str
|
||||
description: str
|
||||
actor: str = "agt"
|
||||
project: str = "glas-harness"
|
||||
report_to_hub: bool = True
|
||||
|
||||
|
||||
class Channel(ABC):
|
||||
"""Base class for concrete invocation channels (CLI, Slack, HTTP, ...)."""
|
||||
|
||||
@abstractmethod
|
||||
def parse_invocation(self, raw: Any) -> GatewayInvocation:
|
||||
"""Turn a channel-specific invocation into a GatewayInvocation."""
|
||||
|
||||
@abstractmethod
|
||||
def render_result(self, result: dict[str, Any]) -> Any:
|
||||
"""Turn a gateway result dict into whatever this channel returns."""
|
||||
```
|
||||
|
||||
`src/glas_harness/channels/base.py`. A channel does not choose the rein
|
||||
or run the gateway itself — `cli.py`'s `main()` still does that, calling
|
||||
`parse_invocation`/`render_result` around the existing
|
||||
`run_task_through_rein` call. Keeping channel construction and gateway
|
||||
invocation separate (rather than folding gateway-calling into the
|
||||
`Channel` ABC itself) is what lets `CLIChannel` be a pure
|
||||
input/output mapper, easy to unit test without touching sand-boxer or a
|
||||
rein at all.
|
||||
`CLIChannel` is the current implementation. The CLI requires
|
||||
`--harness-profile <id[@version]>`; the old sandbox-only input is removed
|
||||
because it could not identify the rein, model route, tool policy, or contract
|
||||
revision. Channels may obtain a profile choice from their own approved
|
||||
configuration, but must pass it explicitly and must surface resolution refusal
|
||||
to their caller.
|
||||
|
||||
## CLIChannel — the first, and so far only, implementation
|
||||
The channel renders the full direct `GatewayResult`. State Hub receives only
|
||||
the compact `ExecutionEvidence` subset.
|
||||
|
||||
`src/glas_harness/channels/cli_channel.py`. Maps an argparse
|
||||
`Namespace` to `GatewayInvocation` (one field each, `--no-hub` inverts
|
||||
to `report_to_hub`) and renders a result dict as
|
||||
`json.dumps(result, indent=2)` — exactly what `cli.py` did inline before
|
||||
this existed. This was a refactor, not a behavior change: verified with
|
||||
a real live run through `python3 -m glas_harness.cli run ...` producing
|
||||
byte-identical output shape to the pre-refactor version, plus unit tests
|
||||
for the mapping in isolation (`tests/test_cli_channel.py`).
|
||||
## Adding a channel
|
||||
|
||||
## Adding a second channel (not done — pattern only)
|
||||
|
||||
No second channel exists yet, and none should be built speculatively —
|
||||
same discipline as ADR-002/ADR-004 (generalize from a real second
|
||||
example, not in anticipation of one). If/when one is needed, e.g. a
|
||||
Slack channel:
|
||||
|
||||
1. Implement `Channel` in `src/glas_harness/channels/slack_channel.py`:
|
||||
`parse_invocation` turns a Slack event payload into a
|
||||
`GatewayInvocation` (message text → `title`/`description`, a
|
||||
configured default `sandbox_profile`, the Slack user id as `actor`
|
||||
or `project`); `render_result` turns the result dict into a Slack
|
||||
message (success/failure, commit sha if present).
|
||||
2. Whatever process receives Slack events constructs the channel and
|
||||
calls `run_task_through_rein` the same way `cli.py` does — no change
|
||||
needed to `gateway.py`, `contract.py`, or any rein.
|
||||
3. If two real channels turn out to share invocation-parsing logic (e.g.
|
||||
both need the same `sandbox_profile` defaulting rule), factor that
|
||||
shared piece out then — not before, and not into the `Channel` ABC
|
||||
itself unless every channel needs it.
|
||||
Implement `parse_invocation` and `render_result`, then call `run_execution`
|
||||
with an `ExecutionRequest`. Carry any assignment/role/duty/goal/resource
|
||||
references supplied by the upstream workforce system. Do not duplicate profile
|
||||
resolution, sandbox coordination, leadership decisions, or rein construction in
|
||||
the channel.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue