unsloth/studio/backend/core/inference
Daniel Han a067609fc3 Fix ~1.2s TTFT penalty when tools are enabled in Studio
When users enable web search, Python execution, or terminal tools,
every message gets a ~1.2s delay before any text appears -- even when
the model does not call any tool. This happens because
generate_chat_completion_with_tools() does a non-streaming detection
pass (stream: False) first, waits for the complete response, then
checks for tool calls. For the ~90% of messages that don't trigger a
tool call, this blocking wait is entirely wasted.

Root cause: the detection pass payload uses stream: False, forcing
llama-server to generate the entire response before returning any
tokens.

Fix: replace the non-streaming detection pass with a streaming pass
(stream: True) and a speculative buffer state machine that detects
tool signals in the first 1-2 SSE chunks:

- BUFFERING: accumulate content tokens, check first chars for tool
  signal prefixes (<tool_call>, <function=)
- STREAMING: no tool detected, yield tokens to caller immediately
- DRAINING: tool signal found, silently accumulate rest of stream

Three detection paths:
1. Structured delta.tool_calls -- detected instantly, transition to
   DRAINING, accumulate fragments, assemble at stream end.
2. XML tool markup in content -- buffer holds up to 32 chars checking
   for <tool_call> or <function= prefix, then transitions to DRAINING.
3. No tool signal -- first non-whitespace, non-XML char triggers
   immediate transition to STREAMING (fast path, ~90% of requests).

Safety net: after any stream ends in STREAMING state, check accumulated
content for XML tool signals. Handles rare "content before tool call"
edge case.

Additional supporting changes:
- Add headers parameter to _stream_with_retry for auth forwarding
- Share _strip_tool_markup and regex patterns between the detection
  pass and the final streaming pass (removes duplication)
- Remove the iteration==0 non-streaming content shortcut (no longer
  needed since all iterations stream directly)
- Keep the final streaming pass as fallback for max_tool_iterations
  exhaustion

Benchmarked on Qwen3.5-4B Q4_K_XL:
- No tools:              TTFT ~112ms (unchanged)
- Tools enabled, no call: TTFT ~112ms (was ~1207ms)
- Decode TPS:            226 (unchanged in all cases)
2026-03-27 06:16:09 +00:00
..
__init__.py Final cleanup 2026-03-12 18:28:04 +00:00
audio_codecs.py studio: per-model inference defaults, GGUF slider fix, reasoning toggle (#4325) 2026-03-16 06:37:55 -07:00
defaults.py studio: web search, KV cache dtype, training progress, inference fixes 2026-03-17 00:30:01 -07:00
inference.py fix: system prompt ignored in unsloth inference (#4528) 2026-03-24 04:01:33 -07:00
llama_cpp.py Fix ~1.2s TTFT penalty when tools are enabled in Studio 2026-03-27 06:16:09 +00:00
orchestrator.py feat(studio): infinite scroll for recommended models list (#4414) 2026-03-18 03:17:01 -07:00
tools.py Fix studio chat crash on Mac: vendor check_signal_escape_patterns (#4431) 2026-03-18 09:10:13 -07:00
worker.py Combine studio setup fixes: frontend caching, venv isolation, Windows CPU support (#4413) 2026-03-18 03:52:25 -07:00