{"record":{"id":"42d9eff5b6007424","repo":"tinyhumansai/openhuman","slug":"turn-model-source-is-missing-a-model","errorCode":null,"errorMessage":"turn model source is missing a model","messagePattern":"turn model source is missing a model","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/openhuman/agent/tinyagents/mod.rs","lineNumber":1608,"sourceCode":"                    .split(':')\n                    .next()\n                    .unwrap_or(&provider_string)\n                    .to_string()\n            };\n            return build_turn_models_crate(\n                &cn.role,\n                &cn.config,\n                model,\n                temperature,\n                context_window,\n                cn.primary_override.as_deref(),\n                provider_id,\n                !is_local,\n                !is_local,\n                cn.force_text_mode,\n            );\n        }\n        Err(anyhow::anyhow!(\"turn model source is missing a model\"))\n    }\n\n    /// Build a standalone summarizer [`ChatModel`](tinyagents::harness::model::ChatModel)\n    /// over this source's provider — a fresh adapter (own error slot) for one-off\n    /// summary calls outside the main turn (e.g. the sub-agent cap-hit checkpoint),\n    /// so the caller can `invoke` without naming the `Provider` trait. The output\n    /// cap rides the per-call `ModelRequest`, not the model.\n    pub(crate) fn build_summarizer(\n        &self,\n        model: &str,\n        temperature: f64,\n    ) -> anyhow::Result<Arc<dyn tinyagents::harness::model::ChatModel<()>>> {\n        if let Some(direct) = &self.direct_model {\n            let profile = direct.profile().cloned().unwrap_or_default();\n            return Ok(Arc::new(\n                ProfileOverrideModel::new(direct.clone(), profile)\n                    .with_request_model(model)\n                    .with_request_temperature(temperature),","sourceCodeStart":1590,"sourceCodeEnd":1626,"githubUrl":"https://github.com/tinyhumansai/openhuman/blob/a221052e0df5b1f7598fceba7329fd1af95d6699/src/openhuman/agent/tinyagents/mod.rs#L1590-L1626","documentation":"TurnModelSource::build fell through both branches: neither direct_model nor crate_native is set (mod.rs:1608, struct at 1389). TurnModelSource is a two-case sum emulated with Options; every constructor sets exactly one, so this error means the source was constructed empty — an internal wiring bug (a Default or struct literal with both fields None), not a user configuration problem.","triggerScenarios":"A new call site building TurnModelSource via struct literal or Default instead of the provided constructors; a refactor adding a third source kind without extending build(); test scaffolding meaning to inject a direct model but passing None.","commonSituations":"Feature work on the agent harness adding model-source paths; CI failures in newly added turn-assembly tests; code copied from a constructor that then gets its body stripped.","solutions":["Construct the source with a real constructor (direct-model injection or the new_crate_native* family) so exactly one branch is Some","If you added a new source kind, extend build() with its branch before the final Err","Add a constructor-level guard (debug_assert or explicit error) that at least one Option is set"],"exampleFix":"// before\nlet source = TurnModelSource { direct_model: None, crate_native: None, force_text_mode: false };\n\n// after\nlet source = TurnModelSource::new_crate_native_from_string(role, provider_string, config);","handlingStrategy":"validation","validationCode":"// Internal: assert the source is configured before building turn models\nfn assert_configured(source: &TurnModelSource) -> anyhow::Result<()> {\n    if source.direct_model.is_none() && source.crate_native.is_none() {\n        anyhow::bail!(\"TurnModelSource built without a model source — use a real constructor\");\n    }\n    Ok(())\n}","typeGuard":"// Internal narrow: exactly-one-Option invariant of the two-case sum\nimpl TurnModelSource {\n    fn configured(&self) -> bool {\n        self.direct_model.is_some() ^ self.crate_native.is_some()\n    }\n}","tryCatchPattern":"// Add context so the invariant break is diagnosable at the call site\nsource.build(model, temp, ctx).await\n    .context(\"assembling turn harness: TurnModelSource had neither direct nor crate-native model\")?","preventionTips":["Always construct TurnModelSource via its constructors — never struct literals or Default","When adding a source kind, extend build() in the same change","Keep a unit test per constructor asserting build() never hits the fallthrough Err"],"tags":["rust","llm","model","internal-invariant"],"backgroundTag":null,"analyzedSha":"a221052e0df5b1f7598fceba7329fd1af95d6699","analyzedAt":"2026-08-16T12:47:06.542Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}