Skip to content

Commit a003363

Browse files
authored
feat: tool calls. (#281)
1 parent 8d624a7 commit a003363

File tree

5 files changed

+520
-63
lines changed

5 files changed

+520
-63
lines changed

examples/chat-api-client.js

Lines changed: 112 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import util from 'node:util';
2+
13
// This is a simple client for dllama-api.
24
//
35
// Usage:
@@ -7,27 +9,43 @@
79

810
const HOST = process.env.HOST ? process.env.HOST : '127.0.0.1';
911
const PORT = process.env.PORT ? Number(process.env.PORT) : 9990;
12+
const DEBUG = ['1', 'true'].includes(process.env.DEBUG);
13+
14+
function debug(name, content) {
15+
if (DEBUG) {
16+
console.log(name, util.inspect(content, {
17+
colors: true,
18+
depth: null,
19+
compact: false,
20+
}));
21+
}
22+
}
1023

11-
async function chat(messages, maxTokens) {
24+
async function complete(messages, maxTokens, extra = {}) {
25+
const body = {
26+
messages,
27+
temperature: 0.7,
28+
stop: ['<|eot_id|>'],
29+
max_tokens: maxTokens,
30+
...extra
31+
};
32+
debug('🔵 Request', body);
1233
const response = await fetch(`http://${HOST}:${PORT}/v1/chat/completions`, {
1334
method: 'POST',
1435
headers: {
1536
'Content-Type': 'application/json',
1637
},
17-
body: JSON.stringify({
18-
messages,
19-
temperature: 0.7,
20-
stop: ['<|eot_id|>'],
21-
max_tokens: maxTokens
22-
}),
38+
body: JSON.stringify(body),
2339
});
24-
return await response.json();
40+
const json = await response.json();
41+
debug('🔴 Response', json);
42+
return json;
2543
}
2644

2745
async function ask(system, user, maxTokens) {
2846
console.log(`> system: ${system}`);
2947
console.log(`> user: ${user}`);
30-
const response = await chat([
48+
const response = await complete([
3149
{
3250
role: 'system',
3351
content: system
@@ -41,9 +59,92 @@ async function ask(system, user, maxTokens) {
4159
console.log(response.choices[0].message.content);
4260
}
4361

62+
async function askWithTools(companyName, maxTokens) {
63+
const tools = [
64+
{
65+
type: 'function',
66+
function: {
67+
name: 'get_most_popular_car_by_company',
68+
description: 'Return the most popular car model for a given company name.',
69+
parameters: {
70+
type: 'object',
71+
properties: {
72+
companyName: {
73+
type: 'string',
74+
description: 'Car company name, e.g., `Toyota`, `Ford`'
75+
}
76+
},
77+
required: ['companyName']
78+
}
79+
}
80+
},
81+
{
82+
type: 'function',
83+
function: {
84+
name: 'get_car_sales_this_year',
85+
description: 'Return total sales for the given car company for the current calendar year.',
86+
parameters: {
87+
type: 'object',
88+
properties: {
89+
companyNameAndCarName: {
90+
type: 'string',
91+
description: 'Car company name and car name concatenated, e.g., `Toyota - Corolla`'
92+
}
93+
},
94+
required: ['companyNameAndCarName']
95+
}
96+
}
97+
}];
98+
99+
const messages = [
100+
{ role: 'system', content: 'You can use only 1 tool at the time.' },
101+
{ role: 'user', content: `Tell me about the most popular car from ${companyName} and its sales this year.` }
102+
];
103+
104+
console.log(`> user: ${messages[1].content}`);
105+
106+
let response;
107+
for (let i = 0; ; i++) {
108+
response = await complete(messages, maxTokens, { tools, tool_choice: 'auto' });
109+
const choice = response.choices[0];
110+
111+
if (choice.finish_reason !== 'tool_calls' || !choice.message.tool_calls?.length) {
112+
break;
113+
}
114+
messages.push(choice.message);
115+
for (const call of choice.message.tool_calls) {
116+
switch (call.function.name) {
117+
case 'get_most_popular_car_by_company':
118+
messages.push({
119+
role: 'tool',
120+
tool_call_id: call.id,
121+
content: JSON.stringify({
122+
carName: 'Corolla'
123+
})
124+
});
125+
break;
126+
case 'get_car_sales_this_year':
127+
messages.push({
128+
role: 'tool',
129+
tool_call_id: call.id,
130+
content: JSON.stringify({
131+
salesThisYear: 250000
132+
})
133+
});
134+
break;
135+
default:
136+
throw new Error(`Unsupported tool: ${call.function.name}`);
137+
}
138+
}
139+
}
140+
141+
console.log(response.choices[0].message.content);
142+
}
143+
44144
async function main() {
45-
await ask('You are an excellent math teacher.', 'What is 1 + 2?', 128);
46-
await ask('You are a romantic.', 'Where is Europe?', 128);
145+
await ask('You are an excellent math teacher.', 'What is 1 + 2?', 256);
146+
await ask('You are a romantic.', 'Where is Europe?', 256);
147+
await askWithTools('Toyota', 5000);
47148
}
48149

49150
main();

0 commit comments

Comments
 (0)