|
| 1 | +# /// script |
| 2 | +# requires-python = ">=3.11" |
| 3 | +# dependencies = [ |
| 4 | +# "rich", |
| 5 | +# ] |
| 6 | +# /// |
| 7 | +from rich import print |
| 8 | +import os |
| 9 | +from ollama import Client, WebCrawlResponse, WebSearchResponse |
| 10 | + |
| 11 | +def format_tool_results(results: WebSearchResponse | WebCrawlResponse): |
| 12 | + match results: |
| 13 | + case WebSearchResponse(): |
| 14 | + if not results.success: |
| 15 | + error_msg = ', '.join(results.errors) if results.errors else 'Unknown error' |
| 16 | + return f'Web search failed: {error_msg}' |
| 17 | + |
| 18 | + output = [] |
| 19 | + for query, search_results in results.results.items(): |
| 20 | + output.append(f'Search results for "{query}":') |
| 21 | + for i, result in enumerate(search_results, 1): |
| 22 | + output.append(f'{i}. {result.title}') |
| 23 | + output.append(f' URL: {result.url}') |
| 24 | + output.append(f' Content: {result.content}') |
| 25 | + output.append('') |
| 26 | + |
| 27 | + return '\n'.join(output).rstrip() |
| 28 | + |
| 29 | + case WebCrawlResponse(): |
| 30 | + if not results.success: |
| 31 | + error_msg = ', '.join(results.errors) if results.errors else 'Unknown error' |
| 32 | + return f'Web crawl failed: {error_msg}' |
| 33 | + |
| 34 | + output = [] |
| 35 | + for url, crawl_results in results.results.items(): |
| 36 | + output.append(f'Crawl results for "{url}":') |
| 37 | + for i, result in enumerate(crawl_results, 1): |
| 38 | + output.append(f'{i}. {result.title}') |
| 39 | + output.append(f' URL: {result.url}') |
| 40 | + output.append(f' Content: {result.content}') |
| 41 | + if result.links: |
| 42 | + output.append(f' Links: {", ".join(result.links)}') |
| 43 | + output.append('') |
| 44 | + |
| 45 | + return '\n'.join(output).rstrip() |
| 46 | + |
| 47 | + |
| 48 | +client = Client(headers={'Authorization': (os.getenv('OLLAMA_API_KEY'))}) |
| 49 | +available_tools = {'websearch': client.websearch, 'webcrawl': client.webcrawl} |
| 50 | + |
| 51 | +query = "ollama's new engine" |
| 52 | +print('Query: ', query) |
| 53 | + |
| 54 | +messages = [{'role': 'user', 'content': query}] |
| 55 | +while True: |
| 56 | + response = client.chat(model='qwen3', messages=messages, tools=[client.websearch, client.webcrawl], think=True) |
| 57 | + if response.message.thinking: |
| 58 | + print('Thinking: ') |
| 59 | + print(response.message.thinking + '\n\n') |
| 60 | + if response.message.content: |
| 61 | + print('Content: ') |
| 62 | + print(response.message.content + '\n') |
| 63 | + |
| 64 | + messages.append(response.message) |
| 65 | + |
| 66 | + if response.message.tool_calls: |
| 67 | + for tool_call in response.message.tool_calls: |
| 68 | + function_to_call = available_tools.get(tool_call.function.name) |
| 69 | + if function_to_call: |
| 70 | + result: WebSearchResponse | WebCrawlResponse = function_to_call(**tool_call.function.arguments) |
| 71 | + print('Result from tool call name: ', tool_call.function.name, 'with arguments: ', tool_call.function.arguments) |
| 72 | + print('Result: ', format_tool_results(result)[:200]) |
| 73 | + messages.append({'role': 'tool', 'content': format_tool_results(result), 'tool_name': tool_call.function.name}) |
| 74 | + else: |
| 75 | + print(f'Tool {tool_call.function.name} not found') |
| 76 | + messages.append({'role': 'tool', 'content': f'Tool {tool_call.function.name} not found', 'tool_name': tool_call.function.name}) |
| 77 | + else: |
| 78 | + # no more tool calls, we can stop the loop |
| 79 | + break |
| 80 | + |
0 commit comments