Skip to content

Model Groups spawn router#14

Open
grzegorznowak wants to merge 4 commits into
mainfrom
model-groups-spawn-router
Open

Model Groups spawn router#14
grzegorznowak wants to merge 4 commits into
mainfrom
model-groups-spawn-router

Conversation

@grzegorznowak

@grzegorznowak grzegorznowak commented Jun 15, 2026

Copy link
Copy Markdown
Collaborator

Summary

Implements the Model Groups spawn-router story end to end: operators can define named model groups, get prompt/autocomplete guidance for them, and route spawned child agents through a group while the default inherited spawn path remains unchanged.

What changed

  • Added Model Groups persistence/state and TUI flows for global/project groups, validation, effective group resolution, and project-over-global overrides.
  • Added #group-name autocomplete for effective groups; suggestions show compact provider/model/thinking details for the operator while inserting only prompt text.
  • Refreshed system prompt guidance with names-only group availability and confidence/fallback rules; provider/model/auth/persistence details are not exposed in the prompt.
  • Extended spawn with optional exact group routing and stopped advertising thinking; stale cached thinking arguments are accepted but ignored.
  • Routed spawn calls randomly choose one available authenticated member from the requested group per call. Empty groups or groups with no usable authenticated entries fail clearly; unknown groups fall back to parent model/thinking.
  • Routed child thinking uses the selected entry's configured thinking level when present, otherwise inherits parent thinking, then clamps to the selected model capability.
  • Child sessions prefer the parent runtime registry/auth while keeping session manager, messages, tools, and spawn isolation intact.
  • Spawn result rendering now distinguishes inherited default routing, successful group routing, and unknown-group fallback identity.

Out of scope

  • Interactive picker/chooser at spawn time.
  • Automatic routing without explicit operator group intent.
  • Registering groups as model picker entries or meta-model proxies.
  • Child profiles, frontmatter, extra tools, budget/context policies, weighted/priority/health/rate-limit routing, retry-time group failover, fuzzy matching, or explicit provider/model override params on spawn.

Verification

CI note / follow-up

  • The latest fix isolates Windows test homes by setting HOME, USERPROFILE, HOMEDRIVE, and HOMEPATH for model-groups tests.
  • CI now runs a runtime dependency audit with --omit=dev. The full dev audit is still blocked by upstream shrinkwrapped Pi dev dependencies, so this PR does not claim the upstream Pi audit issue is fixed. Restore strict full-dev audit after the upstream fix is released and the lockfile is updated.

References

  • Initiative: model-tag-router
  • Story: model-groups-spawn-router — Model Groups spawn router

@grzegorznowak grzegorznowak force-pushed the model-groups-spawn-router branch from 479d78e to 907b4e7 Compare June 16, 2026 04:53
@grzegorznowak grzegorznowak requested a review from ofriw June 16, 2026 08:04

@ofriw ofriw left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the strong PR — the Model Groups architecture is clean and the feature scope is well-contained.

Must fix before merge

1. /model-groups does not guard missing project/model context

The interactive /model-groups command calls createModelGroupsComponent(...) with ctx.modelRegistry and ctx.cwd unconditionally (model-groups/command.ts). But elsewhere in the same subsystem, missing cwd / modelRegistry is explicitly treated as a valid condition and safely skipped (index.ts, refreshModelGroupsState).

That inconsistency means /model-groups can fail when the command is invoked without a fully initialized project/model context, instead of degrading gracefully.

Expected fix: add the same guard pattern in the command path and surface a friendly message when the required context is unavailable.

2. deleteGroup() can report failure after the delete already succeeded

In model-groups/store.ts, deleteGroup() removes the group and saves the updated config first, then loads the other scope to compute otherScopeHasOverride.

If that opposite-scope load throws (for example because recovery hit a backup-failed malformed config), the function throws after the target delete already committed to disk.

That creates a bad correctness property: callers can observe an error for an operation that already mutated persistent state successfully.

Expected fix: make the opposite-scope lookup non-fatal, or compute it before the delete is committed.

3. Test helper duplication

The new model-group test files duplicate helpers like registry(), group(), and withTemp() in several places. That is valid DRY cleanup work, but it is maintenance debt rather than a release blocker.

AGENT_REVIEW.md

…fix deleteGroup error-after-commit

- model-groups/command.ts: add guard for missing ctx.cwd or ctx.modelRegistry
  before calling createModelGroupsComponent; surface friendly notification
  instead of crashing. Matches refreshModelGroupsState pattern in index.ts.
- model-groups/store.ts deleteGroup(): load opposite-scope config before
  saving the delete so a load failure doesn't throw after the delete is
  already persisted on disk. Follows moveGroup's pre-validation pattern.
@grzegorznowak

Copy link
Copy Markdown
Collaborator Author

Addressed the two must-fix items:

1. /model-groups missing context guard → fixed in command.ts

Added check for !ctx.cwd || !ctx.modelRegistry before calling createModelGroupsComponent, surfacing a friendly notification instead of crashing. Matches the existing guard in refreshModelGroupsState().

2. deleteGroup() throwing after successful delete → fixed in store.ts

Reordered deleteGroup() to load the opposite-scope config before calling saveModelGroups. If loadScopeConfig for the other scope throws, nothing was persisted yet — clean failure. Mirrors the pre-validation pattern already used in moveGroup().


This comment is AI-generated.

- Extract duplicated withTemp() and group() into tests/unit/model-groups-helpers.ts
- withTemp: unified async version replacing 2 local variants (crud + integration)
- group: unified opts-object signature replacing 3 local variants (tui, router, autocomplete)
- registry() kept per-file — each test file needs different model sets
@grzegorznowak

Copy link
Copy Markdown
Collaborator Author

3. Test helper DRY cleanup

Extracted shared withTemp() and group() helpers into tests/unit/model-groups-helpers.ts:

  • withTemp() — unified async version (was duplicated in crud and integration tests)
  • group() — unified opts-object signature (was duplicated across tui, router, and autocomplete tests)
  • registry() kept per-file — each test file needs different model sets, not worth forcing into a shared helper

Existing helpers.ts untouched — it stays domain-agnostic.

190/190 pass.


This comment is AI-generated.

grzegorznowak added a commit to grzegorznowak/pi-agenticoding that referenced this pull request Jun 24, 2026
…del-groups, fix deleteGroup error-after-commit

- model-groups/command.ts: add guard for missing ctx.cwd or ctx.modelRegistry
  before calling createModelGroupsComponent; surface friendly notification
  instead of crashing. Matches refreshModelGroupsState pattern in index.ts.
- model-groups/store.ts deleteGroup(): load opposite-scope config before
  saving the delete so a load failure doesn't throw after the delete is
  already persisted on disk. Follows moveGroup's pre-validation pattern.
@grzegorznowak grzegorznowak requested a review from ofriw June 24, 2026 14:22

@ofriw ofriw left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR #14 Review — Model Groups & Spawn Routing

AGENT_REVIEW.md

Assessment

Clean architecture, good test coverage, well-contained scope. One correctness issue to fix before merge. Rest is tech debt.

Issues

1. 🔴 Model group state can go stale when context is unavailable

refreshModelGroupsState in index.ts:47 returns early without clearing state.modelGroups when ctx.cwd or ctx.modelRegistry is missing. Stale groups from a previous valid session remain in state and get injected into the system prompt via before_agent_start (line 208). The session reset in resetState does clear this, but that only runs on /new — not between agent runs within the same extension lifetime. Fix: clear state.modelGroups.groups and state.modelGroups.validation before the early return.

2. 🟡 createModelGroupsComponent is 378 lines

model-groups/tui.ts:76–453. Project guideline: functions above 20 lines should be broken into smaller units. The TUI component contains 7 screen renderers, input handling, and CRUD operations in a single closure. Track as tech debt.

3. 🟡 modelRegistry accessed via as any casts

Four occurrences across index.ts:46–47 and spawn/index.ts:224–225. The ExtensionContext type doesn't include modelRegistry, so every access bypasses type safety. If the upstream property changes shape or name, there's no compile-time protection.

4. 🟢 Unused state field: wizardThinking

model-groups/tui.ts:88. Declared in the TUI state object but never read or written anywhere. The wizard reads thinking options directly via thinkingOptionsFor(currentWizardModel())[state.row].

5. 🟢 Missing SpawnRouteError integration test

model-groups-router.test.ts covers SpawnRouteError at the router level (empty group, no usable models). But no test in spawn.test.ts verifies the error propagates correctly through executeSpawn to the caller — that boundary is untested.

Already addressed

The contributor fixed 3 items from an earlier review pass: context guard in /model-groups command, deleteGroup() save-before-load ordering, and test helper extraction. All verified.

What's good

  • Pure routerresolveSpawnModelRoute is side-effect-free with an injectable rng seam for deterministic testing
  • Boot validation — eagerly validates groups against the model registry at startup, surfaces misconfigurations via operator notifications instead of failing at spawn time
  • Scoped persistence — backup-before-overwrite, typed ModelGroupsPersistenceError with phase tracking, and partialMove state for moveGroup
  • Names-only prompt guidance — group internals (provider, model, thinking, auth) are never exposed to the child agent
  • Test coverage — 6 new test files covering CRUD, routing, TUI, autocomplete, integration, and spawn rendering with good edge-case depth

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.

2 participants