Spaces:
Runtime error
Runtime error
Đào Minh Tú
fix(tools+models): repair UTF-8 mojibake in tool descriptions; trim model list to verified-working set; filter non-chat models from Google live discovery
671888a | // Smoke test: kiểm tra mỗi model có gọi được generateContent + tool call không. | |
| // Run: node scripts/test-models-tools.mjs | |
| import "dotenv/config" | |
| import fs from "node:fs" | |
| import path from "node:path" | |
| // Minimal .env.local loader (dotenv/config above might miss .env.local) | |
| const envFile = path.join(process.cwd(), ".env.local") | |
| if (fs.existsSync(envFile)) { | |
| for (const line of fs.readFileSync(envFile, "utf8").split(/\r?\n/)) { | |
| const m = line.match(/^([A-Z_]+)=(.*)$/) | |
| if (m && !process.env[m[1]]) process.env[m[1]] = m[2].replace(/^"(.*)"$/, "$1") | |
| } | |
| } | |
| import { generateText, tool } from "ai" | |
| import { createGoogleGenerativeAI } from "@ai-sdk/google" | |
| import { createGroq } from "@ai-sdk/groq" | |
| import { createOpenAI } from "@ai-sdk/openai" | |
| import { z } from "zod" | |
| const calculator = tool({ | |
| description: "Evaluate a math expression like '12 * 34'.", | |
| parameters: z.object({ expression: z.string() }), | |
| execute: async ({ expression }) => ({ result: eval(expression) }), | |
| }) | |
| const currentTime = tool({ | |
| description: "Get current ISO time. Use when asked about time/date.", | |
| parameters: z.object({}), | |
| execute: async () => ({ now: new Date().toISOString() }), | |
| }) | |
| const tools = { calculator, currentTime } | |
| const MODELS = [ | |
| ["google", "gemini-2.5-flash-lite"], | |
| ["google", "gemini-2.5-flash"], | |
| ["google", "gemini-2.5-pro"], | |
| ["google", "gemini-2.0-flash"], | |
| ["google", "gemini-2.0-flash-lite"], | |
| ["google", "gemini-flash-latest"], | |
| ["google", "gemini-flash-lite-latest"], | |
| ["google", "gemma-4-26b-a4b-it"], | |
| ["google", "gemma-4-31b-it"], | |
| ["groq", "llama-3.3-70b-versatile"], | |
| ["groq", "llama-3.1-8b-instant"], | |
| ["groq", "openai/gpt-oss-120b"], | |
| ["groq", "openai/gpt-oss-20b"], | |
| ["groq", "qwen/qwen3-32b"], | |
| ["groq", "meta-llama/llama-4-scout-17b-16e-instruct"], | |
| ["github", "gpt-4o-mini"], | |
| ["github", "gpt-4o"], | |
| ] | |
| function getModel(provider, modelId) { | |
| if (provider === "google") return createGoogleGenerativeAI({ apiKey: process.env.GOOGLE_GENERATIVE_AI_API_KEY })(modelId) | |
| if (provider === "groq") return createGroq({ apiKey: process.env.GROQ_API_KEY })(modelId) | |
| if (provider === "github") return createOpenAI({ apiKey: process.env.GITHUB_TOKEN, baseURL: "https://models.inference.ai.azure.com" })(modelId) | |
| } | |
| const results = [] | |
| for (const [provider, modelId] of MODELS) { | |
| const row = { provider, modelId, basic: "", toolCall: "" } | |
| // Basic | |
| try { | |
| const r = await generateText({ | |
| model: getModel(provider, modelId), | |
| prompt: "Trả lời ngắn: 2+2=?", | |
| maxTokens: 50, | |
| }) | |
| row.basic = r.text ? "OK: " + r.text.slice(0, 40).replace(/\n/g, " ") : "EMPTY" | |
| } catch (e) { | |
| row.basic = "FAIL: " + (e.message || String(e)).slice(0, 100) | |
| } | |
| // Tool call | |
| try { | |
| const r = await generateText({ | |
| model: getModel(provider, modelId), | |
| tools, | |
| maxSteps: 3, | |
| prompt: "Tính 17 * 23 bằng tool calculator, rồi trả về kết quả.", | |
| maxTokens: 200, | |
| }) | |
| const used = (r.toolCalls?.length ?? 0) + (r.steps?.flatMap((s) => s.toolCalls || []).length ?? 0) | |
| row.toolCall = used > 0 ? `OK (${used} call): ${r.text?.slice(0, 40)}` : `NO_TOOL: ${r.text?.slice(0, 40)}` | |
| } catch (e) { | |
| row.toolCall = "FAIL: " + (e.message || String(e)).slice(0, 100) | |
| } | |
| console.log(`[${provider}] ${modelId}`) | |
| console.log(` basic: ${row.basic}`) | |
| console.log(` tool : ${row.toolCall}`) | |
| results.push(row) | |
| await new Promise((r) => setTimeout(r, 500)) | |
| } | |
| console.log("\n\n=== SUMMARY ===") | |
| console.log("provider\tmodel\tbasic\ttool") | |
| for (const r of results) { | |
| const b = r.basic.startsWith("OK") ? "✓" : "✗" | |
| const t = r.toolCall.startsWith("OK") ? "✓" : r.toolCall.startsWith("NO_TOOL") ? "—" : "✗" | |
| console.log(`${r.provider}\t${r.modelId}\t${b}\t${t}`) | |
| } | |