{"record":{"id":"7349700c2f2ea458","repo":"tinyhumansai/openhuman","slug":"learning-save-profile-summarisation-failed-e","errorCode":null,"errorMessage":"learning_save_profile: summarisation failed: {e:#}","messagePattern":"learning_save_profile: summarisation failed: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/openhuman/agent/learning/tools.rs","lineNumber":536,"sourceCode":"        PermissionLevel::Write\n    }\n\n    async fn execute(&self, args: serde_json::Value) -> anyhow::Result<ToolResult> {\n        log::debug!(\"[tool][learning] save_profile invoked\");\n        let markdown = read_required_str(&args, \"markdown\")?;\n        let summarize = args\n            .get(\"summarize\")\n            .and_then(serde_json::Value::as_bool)\n            .unwrap_or(false);\n        let config = config_rpc::load_config_with_timeout()\n            .await\n            .map_err(|e| anyhow::anyhow!(\"learning_save_profile: {e}\"))?;\n        let body = if summarize {\n            crate::openhuman::agent::learning::linkedin_enrichment::summarise_profile_with_llm(\n                &config, &markdown,\n            )\n            .await\n            .map_err(|e| anyhow::anyhow!(\"learning_save_profile: summarisation failed: {e:#}\"))?\n        } else {\n            markdown\n        };\n        let path = config.workspace_dir.join(\"PROFILE.md\");\n        if let Some(parent) = path.parent() {\n            tokio::fs::create_dir_all(parent)\n                .await\n                .map_err(|e| anyhow::anyhow!(\"learning_save_profile: create dir failed: {e}\"))?;\n        }\n        tokio::fs::write(&path, &body)\n            .await\n            .map_err(|e| anyhow::anyhow!(\"learning_save_profile: write failed: {e}\"))?;\n        Ok(ToolResult::success(serde_json::to_string(&json!({\n            \"path\": path.display().to_string(),\n            \"bytes\": body.len(),\n        }))?))\n    }\n}","sourceCodeStart":518,"sourceCodeEnd":554,"githubUrl":"https://github.com/tinyhumansai/openhuman/blob/a221052e0df5b1f7598fceba7329fd1af95d6699/src/openhuman/agent/learning/tools.rs#L518-L554","documentation":"Thrown by learning_save_profile when summarize=true and linkedin_enrichment::summarise_profile_with_llm() failed. That function sends the raw markdown to the configured LLM provider to produce a condensed profile; failure is an inference-layer problem — no provider/key configured, network failure, rate limit, or the request being rejected (e.g. oversized markdown). The full {e:#} chain names the provider error.","triggerScenarios":"Calling learning_save_profile {markdown, summarize:true} with no inference provider configured or an expired API key; transient network outage; rate-limited provider; an extremely long pasted LinkedIn profile exceeding context/limits.","commonSituations":"First use of the profile feature before any LLM provider is set up in settings; flaky connectivity; users pasting 50KB profiles.","solutions":["Retry with summarize:false — the tool writes the raw markdown to PROFILE.md without the LLM hop","Verify an inference provider is configured and its key valid (send a trivial chat request)","Trim the markdown and retry summarize:true","Check the error chain for 429/401 to distinguish rate limit from auth"],"exampleFix":"// before\ntool: learning_save_profile {\"markdown\":\"...\",\"summarize\":true} // -> summarisation failed: 401 invalid api key\n// after: persist raw, summarize later\ntool: learning_save_profile {\"markdown\":\"...\",\"summarize\":false} // ok, PROFILE.md written","handlingStrategy":"fallback","validationCode":"// Only request summarisation when a provider is actually configured:\n// (settings show an inference provider / API key) — otherwise:\nlet args = json!({\"markdown\": md, \"summarize\": false});","typeGuard":null,"tryCatchPattern":"let mut args = json!({\"markdown\": md, \"summarize\": true});\nmatch tool_exec(\"learning_save_profile\", args.clone()).await {\n    Err(e) if e.to_string().contains(\"summarisation failed\") => {\n        args[\"summarize\"] = json!(false); // degrade: persist raw markdown\n        tool_exec(\"learning_save_profile\", args).await\n    }\n    other => other,\n}","preventionTips":["Configure and verify an inference provider before using summarize:true","Trim very long profiles before summarising to avoid context/rate limits","Treat 429s as back-off signals, not permanent failures"],"tags":["rust","llm","inference","learning","network"],"backgroundTag":null,"analyzedSha":"a221052e0df5b1f7598fceba7329fd1af95d6699","analyzedAt":"2026-08-16T12:47:06.542Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}