Allow users to set `background_task.syncPollTimeoutMs` in config to override
the default 10-minute sync subagent timeout. Affects sync task, sync continuation,
and unstable agent task paths. Minimum value: 60000ms (1 minute).
Co-authored-by: Wine Fox <fox@ling.plus>
- Add normalizeModelFormat() utility for string/object model handling
- Update subagent-resolver to handle both model formats
- Add explicitUserConfig flag to ModelResolutionResult
- Set explicitUserConfig: true when user model is found in pipeline
This fixes the issue where plugin-provided models fail cache validation
and fall through to random fallback models.
Problem: Agents frequently omit both 'category' and 'subagent_type' parameters
when calling the task() tool, causing validation failures. The JSON Schema
marks both as optional, and LLMs follow schema structure over description text.
Solution (Option A): Add aggressive visual warnings and failure-mode examples
to the tool description:
- ⚠️ CRITICAL warning header
- COMMON MISTAKE example showing what will FAIL
- CORRECT examples for both category and subagent_type usage
- Clear explanation that ONE must be provided
Tests: All 153 existing tests pass (no behavior change, only prompt improvement)
When browserProvider is not set, agent-browser skill should NOT resolve.
Test assertions were inverted — expected 'Skills not found' but asserted the opposite.
- Add normalizeFallbackModels helper to centralize string/array normalization (P3)
- Export RuntimeFallbackConfig and FallbackModels types from config/index.ts
- Fix agent detection regex to use word boundaries for sessionID matching
- Improve tests to verify actual fallback switching logic (not just log paths)
- Add SessionCategoryRegistry cleanup in executeSyncTask on completion/error (P2)
- All 24 runtime-fallback tests pass, 115 delegate-task tests pass
Implement full fallback_models support across all integration points:
1. Model Resolution Pipeline (src/shared/model-resolution-pipeline.ts)
- Add userFallbackModels to ModelResolutionRequest
- Process user fallback_models before hardcoded fallback chain
- Support both connected provider and availability checking modes
2. Agent Utils (src/agents/utils.ts)
- Update applyModelResolution to accept userFallbackModels
- Inject fallback_models for all builtin agents (sisyphus, oracle, etc.)
- Support both single string and array formats
3. Model Resolver (src/shared/model-resolver.ts)
- Add userFallbackModels to ExtendedModelResolutionInput type
- Pass through to resolveModelPipeline
4. Delegate Task Executor (src/tools/delegate-task/executor.ts)
- Extract category fallback_models configuration
- Pass to model resolution pipeline
- Register session category for runtime-fallback hook
5. Session Category Registry (src/shared/session-category-registry.ts)
- New module: maps sessionID -> category
- Used by runtime-fallback to lookup category fallback_models
- Auto-cleanup support
6. Runtime Fallback Hook (src/hooks/runtime-fallback/index.ts)
- Check SessionCategoryRegistry first for category fallback_models
- Fallback to agent-level configuration
- Import and use SessionCategoryRegistry
Test Results:
- runtime-fallback: 24/24 tests passing
- model-resolver: 46/46 tests passing
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
transformModelForProvider only handled github-copilot provider, leaving
google provider models untransformed. This caused ProviderModelNotFoundError
when google/gemini-3-flash was sent to the API (correct ID is
gemini-3-flash-preview).
Changes:
- Add google provider to transformModelForProvider with idempotent regex
negative lookahead to prevent double -preview suffix
- Fix category-default path in model-resolution-pipeline when
availableModels is empty but connected provider exists
- Fix getFirstFallbackModel first-run path that constructed raw model IDs
without transformation
- Fix github-copilot provider gemini transforms to also use idempotent
regex (was vulnerable to double-transform)
- Extract transformModelForProvider to shared module (single source of
truth, imported by cli and shared layers)
- Add 20 new test cases: unit tests for both providers, runtime
integration tests for category-default and fallback-chain paths,
double-transform prevention for both providers
Category-based delegation (task(category='quick')) was broken because
SISYPHUS_JUNIOR_AGENT sent 'sisyphus-junior' to session.prompt but
config.agent keys are now display names ('Sisyphus-Junior').
- Use getAgentDisplayName() for SISYPHUS_JUNIOR_AGENT constant
- Replace hardcoded 'sisyphus-junior' strings in tools.ts with constant
- Update background-output local constants to use display names
- Add remapCommandAgentFields() to translate command agent fields
- Add raw-key fallback in tool-config-handler agentByKey()