Skip to content

Commit 078e6db

Browse files
authored
Use explicit tool selection in compare (#830)
* Update compare defaults and disable local tools * Scope tool removal to compare mode * Use explicit tool selection for compare * Align tool access across chat surfaces * Adjust comparison starter prompts * Trim OSS and Cloud comparison features
1 parent 97ae67a commit 078e6db

6 files changed

Lines changed: 68 additions & 45 deletions

File tree

docs/app/api/chat/route.ts

Lines changed: 61 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,19 @@ const openUiSystemPrompt = readFileSync(
1111

1212
const markdownSystemPrompt = `You are a helpful assistant. Respond using clear, well-structured GitHub-Flavored Markdown.
1313
14-
Use headings, lists, tables, links, block quotes, and fenced code blocks when they make the response easier to understand. Use the available tools when they are relevant, and incorporate their results into the answer.
14+
Use headings, lists, tables, links, block quotes, and fenced code blocks when they make the response easier to understand.
1515
1616
Return only Markdown content. Do not emit OpenUI Lang, component syntax, JSON UI descriptions, or instructions for a renderer.`;
1717

1818
type ResponseMode = "markdown" | "openui";
19+
const TOOL_NAMES = ["get_weather", "get_stock_price", "search_web"] as const;
20+
type ToolName = (typeof TOOL_NAMES)[number];
21+
const TOOL_NAME_SET = new Set<string>(TOOL_NAMES);
1922

2023
interface ChatRequestBody {
2124
messages: unknown[];
2225
responseMode?: ResponseMode;
26+
toolNames?: ToolName[];
2327
}
2428

2529
function invalidRequest(message: string) {
@@ -31,7 +35,7 @@ function parseRequestBody(body: unknown): ChatRequestBody | Response {
3135
return invalidRequest("Request body must be a JSON object");
3236
}
3337

34-
const { messages, responseMode } = body as Record<string, unknown>;
38+
const { messages, responseMode, toolNames } = body as Record<string, unknown>;
3539

3640
if (!Array.isArray(messages)) {
3741
return invalidRequest("messages must be an array");
@@ -41,9 +45,18 @@ function parseRequestBody(body: unknown): ChatRequestBody | Response {
4145
return invalidRequest('responseMode must be either "markdown" or "openui"');
4246
}
4347

48+
if (
49+
toolNames !== undefined &&
50+
(!Array.isArray(toolNames) ||
51+
!toolNames.every((toolName) => typeof toolName === "string" && TOOL_NAME_SET.has(toolName)))
52+
) {
53+
return invalidRequest(`toolNames must contain only: ${TOOL_NAMES.join(", ")}`);
54+
}
55+
4456
return {
4557
messages,
4658
responseMode: responseMode as ResponseMode | undefined,
59+
toolNames: toolNames as ToolName[] | undefined,
4760
};
4861
}
4962

@@ -262,7 +275,11 @@ export async function POST(req: NextRequest) {
262275
return parsedBody;
263276
}
264277

265-
const { messages, responseMode = "openui" } = parsedBody;
278+
const { messages, responseMode = "openui", toolNames } = parsedBody;
279+
const selectedTools =
280+
toolNames === undefined
281+
? tools
282+
: tools.filter((tool) => toolNames.includes(tool.function.name as ToolName));
266283

267284
const apiKey = process.env.OPENROUTER_API_KEY;
268285
if (!apiKey) {
@@ -328,15 +345,24 @@ export async function POST(req: NextRequest) {
328345
let callIdx = 0;
329346
let resultIdx = 0;
330347

331-
const runner = (client.chat.completions as any).runTools(
332-
{
333-
model: MODEL,
334-
messages: chatMessages,
335-
tools,
336-
stream: true,
337-
},
338-
{ signal: req.signal },
339-
);
348+
const runner: any =
349+
selectedTools.length === 0
350+
? client.chat.completions.stream(
351+
{
352+
model: MODEL,
353+
messages: chatMessages,
354+
},
355+
{ signal: req.signal },
356+
)
357+
: (client.chat.completions as any).runTools(
358+
{
359+
model: MODEL,
360+
messages: chatMessages,
361+
tools: selectedTools,
362+
stream: true,
363+
},
364+
{ signal: req.signal },
365+
);
340366
activeRunner = runner;
341367

342368
const handleAbort = () => {
@@ -351,27 +377,29 @@ export async function POST(req: NextRequest) {
351377
close();
352378
};
353379

354-
runner.on("functionToolCall", (fc: any) => {
355-
const id = `tc-${callIdx}`;
356-
pendingCalls.push({ id, name: fc.name, arguments: fc.arguments });
357-
enqueue(sseToolCallStart(encoder, { id, function: { name: fc.name } }, callIdx));
358-
callIdx++;
359-
});
360-
361-
runner.on("functionToolCallResult", (result: string) => {
362-
const tc = pendingCalls[resultIdx];
363-
if (tc) {
364-
enqueue(
365-
sseToolCallArgs(
366-
encoder,
367-
{ id: tc.id, function: { arguments: tc.arguments } },
368-
result,
369-
resultIdx,
370-
),
371-
);
372-
}
373-
resultIdx++;
374-
});
380+
if (selectedTools.length > 0) {
381+
runner.on("functionToolCall", (fc: any) => {
382+
const id = `tc-${callIdx}`;
383+
pendingCalls.push({ id, name: fc.name, arguments: fc.arguments });
384+
enqueue(sseToolCallStart(encoder, { id, function: { name: fc.name } }, callIdx));
385+
callIdx++;
386+
});
387+
388+
runner.on("functionToolCallResult", (result: string) => {
389+
const tc = pendingCalls[resultIdx];
390+
if (tc) {
391+
enqueue(
392+
sseToolCallArgs(
393+
encoder,
394+
{ id: tc.id, function: { arguments: tc.arguments } },
395+
result,
396+
resultIdx,
397+
),
398+
);
399+
}
400+
resultIdx++;
401+
});
402+
}
375403

376404
runner.on("chunk", (chunk: any) => {
377405
// Keep credit handling to non-2xx responses. Provider-specific mid-stream

docs/app/chat/_components/agent-surfaces/oss-agent-surface.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ export function OssAgentSurface({ themeMode, onCreditsExhausted }: OssAgentSurfa
4747
headers: { "Content-Type": "application/json" },
4848
body: JSON.stringify({
4949
messages: openAIMessageFormat.toApi(messages),
50+
toolNames: [],
5051
}),
5152
signal,
5253
});

docs/app/compare/_components/agent-surfaces/use-comparison-chat-llm.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ export function useComparisonChatLLM(
2323
body: JSON.stringify({
2424
messages: openAIMessageFormat.toApi(messages),
2525
responseMode,
26+
toolNames: [],
2627
}),
2728
signal,
2829
});

docs/app/compare/_components/chat-page-header.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,6 @@ interface ComparisonPairMetadata {
6060
const ALL_MODES_SUPPORTED: FeatureSupport = { markdown: true, oss: true, cloud: true };
6161
const OSS_AND_CLOUD_SUPPORTED: FeatureSupport = { markdown: false, oss: true, cloud: true };
6262
const CLOUD_ONLY_SUPPORTED: FeatureSupport = { markdown: false, oss: false, cloud: true };
63-
const MARKDOWN_AND_OSS_SUPPORTED: FeatureSupport = { markdown: true, oss: true, cloud: false };
6463

6564
function comparisonFeature(label: string, support: FeatureSupport): ComparisonFeature {
6665
return { label, support };
@@ -101,7 +100,6 @@ const PAIR_METADATA: Record<ComparisonPair, ComparisonPairMetadata> = {
101100
{ label: "Built-in tools", support: CLOUD_ONLY_SUPPORTED },
102101
{ label: "Responsive output by default", support: CLOUD_ONLY_SUPPORTED },
103102
{ label: "Automatic UI error correction", support: CLOUD_ONLY_SUPPORTED },
104-
{ label: "Self-hostable and open source", support: MARKDOWN_AND_OSS_SUPPORTED },
105103
],
106104
},
107105
"markdown-cloud": {

docs/app/compare/_components/comparison-controls.tsx

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import {
44
ArrowRight,
55
ArrowUp,
66
FileText,
7-
LayoutDashboard,
87
ListChecks,
98
Moon,
109
Plane,
@@ -27,6 +26,7 @@ const COMPARISON_SUGGESTIONS = [
2726
"Show me a chart of the top 5 US stocks outperforming the market in 2025 with key trendlines.",
2827
icon: TrendingUp,
2928
color: "#067647",
29+
hiddenForPair: "oss-cloud",
3030
},
3131
{
3232
label: "Hidden travel gems to explore",
@@ -35,13 +35,6 @@ const COMPARISON_SUGGESTIONS = [
3535
icon: Plane,
3636
color: "#dd517b",
3737
},
38-
{
39-
label: "Create an executive dashboard",
40-
prompt:
41-
"Visualize following SaaS metrics: MRR $1.28M, growth 8.4%, NRR 112%, churn 2.1%, CAC $740, and pipeline $3.6M. Highlight trends, risks, and the three actions leadership should take.",
42-
icon: LayoutDashboard,
43-
color: "#b54708",
44-
},
4538
{
4639
label: "Create an editable launch plan",
4740
prompt:
@@ -148,7 +141,9 @@ export function ComparisonControls({
148141
<div className={styles.suggestionScroller} aria-label="Try a comparison prompt">
149142
<div className={styles.suggestionRow}>
150143
{COMPARISON_SUGGESTIONS.filter(
151-
(suggestion) => !("pairOnly" in suggestion) || suggestion.pairOnly === comparisonPair,
144+
(suggestion) =>
145+
(!("pairOnly" in suggestion) || suggestion.pairOnly === comparisonPair) &&
146+
(!("hiddenForPair" in suggestion) || suggestion.hiddenForPair !== comparisonPair),
152147
).map((suggestion) => {
153148
const SuggestionIcon = suggestion.icon;
154149
const needsCloud = "cloudOnly" in suggestion && suggestion.cloudOnly;

docs/lib/openui-cloud/models.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
export const DEFAULT_MODEL = "anthropic/claude-sonnet-4.6";
1+
export const DEFAULT_MODEL = "openai/gpt-5.4";
22

33
export interface ModelOption {
44
id: string;

0 commit comments

Comments
 (0)