Feat/astra model - #91
thisguymartin wants to merge 19 commits into
Conversation
Fork of ericlitman/open-pstack at v1.4.1 (de67e6b). UPSTREAM-FLEX.md adds the second sync layer (cursor -> open-pstack -> flex) with the merge rehearsal procedure and the expected conflict surface for upstream 1.5.0. NOTICE.md records the provenance chain, LICENSE adds the fork copyright line without removing existing holders, and the README gains a fork section stating what flex adds and that a stock install behaves exactly like upstream.
New gateway lanes run the stock claude binary against each lab's Anthropic-compatible endpoint, reusing the exact claude argv and the existing spawn path. flex-providers.ts owns the per-provider env maps: endpoint (overridable), ANTHROPIC_AUTH_TOKEN from DEEPSEEK_API_KEY or MINIMAX_API_KEY, model pins, nonessential-traffic and attribution-header hygiene, and an isolated CLAUDE_CONFIG_DIR under ~/.pstack-flex. childEnvironment deletes inherited ANTHROPIC_* values before injection so a parent session's credentials or endpoint never bleed into a gateway child. - Preflight is claude --version: auth-status semantics under token auth are undocumented, credentials are checked in-process, and the one-shot invocation is the real auth test. - Gateway receipts force costUsd to null (the CLI prices total_cost_usd at Anthropic rates, fiction for third-party traffic); token usage stays. - Served models match case-insensitively (MiniMax-M3 vs minimax-m3) and otherwise fall back to modelEvidence pinned-argv like Codex. - provider==parent stays rejected; gateway providers are distinct, so they run under both parents through the external runner.
A gateway lane refuses to start, in-process and before any subprocess, when its API key variable is missing or its isolated config dir carries a claude.ai OAuth credentials file (or one that cannot be parsed). The refusal is an unauthenticated receipt (exit 77) whose evidence names the path and never the contents. This guarantees a claude.ai login can never be pointed at a third-party endpoint through the runner. Endpoint authentication errors from the one-shot invocation classify as unauthenticated through the existing stderr matching. Tests cover the key-missing, OAuth-refusal, garbage-file, env-injection, happy-path, case-shifted-model, pinned-argv, and endpoint-401 paths, plus the zero-subscription scenario with mocked binaries; nothing performs network I/O.
PROVIDERS now spreads GATEWAY_PROVIDERS, and the preflight, invocation, parse, and preflight-pass paths branch on isGatewayProvider instead of naming deepseek and minimax in each switch. Adding an Anthropic-compatible gateway is one GATEWAY_PROVIDERS entry plus one GATEWAY_SPECS row; the Record type makes a missing spec a compile error.
provider-dispatch.md gains an additive Flex model matrix section (the stock matrix and its parser contract stay byte-identical), deepseek/ minimax columns in the route table (external runner under both parents), the gateway preflight and receipt semantics, and the panel diversity rule: arena runners and interrogate reviewers span at least two distinct providers unless the operator explicitly confirms otherwise. codex-tools notes that flex descriptors are never spawn_agent lanes.
Mirrors upstream PR ericlitman#73 (issue ericlitman#72): role assignments are chosen first, only assigned families get effort questions and probes, and there is no requirement to assign every matrix family. A failed model demands explicit repair or role reassignment before saving; the fail-closed write rules and the first-run sheet bytes are unchanged. The probe table gains DeepSeek and MiniMax rows (key present, config dir free of OAuth credentials, one-turn probe doubling as the base-URL confirmation), and render-time validation enforces non-empty roles, at least two architect runners, and the two-provider panel diversity rule. model-matrix.test.ts is updated in the same commit because it pins the setup prose, and gains a flex-matrix section check cross-validated against the runner's gateway specs.
LANES.md covers lane kinds, the gateway environment reference, dated prices including DeepSeek's off-peak window, the zero-subscription walkthrough (parent session env-pointed at DeepSeek, MiniMax through the runner), safety rules (unsupported-not-prohibited, never a claude.ai login on a gateway path, per-project privacy opt-in, no silent substitution), the optional OpenRouter and future Ollama lanes, and the live post-merge validation checklist. CHANGES.md records the flex delta.
docs/USAGE.md walks the whole plugin: what pstack-flex is and how it relates to thisguyskills, a mermaid map of task -> poteto-mode -> playbooks -> lane fan-out -> receipts, fork install commands, key handling for gateway lanes, the assignment-first /setup-pstack flow with three worked configurations (full frontier, hybrid saver, zero-subscription duo), copy-paste prompts for poteto-mode, interrogate, arena, swarm, and architect with panel diagrams, a sequence diagram of gateway lane execution including the OAuth guard, a receipt field cheat-sheet, a cost playbook, and a troubleshooting table keyed to receipt statuses. docs/LANES.md gains a "Storing keys" section: macOS Keychain load-on-demand recipe, pass/secret-tool and 1Password CLI alternatives, the direnv plaintext caveat, the honest threat model, and provider spend caps as the real blast-radius control.
The fork section now points newcomers at docs/USAGE.md, and the install commands move from ericlitman/open-pstack to this repository. The marketplace and plugin names are unchanged (pstack@open-pstack), so only the marketplace-add commands change.
Lists the four touch points (GATEWAY_PROVIDERS, GATEWAY_SPECS, the flex matrix row, the setup probe row) and which check fails when each is missing.
feat(runner): DeepSeek and MiniMax gateway lanes
feat(setup): flex dispatch matrix, assignment-first setup, and lane docs
Add DeepSeek Pro and MiniMax preview model choices
Add Astra, GPT-6 Sol, and Luna as optional model families for setup-pstack. Keep upstream defaults intact and validate their provider routes and effort flags.
|
This pull request does not currently match the merge queue conditions, so it cannot be queued from here. The box comes back if it matches again. |
|
| if (isGatewayProvider(provider)) { | ||
| for (const key of Object.keys(result)) { | ||
| if (key.startsWith("ANTHROPIC_")) delete result[key]; | ||
| } | ||
| for (const key of GATEWAY_INHERITED_CONFLICTS) delete result[key]; | ||
| Object.assign(result, gatewayEnvironment(provider, model, source)); |
There was a problem hiding this comment.
Gateway children inherit other keys
When both gateway keys are loaded, a DeepSeek lane inherits MINIMAX_API_KEY, and a MiniMax lane inherits DEEPSEEK_API_KEY. The environment cleanup removes ANTHROPIC_* values but not the other provider’s key. Commands run by the child can access that unrelated credential, even in read-only mode, which permits Bash. Remove unrelated gateway keys before spawning each child.
How this was verified: The runner copies the parent environment, leaves the sibling provider’s key in it, and passes that environment to the gateway child.
| 1. Exit status `0`. | ||
| 2. Receipt status `complete`. | ||
| 3. Either `modelVerified: true` with `modelEvidence: "provider-report"`, or a Codex receipt with `reportedModel: null`, `modelVerified: false`, and `modelEvidence: "pinned-argv"`. For Claude's `fable` and `opus` aliases, the concrete provider report must belong to the requested family. Codex 0.149.0 accepts the exact `--model` argument but does not report the served model in its JSONL stream. | ||
| 3. Either `modelVerified: true` with `modelEvidence: "provider-report"`, or a Codex receipt with `reportedModel: null`, `modelVerified: false`, and `modelEvidence: "pinned-argv"`, or a gateway (`deepseek`/`minimax`) receipt with `modelVerified: false` and `modelEvidence: "pinned-argv"` when the endpoint does not echo the requested slug. For Claude's `fable` and `opus` aliases, the concrete provider report must belong to the requested family. Codex 0.149.0 accepts the exact `--model` argument but does not report the served model in its JSONL stream. Gateway reports match case-insensitively because third-party endpoints are inconsistent about slug casing. |
There was a problem hiding this comment.
Panels reject successful gateway lanes
If a gateway does not report its model, the runner can return a complete receipt with modelVerified: false and modelEvidence: "pinned-argv". This new success condition conflicts with the panel skills: arena accepts pinned-argv evidence only for Codex, while interrogate requires a model-verified receipt. A successfully completed gateway candidate or reviewer can therefore be discarded from the panel. Update those consumers to accept the new receipt condition.
| ): NodeJS.ProcessEnv { | ||
| const spec = GATEWAY_SPECS[provider]; | ||
| const injected: NodeJS.ProcessEnv = { | ||
| ANTHROPIC_BASE_URL: overridden(source, spec.baseUrlOverrideVar) ?? spec.baseUrlDefault, |
There was a problem hiding this comment.
Plaintext endpoint overrides expose tokens
If an operator sets a non-loopback gateway endpoint override to http://, this code accepts it while giving the same child the provider key as ANTHROPIC_AUTH_TOKEN. That can expose the key in transit. Validate the override’s scheme before spawning, with an explicit local-only exception if needed.
How this was verified: The override receives only a nonblank check, then the runner passes it and the provider token together to the gateway child.
# Conflicts: # plugins/pstack/skills/poteto-mode/scripts/runner/model-matrix.test.ts
Add the astra, sol-6, and luna families to the lane guide, usage guide, reference, README, and fork-ownership list. Existing sheets and first-run defaults stay on codex:gpt-5.6-sol@max.
Closes #
What changed
Verification
Live evidence:
A pull request without live evidence remains a draft. Do not merge, tag, release, or roll it out.