Skip to content

Commit 0c078fe

Browse files
committed
Tighten local-tool-runtime comments
1 parent 671c340 commit 0c078fe

5 files changed

Lines changed: 28 additions & 46 deletions

File tree

studio/backend/core/inference/external_agentic.py

Lines changed: 11 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -176,14 +176,11 @@ async def stream_external_local_tool_loop(
176176
created = int(time.time())
177177
cancel_event = cancel_event or threading.Event()
178178

179-
# 9999 is the "no limit" sentinel; pass None so execute_tool never times out
180-
# (mirrors the local GGUF loop).
179+
# 9999 = "no limit" sentinel: pass None so execute_tool never times out (mirrors local GGUF loop).
181180
effective_tool_timeout = None if tool_call_timeout >= 9999 else tool_call_timeout
182-
# Total tool calls executed across all rounds must not exceed the caller's
183-
# per-message budget, even when a single completion returns parallel calls.
181+
# Cap total tool calls across all rounds at the caller's per-message budget, even with parallel calls.
184182
calls_remaining = max_tool_iterations
185-
# A forced tool_choice must only apply to the first round; after a tool
186-
# runs, later rounds are freed to synthesize the answer.
183+
# A forced tool_choice applies only to the first round; later rounds are freed to answer.
187184
active_tool_choice = tool_choice
188185

189186
enabled_names = {
@@ -217,12 +214,10 @@ async def stream_external_local_tool_loop(
217214
stream = True,
218215
)
219216

220-
# Stop may fire while the remote is still in prefill and the read is
221-
# blocked awaiting the next SSE line. Drive the generator one item at a
222-
# time via a cancellable task raced against the cancel event, so Stop
223-
# abandons the in-flight read immediately (calling aclose() on a
224-
# generator that is mid-await raises RuntimeError, so it cannot be used
225-
# to interrupt from another task).
217+
# Stop may fire while the remote read is blocked awaiting the next SSE line. Drive
218+
# the generator one item at a time via a cancellable task raced against the cancel
219+
# event so Stop abandons the read immediately (aclose() on a mid-await generator
220+
# raises RuntimeError, so it can't interrupt from another task).
226221
async def _wait_cancel() -> None:
227222
while not cancel_event.is_set():
228223
await asyncio.sleep(0.1)
@@ -320,7 +315,7 @@ async def _wait_cancel() -> None:
320315
ordered_calls = [tc for tc in ordered_calls if (tc.get("function") or {}).get("name")]
321316

322317
if not ordered_calls or finish_reason not in (None, "tool_calls", "stop"):
323-
# No tool calls emit a terminal finish if we streamed content.
318+
# No tool calls: emit a terminal finish if we streamed content.
324319
if saw_content or finish_reason:
325320
yield _openai_content_chunk_line(
326321
completion_id = completion_id,
@@ -356,8 +351,7 @@ async def _wait_cancel() -> None:
356351
conversation.append(
357352
{
358353
"role": "assistant",
359-
# Retain any streamed explanation so the follow-up round keeps
360-
# the model's own context for interpreting tool results.
354+
# Retain streamed explanation so the follow-up round keeps the model's context.
361355
"content": assistant_content or None,
362356
"tool_calls": assistant_tool_calls,
363357
}
@@ -373,8 +367,7 @@ async def _wait_cancel() -> None:
373367
tool_call_id = tc["id"]
374368

375369
_prov = tool_event_provenance()
376-
# Later rounds must be free to answer; a forced choice only applies
377-
# to the first round.
370+
# Later rounds must be free to answer; a forced choice applies only to the first round.
378371
active_tool_choice = "auto"
379372

380373
# Skip tools the caller did not enable (defense in depth).
@@ -465,7 +458,7 @@ async def _wait_cancel() -> None:
465458

466459
continue
467460

468-
# Budget exhausted after tool rounds one final synthesis pass without tools.
461+
# Budget exhausted after tool rounds: one final synthesis pass without tools.
469462
final_finish_reason = None
470463
if not cancel_event.is_set():
471464
if max_tool_iterations > 0:

studio/backend/routes/inference.py

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6789,9 +6789,8 @@ async def _proxy_to_external_provider(
67896789
# `model_fields_set` tracks explicit-vs-default per request.
67906790
_top_k_explicit = payload.top_k if "top_k" in payload.model_fields_set else None
67916791

6792-
# OAI-compat Connections (ollama / llama.cpp / vLLM / custom) can drive
6793-
# Unsloth's local tool runtime against the remote model (#7282). Hosted
6794-
# providers stay on the pure-proxy + supportsBuiltin* path.
6792+
# OAI-compat Connections (ollama / llama.cpp / vLLM / custom) drive Unsloth's local tool
6793+
# runtime against the remote model (#7282); hosted providers stay on the pure-proxy path.
67956794
from core.inference.external_agentic import (
67966795
provider_supports_local_tool_runtime,
67976796
stream_external_local_tool_loop,
@@ -6806,8 +6805,7 @@ async def _proxy_to_external_provider(
68066805
and payload.stream
68076806
and (_tools_on_ext or _mcp_allowed_ext)
68086807
and not payload.tools # client-supplied tools stay on passthrough
6809-
# Callers opting out via tool_choice="none" skip the loop, mirroring
6810-
# the local GGUF routing gate.
6808+
# tool_choice="none" opts out, mirroring the local GGUF routing gate.
68116809
and not (
68126810
payload.tool_choice == "none" and not _explicit_studio_tool_loop_requested(payload)
68136811
)
@@ -6820,13 +6818,12 @@ async def _stream_local_tools():
68206818
payload, tools_on = bool(_tools_on_ext), mcp_allowed = _mcp_allowed_ext
68216819
)
68226820
if not tools_to_use:
6823-
# Nothing to run reuse the plain proxy stream (incl. client.close).
6821+
# Nothing to run: reuse the plain proxy stream (incl. client.close).
68246822
async for line in _stream():
68256823
yield line
68266824
return
68276825

6828-
# Inject the same tool-action nudge local GGUF turns get so small
6829-
# remote models know when to call tools.
6826+
# Inject the same tool-action nudge local GGUF turns get so small remote models know when to call tools.
68306827
_nudge = _build_tool_action_nudge(tools = tools_to_use, model_name = model)
68316828
_nudge = _apply_rag_nudge(_nudge, tools_to_use, rag_scope = payload.rag_scope)
68326829
loop_messages = list(chat_messages)
@@ -7208,9 +7205,8 @@ async def openai_chat_completions(
72087205

72097206
untrack_current_request(request.scope)
72107207

7211-
# Resolve provider type early so OAI-compat Connections (ollama /
7212-
# llama.cpp / vLLM / custom) can use Unsloth's local tool runtime
7213-
# (#7282) instead of being rejected on confirm_tool_calls.
7208+
# Resolve provider type early so OAI-compat Connections (ollama / llama.cpp / vLLM /
7209+
# custom) can use the local tool runtime (#7282) instead of being rejected on confirm_tool_calls.
72147210
_ext_provider_type = payload.provider_type
72157211
if payload.provider_id and not _ext_provider_type:
72167212
_cfg = providers_db.get_provider(payload.provider_id)

studio/frontend/src/features/chat/api/chat-adapter.ts

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2232,8 +2232,7 @@ export function createOpenAIStreamAdapter(
22322232
externalProvider.baseUrl,
22332233
),
22342234
);
2235-
// OAI-compat Connections (ollama / llama.cpp / vLLM / custom) drive
2236-
// Unsloth's local tool runtime against the remote model (#7282).
2235+
// OAI-compat Connections drive Unsloth's local tool runtime against the remote model (#7282).
22372236
const localToolRuntimeForThisTurn = Boolean(
22382237
externalProvider &&
22392238
providerSupportsLocalToolRuntime(externalProvider.providerType),
@@ -3056,10 +3055,8 @@ export function createOpenAIStreamAdapter(
30563055
...(externalCapabilities?.presencePenalty
30573056
? { presence_penalty: params.presencePenalty }
30583057
: {}),
3059-
// Hosted providers: enabled_tools maps to server-side builtins.
3060-
// OAI-compat Connections: enable Unsloth's local tool runtime
3061-
// (web_search / python / terminal / MCP) against the remote
3062-
// model (#7282).
3058+
// Hosted providers: enabled_tools maps to server-side builtins. OAI-compat
3059+
// Connections: enable the local tool runtime (web_search / python / terminal / MCP) (#7282).
30633060
...(webSearchEnabledForThisTurn ||
30643061
webFetchEnabledForThisTurn ||
30653062
codeExecEnabledForThisTurn ||

studio/frontend/src/features/chat/chat-page.tsx

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2079,10 +2079,8 @@ export function ChatPage({
20792079
: true
20802080
: state.reasoningEnabled,
20812081
supportsPreserveThinking: false,
2082-
// Hosted providers have no local tool runtime, so supportsTools stays
2083-
// false and supportsBuiltin* carries server-side capability. OAI-compat
2084-
// Connections (ollama / llama.cpp / vLLM / custom) can drive Unsloth's
2085-
// local Search/Code/MCP tools against the remote model (#7282).
2082+
// Hosted providers have no local tool runtime (supportsTools false; supportsBuiltin*
2083+
// carries server-side capability). OAI-compat Connections drive local Search/Code/MCP (#7282).
20862084
supportsTools: supportsLocalToolRuntime,
20872085
supportsBuiltinWebSearch,
20882086
supportsBuiltinCodeExecution,
@@ -2608,8 +2606,7 @@ export function ChatPage({
26082606
: true
26092607
: store.reasoningEnabled,
26102608
supportsPreserveThinking: false,
2611-
// Hosted providers → supportsTools false + supportsBuiltin*.
2612-
// OAI-compat Connections can drive local Search/Code/MCP (#7282).
2609+
// Hosted providers: supportsTools false + supportsBuiltin*. OAI-compat Connections drive local Search/Code/MCP (#7282).
26132610
supportsTools: supportsLocalToolRuntime,
26142611
supportsBuiltinWebSearch,
26152612
supportsBuiltinCodeExecution,

studio/frontend/src/features/chat/provider-capabilities.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -160,11 +160,10 @@ function _inferProviderFromOpenrouterId(
160160
}
161161

162162
/**
163-
* OAI-compat Connections (Ollama / llama.cpp / vLLM / Custom) on a remote
164-
* endpoint that can still drive Unsloth's *local* tool runtime (web_search /
165-
* python / terminal / MCP) on the Studio host. Unlike `providerSupportsBuiltin*`
166-
* (server-side hosted tools), these get `supportsTools=true` and the backend
167-
* runs the local tool loop against the model's function calls (#7282).
163+
* OAI-compat Connections (Ollama / llama.cpp / vLLM / Custom) on a remote endpoint that
164+
* can drive Unsloth's *local* tool runtime (web_search / python / terminal / MCP) on the
165+
* Studio host. Unlike `providerSupportsBuiltin*` (server-side), these get `supportsTools=true`
166+
* and the backend runs the local tool loop against the model (#7282).
168167
*/
169168
const LOCAL_TOOL_RUNTIME_PROVIDER_TYPES = new Set([
170169
"ollama",

0 commit comments

Comments
 (0)