Przeglądaj źródła

types: add tool_name to message (#229)

Parth Sareen 2 tygodni temu
rodzic
commit
45d2e0197e
3 zmienionych plików z 144 dodań i 0 usunięć
  1. 1 0
      README.md
  2. 142 0
      examples/tools/multi-tool.ts
  3. 1 0
      src/interfaces.ts

+ 1 - 0
README.md

@@ -63,6 +63,7 @@ ollama.chat(request)
     - `role` `<string>`: The role of the message sender ('user', 'system', or 'assistant').
     - `content` `<string>`: The content of the message.
     - `images` `<Uint8Array[] | string[]>`: (Optional) Images to be included in the message, either as Uint8Array or base64 encoded strings.
+    - `tool_name` `<string>`: (Optional) Add the name of the tool that was executed to inform the model of the result 
   - `format` `<string>`: (Optional) Set the expected format of the response (`json`).
   - `stream` `<boolean>`: (Optional) When true an `AsyncGenerator` is returned.
   - `think` `<boolean>`: (Optional) When true, the model will think about the response before responding. Requires thinking support from the model.

+ 142 - 0
examples/tools/multi-tool.ts

@@ -0,0 +1,142 @@
+import ollama from 'ollama';
+
+// Mock weather functions
+function getTemperature(args: { city: string }): string {
+    const validCities = ['London', 'Paris', 'New York', 'Tokyo', 'Sydney'];
+
+    if (!validCities.includes(args.city)) {
+        return 'Unknown city';
+    }
+
+    return `${Math.floor(Math.random() * 36)} degrees Celsius`;
+}
+
+function getConditions(args: { city: string }): string {
+    const validCities = ['London', 'Paris', 'New York', 'Tokyo', 'Sydney'];
+
+    if (!validCities.includes(args.city)) {
+        return 'Unknown city';
+    }
+
+    const conditions = ['sunny', 'cloudy', 'rainy', 'snowy'];
+    return conditions[Math.floor(Math.random() * conditions.length)];
+}
+
+// Tool definitions
+const getTemperatureTool = {
+    type: 'function',
+    function: {
+        name: 'getTemperature',
+        description: 'Get the temperature for a city in Celsius',
+        parameters: {
+            type: 'object',
+            required: ['city'],
+            properties: {
+                city: { type: 'string', description: 'The name of the city' }
+            }
+        }
+    }
+};
+
+const getConditionsTool = {
+    type: 'function',
+    function: {
+        name: 'getConditions',
+        description: 'Get the weather conditions for a city',
+        parameters: {
+            type: 'object',
+            required: ['city'],
+            properties: {
+                city: { type: 'string', description: 'The name of the city' }
+            }
+        }
+    }
+};
+
+async function run(model: string) {
+    const cities = ['London', 'Paris', 'New York', 'Tokyo', 'Sydney'];
+    const city = cities[Math.floor(Math.random() * cities.length)];
+    const city2 = cities[Math.floor(Math.random() * cities.length)];
+
+    const messages = [{
+        role: 'user',
+        content: `What is the temperature in ${city}? and what are the weather conditions in ${city2}?`
+    }];
+    console.log('----- Prompt:', messages[0].content, '\n');
+
+    const ollama = new Ollama();
+    const availableFunctions = {
+        getTemperature,
+        getConditions
+    };
+
+    const response = await ollama.chat({
+        model: model,
+        messages: messages,
+        tools: [getTemperatureTool, getConditionsTool],
+        stream: true,
+        think: true
+    });
+
+    for await (const chunk of response) {
+        if (chunk.message.thinking) {
+            process.stdout.write(chunk.message.thinking);
+        }
+        if (chunk.message.content) {
+            process.stdout.write(chunk.message.content);
+        }
+        if (chunk.message.tool_calls) {
+            for (const tool of chunk.message.tool_calls) {
+                const functionToCall = availableFunctions[tool.function.name];
+                if (functionToCall) {
+                    console.log('\nCalling function:', tool.function.name, 'with arguments:', tool.function.arguments);
+                    const output = functionToCall(tool.function.arguments);
+                    console.log('> Function output:', output, '\n');
+
+                    messages.push(chunk.message);
+                    messages.push({
+                        role: 'tool',
+                        content: output.toString(),
+                        tool_name: tool.function.name,
+                    });
+                } else {
+                    console.log('Function', tool.function.name, 'not found');
+                }
+            }
+        }
+    }
+
+    console.log('----- Sending result back to model \n');
+
+    if (messages.some(msg => msg.role === 'tool')) {
+        const finalResponse = await ollama.chat({
+            model: model,
+            messages: messages,
+            tools: [getTemperatureTool, getConditionsTool],
+            stream: true,
+            think: true
+        });
+
+        let doneThinking = false;
+        for await (const chunk of finalResponse) {
+            if (chunk.message.thinking) {
+                process.stdout.write(chunk.message.thinking);
+            }
+            if (chunk.message.content) {
+                if (!doneThinking) {
+                    console.log('\n----- Final result:');
+                    doneThinking = true;
+                }
+                process.stdout.write(chunk.message.content);
+            }
+            if (chunk.message.tool_calls) {
+                console.log('Model returned tool calls:');
+                console.log(chunk.message.tool_calls);
+            }
+        }
+    } else {
+        console.log('No tool calls returned');
+    }
+}
+
+run('qwen3').catch(console.error);

+ 1 - 0
src/interfaces.ts

@@ -67,6 +67,7 @@ export interface Message {
   thinking?: string
   images?: Uint8Array[] | string[]
   tool_calls?: ToolCall[]
+  tool_name?: string
 }
 
 export interface ToolCall {