tinyhumansai/openhuman · error

learning_save_profile: summarisation failed: {e:#}

Error message

learning_save_profile: summarisation failed: {e:#}

What it means

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.

Source

Thrown at src/openhuman/agent/learning/tools.rs:536

        PermissionLevel::Write
    }

    async fn execute(&self, args: serde_json::Value) -> anyhow::Result<ToolResult> {
        log::debug!("[tool][learning] save_profile invoked");
        let markdown = read_required_str(&args, "markdown")?;
        let summarize = args
            .get("summarize")
            .and_then(serde_json::Value::as_bool)
            .unwrap_or(false);
        let config = config_rpc::load_config_with_timeout()
            .await
            .map_err(|e| anyhow::anyhow!("learning_save_profile: {e}"))?;
        let body = if summarize {
            crate::openhuman::agent::learning::linkedin_enrichment::summarise_profile_with_llm(
                &config, &markdown,
            )
            .await
            .map_err(|e| anyhow::anyhow!("learning_save_profile: summarisation failed: {e:#}"))?
        } else {
            markdown
        };
        let path = config.workspace_dir.join("PROFILE.md");
        if let Some(parent) = path.parent() {
            tokio::fs::create_dir_all(parent)
                .await
                .map_err(|e| anyhow::anyhow!("learning_save_profile: create dir failed: {e}"))?;
        }
        tokio::fs::write(&path, &body)
            .await
            .map_err(|e| anyhow::anyhow!("learning_save_profile: write failed: {e}"))?;
        Ok(ToolResult::success(serde_json::to_string(&json!({
            "path": path.display().to_string(),
            "bytes": body.len(),
        }))?))
    }
}

View on GitHub (pinned to a221052e0d)

Solutions

  1. Retry with summarize:false — the tool writes the raw markdown to PROFILE.md without the LLM hop
  2. Verify an inference provider is configured and its key valid (send a trivial chat request)
  3. Trim the markdown and retry summarize:true
  4. Check the error chain for 429/401 to distinguish rate limit from auth

Example fix

// before
tool: learning_save_profile {"markdown":"...","summarize":true} // -> summarisation failed: 401 invalid api key
// after: persist raw, summarize later
tool: learning_save_profile {"markdown":"...","summarize":false} // ok, PROFILE.md written
Defensive patterns

Strategy: fallback

Validate before calling

// Only request summarisation when a provider is actually configured:
// (settings show an inference provider / API key) — otherwise:
let args = json!({"markdown": md, "summarize": false});

Try / catch

let mut args = json!({"markdown": md, "summarize": true});
match tool_exec("learning_save_profile", args.clone()).await {
    Err(e) if e.to_string().contains("summarisation failed") => {
        args["summarize"] = json!(false); // degrade: persist raw markdown
        tool_exec("learning_save_profile", args).await
    }
    other => other,
}

Prevention

When it happens

Trigger: 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.

Common situations: First use of the profile feature before any LLM provider is set up in settings; flaky connectivity; users pasting 50KB profiles.

Related errors


AI-assisted analysis of tinyhumansai/openhuman@a221052e0d (2026-08-16). Data as JSON: /api/errors/7349700c2f2ea458. Report an issue: GitHub.