|
@@ -1,5 +1,4 @@
|
|
|
-import ollama, { Ollama } from 'ollama'
|
|
|
-import type { Message } from 'ollama'
|
|
|
+import { Ollama, type Message, type SearchResponse, type FetchResponse } from 'ollama'
|
|
|
|
|
|
async function main() {
|
|
|
|
|
@@ -14,52 +13,46 @@ async function main() {
|
|
|
type: 'function',
|
|
|
function: {
|
|
|
name: 'webSearch',
|
|
|
- description: 'Performs a web search for the given queries.',
|
|
|
+ description: 'Performs a web search for the given query.',
|
|
|
parameters: {
|
|
|
type: 'object',
|
|
|
properties: {
|
|
|
- queries: {
|
|
|
- type: 'array',
|
|
|
- items: { type: 'string' },
|
|
|
- description: 'An array of search queries.',
|
|
|
- },
|
|
|
+ query: { type: 'string', description: 'Search query string.' },
|
|
|
max_results: {
|
|
|
type: 'number',
|
|
|
description: 'The maximum number of results to return per query (default 5, max 10).',
|
|
|
},
|
|
|
},
|
|
|
- required: ['queries'],
|
|
|
+ required: ['query'],
|
|
|
},
|
|
|
},
|
|
|
}
|
|
|
|
|
|
- const webCrawlTool = {
|
|
|
+ const webFetchTool = {
|
|
|
type: 'function',
|
|
|
function: {
|
|
|
- name: 'webCrawl',
|
|
|
- description: 'Performs a web crawl for the given URLs.',
|
|
|
+ name: 'webFetch',
|
|
|
+ description: 'Fetches a single page by URL.',
|
|
|
parameters: {
|
|
|
type: 'object',
|
|
|
properties: {
|
|
|
- urls: {
|
|
|
- type: 'array',
|
|
|
- items: { type: 'string' },
|
|
|
- description: 'An array of URLs to crawl.',
|
|
|
- },
|
|
|
+ url: { type: 'string', description: 'A single URL to fetch.' },
|
|
|
},
|
|
|
- required: ['urls'],
|
|
|
+ required: ['url'],
|
|
|
},
|
|
|
},
|
|
|
}
|
|
|
|
|
|
- const availableTools = {
|
|
|
- webSearch: async (args: { queries: string[]; max_results?: number }) => {
|
|
|
- return await client.webSearch(args)
|
|
|
- },
|
|
|
- webCrawl: async (args: { urls: string[] }) => {
|
|
|
- return await client.webCrawl(args)
|
|
|
- },
|
|
|
- }
|
|
|
+ const availableTools = {
|
|
|
+ webSearch: async (args: { query: string; max_results?: number }): Promise<SearchResponse> => {
|
|
|
+ const res = await client.webSearch(args)
|
|
|
+ return res as SearchResponse
|
|
|
+ },
|
|
|
+ webFetch: async (args: { url: string }): Promise<FetchResponse> => {
|
|
|
+ const res = await client.webFetch(args)
|
|
|
+ return res as FetchResponse
|
|
|
+ },
|
|
|
+ }
|
|
|
|
|
|
const messages: Message[] = [
|
|
|
{
|
|
@@ -69,33 +62,23 @@ async function main() {
|
|
|
]
|
|
|
|
|
|
console.log('----- Prompt:', messages.find((m) => m.role === 'user')?.content, '\n')
|
|
|
-
|
|
|
+
|
|
|
while (true) {
|
|
|
- const response = await client.chat({
|
|
|
- model: 'gpt-oss',
|
|
|
+ const response = await client.chat({
|
|
|
+ model: 'qwen3',
|
|
|
messages: messages,
|
|
|
- tools: [webSearchTool, webCrawlTool],
|
|
|
+ tools: [webSearchTool, webFetchTool],
|
|
|
stream: true,
|
|
|
think: true,
|
|
|
})
|
|
|
|
|
|
let hadToolCalls = false
|
|
|
- let startedThinking = false
|
|
|
- let finishedThinking = false
|
|
|
var content = ''
|
|
|
var thinking = ''
|
|
|
for await (const chunk of response) {
|
|
|
- if (chunk.message.thinking && !startedThinking) {
|
|
|
- startedThinking = true
|
|
|
- process.stdout.write('Thinking:\n========\n\n')
|
|
|
- } else if (chunk.message.content && startedThinking && !finishedThinking) {
|
|
|
- finishedThinking = true
|
|
|
- process.stdout.write('\n\nResponse:\n========\n\n')
|
|
|
- }
|
|
|
|
|
|
if (chunk.message.thinking) {
|
|
|
thinking += chunk.message.thinking
|
|
|
- process.stdout.write(chunk.message.thinking)
|
|
|
}
|
|
|
if (chunk.message.content) {
|
|
|
content += chunk.message.content
|
|
@@ -116,7 +99,7 @@ async function main() {
|
|
|
const args = toolCall.function.arguments as any
|
|
|
console.log('\nCalling function:', toolCall.function.name, 'with arguments:', args)
|
|
|
const output = await functionToCall(args)
|
|
|
- console.log('Function output:', JSON.stringify(output).slice(0, 200), '\n')
|
|
|
+ console.log('Function result:', JSON.stringify(output).slice(0, 200), '\n')
|
|
|
|
|
|
messages.push(chunk.message)
|
|
|
messages.push({
|
|
@@ -134,7 +117,7 @@ async function main() {
|
|
|
break
|
|
|
}
|
|
|
|
|
|
- console.log('----- Sending result back to model \n')
|
|
|
+
|
|
|
}
|
|
|
}
|
|
|
|