Skip to content

feat(a3): prove wrapModelCall provider routing (LIA-396)#1034

Closed
sliamh11 wants to merge 1 commit into
mainfrom
a3-provider-override-walking-skeleton
Closed

feat(a3): prove wrapModelCall provider routing (LIA-396)#1034
sliamh11 wants to merge 1 commit into
mainfrom
a3-provider-override-walking-skeleton

Conversation

@sliamh11

Copy link
Copy Markdown
Owner

Summary

  • A3 of the MA kill-switch spike (LIA-394..400): proves LangChain JS's real wrapModelCall middleware contract can route different chat model providers to different requests within one logical session — Claude for a main agent, live local Ollama for a nested subagent.
  • "One logical session" = one top-level agent.invoke() whose delegate_to_subagent tool's execute() nests a second agent.invoke(), both sharing one wrapModelCall middleware instance disambiguated by request.runtime.context.role. Validated live before implementation (see plan).
  • createProviderRoutingMiddleware is exported as a standalone, parameterized reusable primitive — Strategy-pattern resolveModel/executeOverride seams, zero hardcoded role coupling — so A7 (LIA-400) can import it directly for its cross-provider benchmark matrix.
  • Per-AC verdict (not a blanket pass) — see scripts/spikes/lia396_provider_override_walking_skeleton.md:
    • AC1 (selects Claude for main-agent) — PASS
    • AC2 (selects Ollama for subagent) — PASS, and this leg is fully live, zero mocking (real local gemma4:e2b call)
    • AC3 (both requests execute within one logical session) — PARTIAL: call-stack nesting proven live (main → sub → main trace); the Claude leg's live network execution is deferred to A4 (LIA-397, credential-proxy), since ANTHROPIC_API_KEY is absent here — explicitly disclosed, not folded into a blanket PASS
    • AC4 (provider-attribution logging) — PASS
    • AC5 (A7-reusable) — PASS
  • Forks fresh off origin/main per the established per-slice convention (A1/PR spike(a1): LangChain createAgent walking skeleton reusing tool-broker.ts (LIA-394) #1031, A2/PR feat(a2): prove blocking warden enforcement via wrapToolCall (LIA-395) #1032 both still open/unmerged).

Test plan

  • npx vitest run scripts/spikes/lia396_provider_override_walking_skeleton.test.ts — 6/7 passing, 1 correctly skipped (no ANTHROPIC_API_KEY)
  • npx tsx scripts/spikes/lia396_provider_override_walking_skeleton.ts — direct demo confirms the live main → sub → main trace with a real (non-canned) Ollama answer
  • npm run typecheck — clean
  • The real-Ollama integration test self-gates on a live reachability + model-presence probe (added after two GPT-caught defects: an unconditional live-network test, then a reachability-only gate that missed model-presence) — won't break npm test on machines without Ollama/the model
  • 2 native + 2 GPT-backend plan-review rounds, both SHIP
  • Native code-reviewer + 3 GPT-backend code-review rounds (2 REVISE fixing real test-hermeticity defects, 1 SHIP)
  • Fresh verification-gate: SHIP (independently re-ran every claim)
  • Human review

Linear: LIA-396

🤖 Generated with Claude Code

Proves LangChain's real wrapModelCall middleware contract can route
different chat model providers to different requests within one logical
session: a delegate_to_subagent tool nests a second agent.invoke() inside
the main agent's execute(), both sharing one middleware instance keyed by
request.runtime.context.role.

createProviderRoutingMiddleware is the reusable primitive -- Strategy-
pattern resolveModel/executeOverride seams, no hardcoded role coupling --
exported standalone so A7 (LIA-400) can import it directly for its
cross-provider benchmark matrix.

Per-AC verdict (not a blanket pass): AC1/AC2/AC4/AC5 PASS. AC3 ("both
requests execute within one logical session") is PARTIAL -- call-stack
nesting is proven live (main -> sub -> main trace), but the Claude leg's
live network execution is deferred to A4 (LIA-397, credential proxy)
since ANTHROPIC_API_KEY is absent here. The Ollama/subagent leg is fully
live with zero mocking -- a real local gemma4:e2b call, not a stub.

Forks fresh off origin/main per the established per-slice convention
(A1/PR #1031, A2/PR #1032 both still open).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@github-actions github-actions Bot added the dependencies Dependency updates label Jul 14, 2026
sliamh11 added a commit that referenced this pull request Jul 14, 2026
Cherry-picked from a3-provider-override-walking-skeleton (d938a3f),
which shares deus-v2/dev's merge-base commit (df9df3f) and applies
cleanly. A7 [LIA-400] imports createProviderRoutingMiddleware from this
spike directly per A3's own file header comment. A3's own PR (#1034,
targeting main) is still open/unmerged and conflicting -- deus-v2/dev
roadmap work isn't gated on that landing first.

package.json/package-lock.json conflicts resolved by keeping both
sides' additive deps (@langchain/mcp-adapters from A5, @langchain/ollama
from this commit) and letting npm regenerate the lock incrementally.

Also fixes a real test-reliability defect a GPT-backend code-reviewer
caught in the cherry-picked test file: the optional live full-Claude
smoke test was gated only on ANTHROPIC_API_KEY, but its delegate leg
requires local Ollama too -- now gated on both.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
sliamh11 added a commit that referenced this pull request Jul 14, 2026
Also brings in A3's [LIA-396] provider-routing middleware spike, which
was cherry-picked into this branch as a prerequisite (A3's own PR #1034
remains open/unmerged, targeting main). 6-chain x 3-provider benchmark;
kill-switch criterion 4 recorded NO-PASS-YET (qualified) -- see
scripts/spikes/lia400_tool_loop_reliability_benchmark.md.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
sliamh11 added a commit that referenced this pull request Jul 17, 2026
… --repo (#1054)

## Summary
- `_check_ci_status`/`_query_gh_checks` (ci_status.py) and
`_gh_pr_head_branch` (codex_warden_hooks.py) never passed `gh` an
explicit `--repo`, relying entirely on `gh`'s cwd-based git-remote
resolution.
- This silently broke cross-repo gating: a `gh pr merge --repo
<other-repo> --admin <n>` command run from a worktree tree whose ambient
remote is a *different* repo had its internal CI/PR-view check silently
resolve against the wrong repo — confirmed live this session merging a
`sliamh11/deus-v2` PR from inside the `sliamh11/Deus` worktree tree,
where the gate checked an unrelated same-numbered PR on the wrong repo
and produced a false "CI is red" block.
- Added `_extract_repo_flag` (command_parse.py) to capture an explicit
`-R`/`--repo` value already present in the gated command (global or
subcommand-local position, last-occurrence-wins matching gh's own
precedence, gh's attached `-Rowner/repo` form included), and threaded it
through every gh call site: `_check_ci_status`, `_gh_pr_head_branch`,
`_pr_matches_worktree`, `run_admin_merge_gate`, `approve_admin_merge`.
- Additive and backward-compatible: argv is byte-identical to today when
no `--repo`/`-R` is present in the gated command (verified by dedicated
regression tests).

## Test plan
- [x] `python3 -m pytest scripts/tests/test_codex_warden_hooks.py -q` →
294 passed (279 pre-existing + 15 new)
- [x] Real end-to-end hook invocation (not just unit tests) via
`codex_warden_hooks.py run admin-merge-gate`, against live GitHub state:
- **Error path, same-repo (control):** `gh pr merge --repo sliamh11/Deus
--admin 1053` (real PR with a genuinely failing `ci` check) → correctly
denied with `"CI is red ... failing checks: ci"`.
- **Cross-repo bug reproduction:** from the same cwd (ambient remote
`sliamh11/Deus`), `gh pr merge --repo sliamh11/deus-v2 --admin --squash
14` → correctly denied using deus-v2-*specific* data (10 checks,
TrueCourse failing in the unfiltered set) — proven distinct from what
the *unscoped* `gh pr checks 14` call from the same cwd resolves to (a
completely unrelated `sliamh11/Deus` PR #14, "bump @vitest/coverage-v8",
with its own failing `ci`). That mismatch is the exact pre-fix bug.
- **Happy/allow path:** real green PR #1034 on `sliamh11/Deus` (0
non-passing required checks, independently confirmed) →
`approve_admin_merge` + the real PreToolUse hook invocation both
succeed, hook allows (empty output, no `permissionDecision`), one-shot
marker consumed as designed.

## Known follow-up (not in scope here)
- `_extract_pr_ref` still doesn't recognize gh's attached `-Rowner/repo`
short form (only `_extract_repo_flag`, added in this PR, handles it).
Low-probability edge case (would only matter if the attached form is
combined with a positional PR ref); flagged by code-review as a
candidate follow-up, not a regression from this change.
- Separately (not touched by this PR): `sliamh11/deus-v2` is a private
repo without GitHub Pro, so GitHub's classic branch-protection API
returns 403 for it, making `_check_ci_status` classify every deus-v2 PR
as `_CI_STATUS_NO_REQUIRED` (fail-closed) regardless of actual CI state.
This is an orthogonal billing/plan constraint, surfaced to the user
separately — this PR's fix is still correct and necessary (it was
actively causing the gate to check a totally wrong, unrelated PR).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
@sliamh11

Copy link
Copy Markdown
Owner Author

Superseded — this exact commit (d938a3f) was already cherry-picked onto Deus V2 as commit d054fb4 on sliamh11/deus-v2 main (part of the sequential spike-integration lineage, ahead of A6/A7) before this PR could be migrated. Verified byte-identical file content and confirmed both the AC3-PARTIAL disposition and the live-Ollama hermeticity gate survived. No new port PR needed — closing as duplicate.

@sliamh11 sliamh11 closed this Jul 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Dependency updates

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant