spagestic commited on
Commit
0be6708
·
1 Parent(s): f5ae245

custom think tool added

Browse files
ui/inference/completion.py CHANGED
@@ -16,7 +16,7 @@ def complete_turn(
16
  temperature: float,
17
  top_p: float,
18
  tools: list[dict[str, Any]] | None,
19
- tool_choice: str = "auto",
20
  ) -> tuple[str, str, list[dict[str, Any]] | None]:
21
  """Run one model turn, preferring streaming and falling back to a single request."""
22
  content = ""
 
16
  temperature: float,
17
  top_p: float,
18
  tools: list[dict[str, Any]] | None,
19
+ tool_choice: Any = "auto",
20
  ) -> tuple[str, str, list[dict[str, Any]] | None]:
21
  """Run one model turn, preferring streaming and falling back to a single request."""
22
  content = ""
ui/inference/config.py CHANGED
@@ -2,8 +2,10 @@
2
  from __future__ import annotations
3
 
4
  from .tool_schemas import TOOL_SCHEMAS
 
5
 
6
  MODEL_ID = "Qwen/Qwen3.6-27B"
7
  MAX_TOOL_ROUNDS = 5
8
 
9
  TOOLS = TOOL_SCHEMAS
 
 
2
  from __future__ import annotations
3
 
4
  from .tool_schemas import TOOL_SCHEMAS
5
+ from .tool_schemas import think as THINK_SCHEMA
6
 
7
  MODEL_ID = "Qwen/Qwen3.6-27B"
8
  MAX_TOOL_ROUNDS = 5
9
 
10
  TOOLS = TOOL_SCHEMAS
11
+ THINK_TOOLS = [THINK_SCHEMA]
ui/inference/respond.py CHANGED
@@ -1,6 +1,8 @@
1
  # ui/inference/respond.py
2
  from __future__ import annotations
3
 
 
 
4
  from typing import Any
5
 
6
  import gradio as gr
@@ -8,7 +10,7 @@ from gradio import ChatMessage
8
  from huggingface_hub import InferenceClient
9
 
10
  from .completion import complete_turn
11
- from .config import MAX_TOOL_ROUNDS, MODEL_ID, TOOLS
12
  from .messages import history_to_api_messages, multimodal_input_to_api_content
13
  from .streaming import yield_response
14
  from .tools import execute_tool_calls
@@ -46,6 +48,38 @@ def respond(
46
  ui_messages: list[ChatMessage] = []
47
 
48
  try:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
49
  for _ in range(MAX_TOOL_ROUNDS):
50
  content, reasoning, tool_calls = complete_turn(
51
  client,
 
1
  # ui/inference/respond.py
2
  from __future__ import annotations
3
 
4
+ import json
5
+ import uuid
6
  from typing import Any
7
 
8
  import gradio as gr
 
10
  from huggingface_hub import InferenceClient
11
 
12
  from .completion import complete_turn
13
+ from .config import MAX_TOOL_ROUNDS, MODEL_ID, THINK_TOOLS, TOOLS
14
  from .messages import history_to_api_messages, multimodal_input_to_api_content
15
  from .streaming import yield_response
16
  from .tools import execute_tool_calls
 
48
  ui_messages: list[ChatMessage] = []
49
 
50
  try:
51
+ content, reasoning, tool_calls = complete_turn(
52
+ client,
53
+ api_messages,
54
+ max_tokens=max_tokens,
55
+ temperature=temperature,
56
+ top_p=top_p,
57
+ tools=THINK_TOOLS,
58
+ tool_choice="required",
59
+ )
60
+ if not tool_calls:
61
+ thought = content or reasoning or "Plan the response before taking action."
62
+ tool_calls = [
63
+ {
64
+ "id": f"call_{uuid.uuid4().hex}",
65
+ "type": "function",
66
+ "function": {
67
+ "name": "think",
68
+ "arguments": json.dumps({"thought": thought}),
69
+ },
70
+ }
71
+ ]
72
+ content = ""
73
+
74
+ for ui_msg, globe_state in execute_tool_calls(
75
+ api_messages,
76
+ ui_messages,
77
+ tool_calls,
78
+ content,
79
+ globe_state,
80
+ ):
81
+ yield ui_msg, globe_state
82
+
83
  for _ in range(MAX_TOOL_ROUNDS):
84
  content, reasoning, tool_calls = complete_turn(
85
  client,
ui/inference/tool_schemas/__init__.py CHANGED
@@ -8,9 +8,11 @@ from .get_passport_stats import SCHEMA as get_passport_stats
8
  from .get_visa_requirement import SCHEMA as get_visa_requirement
9
  from .scrape_web_page import SCHEMA as scrape_web_page
10
  from .search_immigration_info import SCHEMA as search_immigration_info
 
11
  from .update_globe import SCHEMA as update_globe
12
 
13
  TOOL_SCHEMAS: list[dict[str, Any]] = [
 
14
  get_economic_indicator,
15
  get_visa_requirement,
16
  get_passport_stats,
 
8
  from .get_visa_requirement import SCHEMA as get_visa_requirement
9
  from .scrape_web_page import SCHEMA as scrape_web_page
10
  from .search_immigration_info import SCHEMA as search_immigration_info
11
+ from .think import SCHEMA as think
12
  from .update_globe import SCHEMA as update_globe
13
 
14
  TOOL_SCHEMAS: list[dict[str, Any]] = [
15
+ think,
16
  get_economic_indicator,
17
  get_visa_requirement,
18
  get_passport_stats,
ui/inference/tool_schemas/think.py ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ from typing import Any
4
+
5
+
6
+ SCHEMA: dict[str, Any] = {
7
+ "type": "function",
8
+ "function": {
9
+ "name": "think",
10
+ "description": (
11
+ "Use this tool as a private scratchpad to reason step by step before "
12
+ "taking other actions. Record hypotheses, summarize evidence, plan "
13
+ "next steps, or note uncertainties. Do not use it for final "
14
+ "user-facing output."
15
+ ),
16
+ "parameters": {
17
+ "type": "object",
18
+ "properties": {
19
+ "thought": {
20
+ "type": "string",
21
+ "description": (
22
+ "Internal reasoning notes, intermediate analysis, "
23
+ "assumptions, and next-step planning."
24
+ ),
25
+ },
26
+ },
27
+ "required": ["thought"],
28
+ },
29
+ },
30
+ }
ui/inference/tools.py CHANGED
@@ -42,6 +42,8 @@ def _run_tool(
42
  *,
43
  globe_state: dict[str, Any] | None = None,
44
  ) -> tuple[Any, dict[str, Any] | None]:
 
 
45
  if name == "get_economic_indicator":
46
  return (
47
  get_indicator_series(
@@ -110,6 +112,65 @@ def execute_tool_calls(
110
  tool_args = tool_call["function"]["arguments"]
111
  started = time.monotonic()
112
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
113
  ui_messages.append(
114
  ChatMessage(
115
  role="assistant",
 
42
  *,
43
  globe_state: dict[str, Any] | None = None,
44
  ) -> tuple[Any, dict[str, Any] | None]:
45
+ if name == "think":
46
+ return {"ok": True}, globe_state
47
  if name == "get_economic_indicator":
48
  return (
49
  get_indicator_series(
 
112
  tool_args = tool_call["function"]["arguments"]
113
  started = time.monotonic()
114
 
115
+ if tool_name == "think":
116
+ try:
117
+ args = json.loads(tool_args or "{}")
118
+ except json.JSONDecodeError:
119
+ args = {}
120
+ thought = str(args.get("thought") or "").strip()
121
+
122
+ ui_messages.append(
123
+ ChatMessage(
124
+ role="assistant",
125
+ content="Thinking…",
126
+ metadata={
127
+ "title": "Thinking",
128
+ "status": "pending",
129
+ },
130
+ )
131
+ )
132
+ yield ui_messages, globe_state
133
+
134
+ if thought:
135
+ prefix = "Thinking:\n\n"
136
+ for index in range(len(thought)):
137
+ ui_messages[-1] = ChatMessage(
138
+ role="assistant",
139
+ content=f"{prefix}{thought[: index + 1]}",
140
+ metadata={
141
+ "title": "Thinking",
142
+ "status": "pending",
143
+ },
144
+ )
145
+ yield ui_messages, globe_state
146
+
147
+ result, globe_state = run_tool(
148
+ tool_name,
149
+ tool_args,
150
+ globe_state=globe_state,
151
+ )
152
+ duration = time.monotonic() - started
153
+ ui_messages[-1] = ChatMessage(
154
+ role="assistant",
155
+ content=f"Thinking:\n\n{thought}" if thought else "Thinking complete.",
156
+ metadata={
157
+ "title": "Thinking",
158
+ "status": "done",
159
+ "duration": duration,
160
+ },
161
+ )
162
+ yield ui_messages, globe_state
163
+
164
+ api_messages.append(
165
+ {
166
+ "role": "tool",
167
+ "tool_call_id": tool_call["id"],
168
+ "name": tool_name,
169
+ "content": result,
170
+ }
171
+ )
172
+ continue
173
+
174
  ui_messages.append(
175
  ChatMessage(
176
  role="assistant",