|
1 | 1 | // ignore_for_file: avoid_print |
2 | 2 |
|
3 | 3 | import 'dart:io'; |
4 | | -import 'dart:convert'; |
5 | | -import 'package:http/http.dart' as http; |
6 | | -import 'package:intl/intl.dart'; |
7 | 4 | import 'package:llama_cpp_dart/llama_cpp_dart.dart'; |
8 | 5 |
|
9 | | -// ========================================================== |
10 | | -// TOOLS (No changes here, they are correct) |
11 | | -// ========================================================== |
| 6 | +String prompt = """what is 2 * 4?"""; |
12 | 7 |
|
13 | | -/// Tool to get the current time. |
14 | | -String getCurrentTime() { |
15 | | - final now = DateTime.now(); |
16 | | - final formattedTime = DateFormat('HH:mm').format(now); |
17 | | - return "The current time is $formattedTime."; |
18 | | -} |
19 | | - |
20 | | -/// Tool to get the weather for a city. |
21 | | -Future<String> getWeather(String city) async { |
22 | | - try { |
23 | | - final url = Uri.parse('https://wttr.in/$city?format=%C,+%t'); |
24 | | - final response = await http.get(url); |
25 | | - if (response.statusCode == 200) { |
26 | | - final body = response.body.trim(); |
27 | | - if (body.contains(',')) { |
28 | | - return "The weather in $city is ${body.split(',')[0]} with a temperature of ${body.split(',')[1]}."; |
29 | | - } |
30 | | - return "Could not parse weather for $city. Response: $body"; |
31 | | - } else { |
32 | | - return "Sorry, I couldn't get the weather for $city."; |
33 | | - } |
34 | | - } catch (e) { |
35 | | - return "An error occurred while fetching weather: $e"; |
36 | | - } |
37 | | -} |
38 | | - |
39 | | -final Map<String, Function> toolBox = { |
40 | | - 'getCurrentTime': getCurrentTime, |
41 | | - 'getWeather': getWeather, |
42 | | -}; |
43 | | - |
44 | | -// ========================================================== |
45 | | -// PROMPT ENGINEERING |
46 | | -// ========================================================== |
47 | | - |
48 | | -String buildToolDescriptions() { |
49 | | - return """ |
50 | | -- `getCurrentTime()`: Use this tool to get the current time. It takes no arguments. |
51 | | -- `getWeather(city: string)`: Use this tool to get the weather for a specific city. |
52 | | -"""; |
53 | | -} |
54 | | - |
55 | | -String buildSystemPrompt() { |
56 | | - return """ |
57 | | -You are an expert at choosing the right function to call to answer a user's question. You have access to the following tools: |
58 | | -${buildToolDescriptions()} |
59 | | -
|
60 | | -Your goal is to respond with ONLY a JSON object that represents the function call(s) needed. |
61 | | -- The JSON should be an array of objects. |
62 | | -- Each object must have a "tool_name" and an "arguments" map. |
63 | | -- If no tool is needed, or if you don't have enough information (e.g., the user asks for weather but doesn't name a city), respond with an empty JSON array: `[]`. |
64 | | -- Do NOT add any other text, explanation, or conversation. |
65 | | -
|
66 | | -Example: |
67 | | -User: What's the weather like in Paris? |
68 | | -Your response: |
69 | | -[ |
70 | | - {"tool_name": "getWeather", "arguments": {"city": "Paris"}} |
71 | | -] |
72 | | -
|
73 | | -User: what time is it? |
74 | | -Your response: |
75 | | -[ |
76 | | - {"tool_name": "getCurrentTime", "arguments": {}} |
77 | | -] |
78 | | -
|
79 | | -User: Tell me a joke. |
80 | | -Your response: |
81 | | -[] |
82 | | -"""; |
83 | | -} |
84 | | - |
85 | | -// ========================================================== |
86 | | -// MAIN AGENT LOGIC (This is where the fix is) |
87 | | -// ========================================================== |
88 | | - |
89 | | -Future<void> main() async { |
| 8 | +void main() async { |
90 | 9 | try { |
91 | | - // --- Standard LLM Setup (using your working example's structure) --- |
92 | 10 | Llama.libraryPath = "bin/MAC_ARM64/libllama.dylib"; |
93 | 11 | String modelPath = "/Users/adel/Workspace/gguf/gemma-3-4b-it-q4_0.gguf"; |
94 | 12 |
|
95 | | - final modelParams = ModelParams()..nGpuLayers = -1; |
96 | | - final contextParams = ContextParams()..nCtx = 2048; |
97 | | - final samplerParams = SamplerParams(); |
98 | | - |
99 | | - final llama = |
100 | | - Llama(modelPath, modelParams, contextParams, samplerParams, false); |
101 | | - |
102 | | - // --- The Agent's Main Loop --- |
103 | | - while (true) { |
104 | | - stdout.write("\nAsk me something (or type 'exit'): "); |
105 | | - final userInput = stdin.readLineSync(); |
106 | | - |
107 | | - if (userInput == null || userInput.toLowerCase() == 'exit') { |
108 | | - break; |
109 | | - } |
| 13 | + ChatHistory history = ChatHistory() |
| 14 | + ..addMessage(role: Role.user, content: prompt) |
| 15 | + ..addMessage(role: Role.assistant, content: ""); |
110 | 16 |
|
111 | | - print("🧠 Thinking..."); |
| 17 | + final modelParams = ModelParams()..nGpuLayers = 99; |
112 | 18 |
|
113 | | - // 1. Build the prompt using ChatHistory (THE CORRECT WAY) |
114 | | - final history = ChatHistory() |
115 | | - ..addMessage(role: Role.user, content: buildSystemPrompt()) |
116 | | - ..addMessage(role: Role.user, content: userInput) |
117 | | - ..addMessage(role: Role.assistant, content: ''); |
| 19 | + final contextParams = ContextParams() |
| 20 | + ..nPredict = -1 |
| 21 | + ..nCtx = 8192 |
| 22 | + ..nBatch = 8192; |
118 | 23 |
|
119 | | - // 2. Set the prompt and get the response by streaming tokens (THE CORRECT WAY) |
120 | | - llama.setPrompt(history.exportFormat(ChatFormat.gemini, |
121 | | - leaveLastAssistantOpen: true)); |
| 24 | + final samplerParams = SamplerParams() |
| 25 | + ..temp = 0.7 |
| 26 | + ..topK = 64 |
| 27 | + ..topP = 0.95 |
| 28 | + ..penaltyRepeat = 1.1; |
122 | 29 |
|
123 | | - final responseBuffer = StringBuffer(); |
124 | | - while (true) { |
125 | | - final (token, done) = llama.getNext(); |
126 | | - responseBuffer.write(token); |
127 | | - if (done) break; |
128 | | - } |
129 | | - final llmResponse = responseBuffer.toString().trim(); |
130 | | - |
131 | | - print("✅ LLM's Plan (raw response): $llmResponse"); |
132 | | - |
133 | | - // 3. The "Coordinator" (our code) reads the plan and executes it. |
134 | | - try { |
135 | | - final jsonRegex = RegExp(r'\[.*\]', dotAll: true); |
136 | | - final match = jsonRegex.firstMatch(llmResponse); |
137 | | - |
138 | | - if (match == null) { |
139 | | - print( |
140 | | - "🤖 I couldn't decide on a tool to use. Here's my raw thought: $llmResponse"); |
141 | | - continue; |
142 | | - } |
143 | | - |
144 | | - final jsonString = match.group(0)!; |
145 | | - final List<dynamic> toolCalls = jsonDecode(jsonString); |
146 | | - |
147 | | - if (toolCalls.isEmpty) { |
148 | | - print( |
149 | | - "🤖 I don't have a tool for that. Please ask me about the time or weather."); |
150 | | - continue; |
151 | | - } |
152 | | - |
153 | | - // 4. Execute each tool in the plan |
154 | | - for (var call in toolCalls) { |
155 | | - final toolName = call['tool_name']; |
156 | | - final arguments = call['arguments'] as Map<String, dynamic>; |
157 | | - final tool = toolBox[toolName]; |
| 30 | + Llama llama = |
| 31 | + Llama(modelPath, modelParams, contextParams, samplerParams, false); |
158 | 32 |
|
159 | | - if (tool != null) { |
160 | | - print("🛠️ Executing tool: $toolName with args: $arguments"); |
161 | | - if (toolName == 'getWeather') { |
162 | | - final result = await getWeather(arguments['city']); |
163 | | - print("✔️ Result: $result"); |
164 | | - } else if (toolName == 'getCurrentTime') { |
165 | | - final result = getCurrentTime(); |
166 | | - print("✔️ Result: $result"); |
167 | | - } |
168 | | - } else { |
169 | | - print("❌ Error: Tool '$toolName' not found in my toolbox."); |
170 | | - } |
171 | | - } |
172 | | - } catch (e) { |
173 | | - print("❌ Error processing the LLM's plan: $e"); |
174 | | - print(" My plan was: $llmResponse"); |
175 | | - } |
| 33 | + llama.setPrompt( |
| 34 | + history.exportFormat(ChatFormat.gemini, leaveLastAssistantOpen: true)); |
| 35 | + while (true) { |
| 36 | + var (token, done) = llama.getNext(); |
| 37 | + stdout.write(token); |
| 38 | + if (done) break; |
176 | 39 | } |
| 40 | + stdout.write("\n"); |
177 | 41 |
|
178 | 42 | llama.dispose(); |
179 | | - print("Goodbye!"); |
180 | 43 | } catch (e) { |
181 | | - print("\nFatal Error: ${e.toString()}"); |
| 44 | + print("\nError: ${e.toString()}"); |
182 | 45 | } |
183 | 46 | } |
0 commit comments