Skip to content

Commit 98fd2ac

Browse files
gryszzzgryszclaude
authored
fix(providers): recover Groq tool_use_failed as a plain assistant turn (v0.7.6) (#97)
Groq rejects a generation with HTTP 400 code=tool_use_failed when the model emits a malformed tool call — but preserves the text the model was producing in error.failed_generation. Previously this failed the whole run; now the adapter recovers that text as a plain assistant turn (no intents — a call that cannot parse never reaches the runtime), so the chat gets the model's words instead of an error. A humanized fallback covers variants without recoverable text. With Auto mode advertising the full tool surface to llama-class models this failure is common, so recovery matters. Versions bumped to 0.7.6. Verified: cognition + runtime crates build and test green. Not verified here: a live Groq tool_use_failed reproduction (depends on model behavior). Co-authored-by: grysz <117801274+grysz@users.noreply.github.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
1 parent 014cacb commit 98fd2ac

9 files changed

Lines changed: 44 additions & 20 deletions

File tree

thymos/Cargo.lock

Lines changed: 12 additions & 12 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

thymos/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ members = [
1616
]
1717

1818
[workspace.package]
19-
version = "0.7.5"
19+
version = "0.7.6"
2020
edition = "2021"
2121
license = "Apache-2.0"
2222
rust-version = "1.80"

thymos/clients/desktop/package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

thymos/clients/desktop/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "thymos-desktop",
3-
"version": "0.7.5",
3+
"version": "0.7.6",
44
"private": true,
55
"description": "OpenThymos Desktop — governed-cognition runtime, install once.",
66
"scripts": {

thymos/clients/desktop/src-tauri/Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

thymos/clients/desktop/src-tauri/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
[package]
77
name = "thymos-desktop"
8-
version = "0.7.5"
8+
version = "0.7.6"
99
edition = "2021"
1010
license = "Apache-2.0"
1111
description = "OpenThymos Desktop — a governed-cognition client that supervises a local runtime."

thymos/clients/desktop/src-tauri/tauri.conf.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"$schema": "https://schema.tauri.app/config/2",
33
"productName": "OpenThymos",
4-
"version": "0.7.5",
4+
"version": "0.7.6",
55
"identifier": "com.openthymos.desktop",
66
"build": {
77
"frontendDist": "../src"

thymos/crates/thymos-cognition/src/openai.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,28 @@ impl Cognition for OpenAiCognition {
230230
.json()
231231
.map_err(|e| Error::Other(format!("openai response parse: {e}")))?;
232232
if !status.is_success() {
233+
// Groq's `tool_use_failed`: the model emitted a malformed tool
234+
// call and the API rejected the whole generation with a 400 —
235+
// but the text the model was trying to produce is preserved in
236+
// `error.failed_generation`. Recover it as a plain assistant
237+
// turn instead of failing the run: no tool executes (a call that
238+
// can't parse never reaches the runtime), the model just "spoke".
239+
if status.as_u16() == 400 {
240+
if let Some(failed) = resp_json
241+
.pointer("/error/failed_generation")
242+
.and_then(|v| v.as_str())
243+
.filter(|s| !s.trim().is_empty())
244+
{
245+
let text = failed.to_string();
246+
self.messages
247+
.push(json!({ "role": "assistant", "content": text }));
248+
return Ok(CognitionStep {
249+
intents: vec![],
250+
final_answer: Some(text),
251+
usage: crate::CognitionUsage::default(),
252+
});
253+
}
254+
}
233255
// Prefer the standard header; fall back to providers that put the
234256
// precise wait only in the JSON body ("Please try again in 9.62s").
235257
let hint_ms = retry_after_header

thymos/crates/thymos-runtime/src/agent_async.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,9 @@ fn parse_retry_after_hint(msg: &str) -> Option<u64> {
4242
/// some providers, embed request context). Unknown errors get a generic line.
4343
pub fn humanize_provider_error(msg: &str) -> String {
4444
let m = msg.to_lowercase();
45-
if m.contains("429") || m.contains("rate limit") {
45+
if m.contains("tool_use_failed") {
46+
"The model fumbled a tool call (a provider-side formatting failure). Just ask again — smaller steps help, or switch models in Providers.".to_string()
47+
} else if m.contains("429") || m.contains("rate limit") {
4648
"The provider is rate-limiting requests right now (token budget).".to_string()
4749
} else if m.contains("401") || m.contains("invalid api key") || m.contains("unauthorized") {
4850
"The provider rejected the API key. Check it in Settings.".to_string()

0 commit comments

Comments
 (0)