refactor: remove Responses API, consolidate to Chat Completions (#272)

* fix: strip reasoning from LLM responses and persist assistant messages reliably

- Filter out `type: "reasoning"` output items from NEAR AI Responses API
  parsing so chain-of-thought never reaches the UI (nearai.rs)
- Rewrite clean_response with regex-based tag stripping that is
  code-aware (preserves tags inside fenced blocks and inline backticks),
  supports 9+ tag names (think, thought, reasoning, reflection, etc.),
  handles <final> extraction, pipe-delimited tags, and case/whitespace
  tolerance (reasoning.rs)
- Add Reasoning::complete() helper so all non-agentic LLM call sites
  (summarize, suggest, heartbeat, compaction) get automatic response
  cleaning; thread SafetyLayer through to those callers
- Change persist_turn from fire-and-forget tokio::spawn to awaited async
  so both user and assistant messages are written before returning,
  preventing data loss on shutdown/restart
- Pass input_count through seed_response_chain so response chaining
  delta calculation is accurate after thread hydration on restart
- Make NearAiResponse.usage optional and preserve response_id in alt
  response path for chaining continuity
- Persist session token to DB during onboarding wizard so runtime
  loads it without legacy-key fallback; suppress spurious warning on
  fresh installs
- Fix dev tool double-registration when builder already registers them
- Load dotenv/ironclaw env for doctor and status subcommands
- Reduce startup log noise (demote info→debug for skills, remove
  redundant info lines)

Co-Authored-By: Claude Opus 4.6 <[email protected]>

* Nudge to not loop over tools continuesly

* refactor: remove Responses API, consolidate NEAR AI to Chat Completions only

The Responses API provider (nearai.rs, 1278 lines) added significant complexity
(response chaining state machine, delta message calculation, previous_response_id
persistence) for marginal benefit. This consolidates to the Chat Completions API
only, upgrading NearAiChatProvider with dual auth (session token + API key) and
401 retry for session token renewal.

- Delete src/llm/nearai.rs (Responses API provider)
- Upgrade nearai_chat.rs with SessionManager, dual auth, flexible list_models
- Remove response_id from CompletionResponse and ToolCompletionResponse
- Remove seed_response_chain/get_response_chain_id from LlmProvider trait
- Remove response chain persistence from agent (thread_ops, session)
- Remove NearAiApiMode enum and NEARAI_API_MODE config
- Clean up all wrapper providers (retry, circuit_breaker, failover, cache)
- Update documentation (CLAUDE.md, .env.example)

Co-Authored-By: Claude Opus 4.6 <[email protected]>

* feat: runtime log level control via gateway UI and URL parameter

Add server-side log level switching using tracing_subscriber::reload::Layer
so the EnvFilter can be swapped at runtime without restarting. Expose via
GET/PUT /api/logs/level endpoints, a "Server: LEVEL" dropdown in the logs
toolbar, and a ?log_level=debug URL parameter for one-click activation.

Also applies cargo fmt to pre-existing files (llm/, tests/).

Co-Authored-By: Claude Opus 4.6 <[email protected]>

---------

Co-authored-by: Claude Opus 4.6 <[email protected]>
This commit is contained in:
Illia Polosukhin
2026-02-20 20:43:32 +00:00
committed by GitHub
co-authored by Claude Opus 4.6
parent 7df356c109
commit 448383cfb0
38 changed files with 1331 additions and 1785 deletions
+54 -1
View File
@@ -826,6 +826,12 @@ impl SetupWizard {
self.session_manager = Some(session);
// Persist session token to the database so the runtime can load it
// via `attach_store()` → `load_session_from_db()` without the
// backwards-compat fallback. The session manager saved to disk but
// doesn't have a DB store attached during onboarding.
self.persist_session_to_db().await;
// If the user chose the API key path, NEARAI_API_KEY is now set
// in the environment. Persist it to the encrypted secrets store
// so inject_llm_keys_from_secrets() can load it on future runs.
@@ -1160,7 +1166,6 @@ impl SetupWizard {
base_url,
auth_base_url,
session_path: crate::llm::session::default_session_path(),
api_mode: crate::config::NearAiApiMode::Responses,
api_key: None,
fallback_model: None,
max_retries: 3,
@@ -1861,6 +1866,54 @@ impl SetupWizard {
Ok(())
}
/// Persist the NEAR AI session token to the database.
///
/// The session manager writes to disk during `ensure_authenticated()` but
/// doesn't have a DB store attached during onboarding. This reads the
/// session file from disk and stores it under the `nearai.session_token`
/// key so the runtime's `attach_store()` finds it without fallback.
///
/// Best-effort: silently ignores errors (no DB connection yet, no
/// session file, etc.).
async fn persist_session_to_db(&self) {
let session_path = crate::llm::session::default_session_path();
let data = match std::fs::read_to_string(&session_path) {
Ok(d) if !d.trim().is_empty() => d,
_ => return,
};
let value: serde_json::Value = match serde_json::from_str(&data) {
Ok(v) => v,
Err(_) => return,
};
#[cfg(feature = "postgres")]
if let Some(ref pool) = self.db_pool {
let store = crate::history::Store::from_pool(pool.clone());
if let Err(e) = store
.set_setting("default", "nearai.session_token", &value)
.await
{
tracing::debug!("Could not persist session token to postgres: {}", e);
} else {
tracing::debug!("Session token persisted to database");
return;
}
}
#[cfg(feature = "libsql")]
if let Some(ref backend) = self.db_backend {
use crate::db::SettingsStore as _;
if let Err(e) = backend
.set_setting("default", "nearai.session_token", &value)
.await
{
tracing::debug!("Could not persist session token to libsql: {}", e);
} else {
tracing::debug!("Session token persisted to database");
}
}
}
/// Persist settings to DB and bootstrap .env after each step.
///
/// Silently ignores errors (e.g., DB not connected yet before step 1