diff --git a/packages/kbot/README.md b/packages/kbot/README.md deleted file mode 100644 index 66f229c8..00000000 --- a/packages/kbot/README.md +++ /dev/null @@ -1,213 +0,0 @@ -# @plastichub/kbot - -AI-powered command-line tool for code modifications and project management that supports multiple AI models and routers. - -## Overview - -Code-bot is a powerful CLI tool that helps developers automate code modifications, handle project management tasks, and integrate with various AI models for intelligent code and content assistance. - -## Quick Start - -### Installation Steps - -KBot requires Node.js to run. It's recommended to use Node.js version 18 or higher. - -1. Visit the official [Node.js website](https://nodejs.org/) -2. Download the LTS (Long Term Support) version for your operating system -3. Follow the installation wizard -4. Verify installation by opening a terminal and running: - ```bash - node --version - npm --version - ``` - -### API Keys - -KBot supports both OpenRouter and OpenAI APIs. You'll need at least one of these set up. - -#### OpenRouter API (Recommended) - -1. Visit [OpenRouter](https://openrouter.ai/) -2. Sign up for an account -3. Navigate to the API Keys section -4. Create a new API key - -#### OpenAI API (Optional) - -1. Go to [OpenAI's platform](https://platform.openai.com/) -2. Create an account or sign in -3. Navigate to API keys section -4. Create a new secret key - -### Installation using Node NPM package manager - -```bash -npm install -g @plastichub/kbot -``` - -## Configuration - -### API Keys Setup - -Create configuration at `$HOME/.osr/.config.json` (or export OSR_CONFIG with path to config.json): - -```json -{ - "openrouter": { - "key": "your-openrouter-key" - }, - "openai": { - "key": "your-openai-key" - }, - "email": { - "newsletter": { - "host": "host.org", - "port": 465, - "debug": true, - "transactionLog": true, - "auth": { - "user": "foo@bar.com", - "pass": "pass" - } - } - }, - "google": { - "cse": "custom search engine id", - "api_key": "google custom search api key" - }, - "serpapi": { - "key": "your SerpAPI key (optional, used for web searches(places, google maps))" - }, - "deepseek": { - "key": "your SerpAPI key (optional, used for web searches(places, google maps))" - }, -} -``` - -### Preferences Setup - -Optionally, create `.kbot/preferences.md` in your project directory to customize AI interactions: - -```markdown -## My Preferences - -Gender : male -Location : New York, USA (eg: `send me all saunas next to me`) -Language : English -Occupation : software developer, Typescript -Age : 30+ - -## Contacts - -My email address : example@email.com (eg: `send me latest hacker news`) -My wife's email address ("Anne") : example@email.com (eg: `send email to my wife, with latest local news') - -## Content - -When creating content -- always Markdown -- always add links -- when sending emails, always add 'Best regards, [Your Name]' -``` -## Commands - -### Prompt - -```kbot "create Astro minimal boilerplate, use starlight theme. Install dependencies via NPM tool"``` - -### Fetch latest models - -```kbot fetch``` - -### Print examples - -```kbot examples``` - -### Print extended help - -```kbot help-md``` - -### Initialize folder - -```kbot init``` - -### Internal : Build - -```kbot build``` - -# Command Line Parameters - -This document describes all available command line parameters. - -## Core Parameters - -| Parameter | Description | Default | Required | -|-----------|-------------|---------|----------| -| `path` | Target directory | `.` | No | -| `prompt` | The prompt. Supports file paths and environment variables | `./prompt.md` | No | -| `output` | Optional output path for modified files (Tool mode only) | - | No | -| `dst` | Optional destination path for the result, will substitute ${MODEL} and ${ROUTER} in the path. | - | No | -| `model` | AI model to use for processing | `anthropic/claude-3.5-sonnet` | No | -| `router` | Router to use: openai or openrouter | `openrouter` | No | -| `mode` | Chat completion mode: "completion" (without tools) or "tools" | `tools` | No | - -## Advanced Parameters - -| Parameter | Description | Default | Required | -|-----------|-------------|---------|----------| -| `each` | Target directory | `.` | No | -| `dry` | Dry run - only write out parameters without making API calls | `false` | No | - -## File Selection & Tools - -| Parameter | Description | Default | Required | -|-----------|-------------|---------|----------| -| `include` | Glob patterns to match files for processing. Supports multiple patterns, e.g. `--include=src/*.tsx,src/*.ts --include=package.json` | - | No | -| `disable` | Disable tools categories | `[]` | No | -| `disableTools` | List of specific tools to disable | `[]` | No | - -## Configuration & Profiles - -| Parameter | Description | Default | Required | -|-----------|-------------|---------|----------| -| `profile` | Path to profile for variables. Supports environment variables | `${POLYMECH-ROOT}/profile.json` | No | -| `env` | Environment (in profile) | `default` | No | -| `config` | Path to JSON configuration file (API keys). Supports environment variables | - | No | -| `preferences` | Path to preferences file (location, email, gender, etc). Supports environment variables | `./.kbot/preferences.md` | No | - -## Debugging & Logging - -| Parameter | Description | Default | Required | -|-----------|-------------|---------|----------| -| `logLevel` | Logging level for the application (0-4) | `2` | No | -| `logs` | Logging directory | `./.kbot` | No | -| `dump` | Create a script | - | No | - - -# Working on Larger Directories - -Since LLMs (Large Language Models) and providers are limited to very small 'context windows', it's necessary to feed them with smaller chunks instead. This document explains how to process larger directories efficiently. - -## Directory Processing Example - -Here's an example of how to walk through files and process them: - -```bash -osr-cli each --main='kbot \"read ${KEY} and translate to german, save in docs/language code/filename.md\" --include=\"${REL}\" --include=\".kbot/preferences.md\"' --list="./docs/*.md" --cwd=. -``` - -### Parameter Explanation - -- `each`: Command to process multiple files iteratively -- `--main`: The main command (`kbot`) to execute for each file - - `--include=\"${REL}\"` instructs kbot to include the current selected path - - `--include=\".kbot/preferences.md\"` instructs kbot to include additional preferences about the task (eg: translation specifics) -- `--list`: Specifies the file pattern to match - - Supports include patterns (e.g., `"./docs/*.md"`) -- `--cwd`: Sets the current working directory for the command execution. Default is the current directory (`.`) - -**Note** requires `@plastichub/osr-cli-commons` to be installed globally: - -```bash -npm i -g @plastichub/osr-cli-commons -``` \ No newline at end of file diff --git a/packages/kbot/dist-in/commands/run-assistant.js b/packages/kbot/dist-in/commands/run-assistant.js index f986e570..9863605d 100644 --- a/packages/kbot/dist-in/commands/run-assistant.js +++ b/packages/kbot/dist-in/commands/run-assistant.js @@ -129,9 +129,9 @@ export const runAssistant = async (client, params, options) => { model: params.model, tools: [{ type: "file_search" }, ...params.tools], }); - let files = glob(path.resolve(options.path), options.include) || []; - files = files.filter((f) => path.extname(f) in supported); - const attachments = await Promise.all(files.map(async (file) => { + const { files } = glob(path.resolve(options.path), options.include) || { files: [], webUrls: new Set() }; + const filesToProcess = files.filter((f) => path.extname(f) in supported); + const attachments = await Promise.all(filesToProcess.map(async (file) => { const file_id = await createOpenAIFile(client, file); return { file_id: file_id.id, @@ -170,4 +170,4 @@ export const runAssistant = async (client, params, options) => { const ret = await defer; return await onCompletion(ret.text.value, options); }; -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicnVuLWFzc2lzdGFudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9jb21tYW5kcy9ydW4tYXNzaXN0YW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxJQUFJLE1BQU0sV0FBVyxDQUFBO0FBQ2pDLE9BQU8sS0FBSyxFQUFFLE1BQU0sU0FBUyxDQUFBO0FBTTdCLE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxhQUFhLENBQUE7QUFDcEMsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLHFCQUFxQixDQUFBO0FBQ2xELE9BQU8sRUFBRSxJQUFJLEVBQUUsTUFBTSxjQUFjLENBQUE7QUFDbkMsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLGNBQWMsQ0FBQTtBQUVyQyxNQUFNLENBQUMsTUFBTSxTQUFTLEdBQTJCO0lBQy9DLElBQUksRUFBRSxVQUFVO0lBQ2hCLE1BQU0sRUFBRSxZQUFZO0lBQ3BCLEtBQUssRUFBRSxlQUFlO0lBQ3RCLE1BQU0sRUFBRSxVQUFVO0lBQ2xCLE1BQU0sRUFBRSxvQkFBb0I7SUFDNUIsT0FBTyxFQUFFLHlFQUF5RTtJQUNsRixLQUFLLEVBQUUsZUFBZTtJQUN0QixPQUFPLEVBQUUsV0FBVztJQUNwQixPQUFPLEVBQUUsYUFBYTtJQUN0QixLQUFLLEVBQUUsaUJBQWlCO0lBQ3hCLE9BQU8sRUFBRSxrQkFBa0I7SUFDM0IsS0FBSyxFQUFFLGVBQWU7SUFDdEIsTUFBTSxFQUFFLGlCQUFpQjtJQUN6QixNQUFNLEVBQUUsWUFBWTtJQUNwQixPQUFPLEVBQUUsMkVBQTJFO0lBQ3BGLEtBQUssRUFBRSxlQUFlLEVBQVUsaUNBQWlDO0lBQ2pFLEtBQUssRUFBRSxhQUFhO0lBQ3BCLEtBQUssRUFBRSxrQkFBa0I7SUFDekIsTUFBTSxFQUFFLFlBQVk7SUFDcEIsS0FBSyxFQUFFLHdCQUF3QjtJQUMvQixNQUFNLEVBQUUsWUFBWTtDQUNyQixDQUFDO0FBRUYsTUFBTSxDQUFDLE1BQU0sZ0JB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 \ No newline at end of file +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicnVuLWFzc2lzdGFudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9jb21tYW5kcy9ydW4tYXNzaXN0YW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxJQUFJLE1BQU0sV0FBVyxDQUFBO0FBQ2pDLE9BQU8sS0FBSyxFQUFFLE1BQU0sU0FBUyxDQUFBO0FBTTdCLE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxhQUFhLENBQUE7QUFDcEMsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLHFCQUFxQixDQUFBO0FBQ2xELE9BQU8sRUFBRSxJQUFJLEVBQUUsTUFBTSxjQUFjLENBQUE7QUFDbkMsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLGNBQWMsQ0FBQTtBQUVyQyxNQUFNLENBQUMsTUFBTSxTQUFTLEdBQTJCO0lBQy9DLElBQUksRUFBRSxVQUFVO0lBQ2hCLE1BQU0sRUFBRSxZQUFZO0lBQ3BCLEtBQUssRUFBRSxlQUFlO0lBQ3RCLE1BQU0sRUFBRSxVQUFVO0lBQ2xCLE1BQU0sRUFBRSxvQkFBb0I7SUFDNUIsT0FBTyxFQUFFLHlFQUF5RTtJQUNsRixLQUFLLEVBQUUsZUFBZTtJQUN0QixPQUFPLEVBQUUsV0FBVztJQUNwQixPQUFPLEVBQUUsYUFBYTtJQUN0QixLQUFLLEVBQUUsaUJBQWlCO0lBQ3hCLE9BQU8sRUFBRSxrQkFBa0I7SUFDM0IsS0FBSyxFQUFFLGVBQWU7SUFDdEIsTUFBTSxFQUFFLGlCQUFpQjtJQUN6QixNQUFNLEVBQUUsWUFBWTtJQUNwQixPQUFPLEVBQUUsMkVBQTJFO0lBQ3BGLEtBQUssRUFBRSxlQUFlLEVBQVUsaUNBQWlDO0lBQ2pFLEtBQUssRUFBRSxhQUFhO0lBQ3BCLEtBQUssRUFBRSxrQkFBa0I7SUFDekIsTUFBTSxFQUFFLFlBQVk7SUFDcEIsS0FBSyxFQUFFLHdCQUF3QjtJQUMvQixNQUFNLEVBQUUsWUFBWTtDQUNyQixDQUFDO0FBRUYsTUFBTSxDQUFDLE1BQU0sZ0JB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 \ No newline at end of file diff --git a/packages/kbot/dist-in/commands/run.js b/packages/kbot/dist-in/commands/run.js index 0b781007..33ac6f04 100644 --- a/packages/kbot/dist-in/commands/run.js +++ b/packages/kbot/dist-in/commands/run.js @@ -9,7 +9,7 @@ import { isArray, isString } from '@polymech/core/primitives'; import { Logger } from 'tslog'; import { createClient } from '../client.js'; import { OptionsSchema } from '../zod_schema.js'; -import { get } from '../source.js'; +import { get, isWebUrl } from '../source.js'; import { flatten } from '../utils/array.js'; import { collector } from '../collector.js'; import { load as loadProfile } from '../profile.js'; @@ -72,6 +72,7 @@ export const complete_messages = async (opts, options) => { } messages.push(promptMessage); messages.push((await preferences(opts))); + // Get content from files and web URLs let files = await get(path.resolve(options.path || '.'), options.include, options) || []; files = files.map(f => { return { ...f, role: 'user' }; }); messages = [...messages, ...files]; @@ -157,11 +158,16 @@ export const processRun = async (opts) => { * preserving any spaces within the paths. Needed for Salamand File Manager selections (eg: kbot "summarize, as json" -i "$(ListOfSelectedFullNames)") * - For Windows, it looks for patterns like "C:\" (any drive letter). * - For POSIX, it looks for a leading slash "/". + * - For web URLs, it looks for patterns like "http://" or "https://". * * Returns an array of path strings. If no matches are found, returns []. * */ function extractPaths(input) { + // If it's a web URL, return it + if (isWebUrl(input)) { + return [input]; + } // If it's a direct path that exists, return it if (exists(path.resolve(resolve(input)))) { return [input]; @@ -170,8 +176,8 @@ function extractPaths(input) { if (hasMagic(input)) { return [input]; } - // Matches either a Windows drive pattern like "C:\" or a forward slash "/". - const pathStartRegex = /([A-Za-z]:\\)|\//g; + // Matches either a Windows drive pattern like "C:\", a forward slash "/", or http/https URLs + const pathStartRegex = /([A-Za-z]:\\)|\/|(https?:\/\/)/g; const matchIndices = []; let match; // Collect the start index of each path @@ -208,13 +214,13 @@ export const run = async (opts) => { opts.include = [opts.include]; } if (isArray(opts.include)) { - // First check for glob patterns - const globPatterns = opts.include.filter((path) => hasMagic(path)); - // Then process non-glob patterns - const nonGlobPaths = opts.include.filter((path) => !hasMagic(path)); - const processedPaths = flattenArrays(nonGlobPaths.map(extractPaths)); - // Combine glob patterns and processed paths - opts.include = [...globPatterns, ...processedPaths]; + // First check for glob patterns and web URLs + const specialPatterns = opts.include.filter((path) => hasMagic(path) || isWebUrl(path)); + // Then process normal paths + const normalPaths = opts.include.filter((path) => !hasMagic(path) && !isWebUrl(path)); + const processedPaths = flattenArrays(normalPaths.map(extractPaths)); + // Combine special patterns and processed paths + opts.include = [...specialPatterns, ...processedPaths]; } } else { @@ -270,4 +276,4 @@ export const run = async (opts) => { } return ret; }; -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicnVuLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2NvbW1hbmRzL3J1bi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssSUFBSSxNQUFNLFdBQVcsQ0FBQTtBQUNqQyxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0sTUFBTSxDQUFBO0FBQy9CLE9BQU8sRUFBRSxJQUFJLElBQUksR0FBRyxFQUFFLE1BQU0sa0JBQWtCLENBQUE7QUFDOUMsT0FBTyxFQUFFLElBQUksSUFBSSxNQUFNLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQTtBQUNwRCxPQUFPLEVBQUUsSUFBSSxJQUFJLEtBQUssRUFBRSxNQUFNLG9CQUFvQixDQUFBO0FBQ2xELE9BQU8sRUFBRSxJQUFJLElBQUksSUFBSSxFQUFFLE1BQU0sbUJBQW1CLENBQUE7QUFDaEQsT0FBTyxFQUFFLGFBQWEsRUFBRSxPQUFPLEVBQUUsTUFBTSxFQUFFLFVBQVUsRUFBRSxNQUFNLG1CQUFtQixDQUFBO0FBQzlFLE9BQU8sRUFBRSxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0sMkJBQTJCLENBQUE7QUFLN0QsT0FBTyxFQUFFLE1BQU0sRUFBVyxNQUFNLE9BQU8sQ0FBQTtBQUN2QyxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sY0FBYyxDQUFBO0FBQzNDLE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQTtBQUNoRCxPQUFPLEVBQUUsR0FBRyxFQUFFLE1BQU0sY0FBYyxDQUFBO0FBQ2xDLE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSxtQkFBbUIsQ0FBQTtBQUMzQyxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0saUJBQWlCLENBQUE7QUFDM0MsT0FBTyxFQUFFLElBQUksSUFBSSxXQUFXLEVBQUUsTUFBTSxlQUFlLENBQUE7QUFDbkQsT0FBTyxFQUFFLElBQUksSUFBSSxTQUFTLEVBQUUsTUFBTSxhQUFhLENBQUE7QUFDL0MsT0FBTyxFQUFFLFdBQVcsRUFB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 \ No newline at end of file +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicnVuLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2NvbW1hbmRzL3J1bi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssSUFBSSxNQUFNLFdBQVcsQ0FBQTtBQUNqQyxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0sTUFBTSxDQUFBO0FBQy9CLE9BQU8sRUFBRSxJQUFJLElBQUksR0FBRyxFQUFFLE1BQU0sa0JBQWtCLENBQUE7QUFDOUMsT0FBTyxFQUFFLElBQUksSUFBSSxNQUFNLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQTtBQUNwRCxPQUFPLEVBQUUsSUFBSSxJQUFJLEtBQUssRUFBRSxNQUFNLG9CQUFvQixDQUFBO0FBQ2xELE9BQU8sRUFBRSxJQUFJLElBQUksSUFBSSxFQUFFLE1BQU0sbUJBQW1CLENBQUE7QUFDaEQsT0FBTyxFQUFFLGFBQWEsRUFBRSxPQUFPLEVBQUUsTUFBTSxFQUFFLFVBQVUsRUFBRSxNQUFNLG1CQUFtQixDQUFBO0FBQzlFLE9BQU8sRUFBRSxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0sMkJBQTJCLENBQUE7QUFLN0QsT0FBTyxFQUFFLE1BQU0sRUFBVyxNQUFNLE9BQU8sQ0FBQTtBQUN2QyxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sY0FBYyxDQUFBO0FBQzNDLE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQTtBQUNoRCxPQUFPLEVBQUUsR0FBRyxFQUFFLFFBQVEsRUFBRSxNQUFNLGNBQWMsQ0FBQTtBQUM1QyxPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQU0sbUJBQW1CLENBQUE7QUFDM0MsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLGlCQUFpQixDQUFBO0FBQzNDLE9BQU8sRUFBRSxJQUFJLElBQUksV0FBVyxFQUFFLE1BQU0sZUFBZSxDQUFBO0FBQ25ELE9BQU8sRUFBRSxJQUFJLElBQUksU0FBUyxFQUFFLE1BQU0sYUFBYSxDQUFBO0FBQy9DLE9BQU8sRUFB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 \ No newline at end of file diff --git a/packages/kbot/dist-in/http.d.ts b/packages/kbot/dist-in/http.d.ts new file mode 100644 index 00000000..f239e74a --- /dev/null +++ b/packages/kbot/dist-in/http.d.ts @@ -0,0 +1,16 @@ +import { IHandlerResult } from './mime-handlers.js'; +/** + * Fetch web content with caching + */ +export declare function fetchUrl(url: string): Promise<{ + content: string; + contentType: string; +}>; +/** + * Process HTML content into markdown + */ +export declare function processHtml(html: string): string; +/** + * Handle a web URL and return it in a format compatible with the get() function + */ +export declare function handleWebUrl(url: string): Promise; diff --git a/packages/kbot/dist-in/http.js b/packages/kbot/dist-in/http.js new file mode 100644 index 00000000..ecb9e8d1 --- /dev/null +++ b/packages/kbot/dist-in/http.js @@ -0,0 +1,124 @@ +import * as path from 'node:path'; +import * as fs from 'node:fs'; +import axios from 'axios'; +import TurndownService from 'turndown'; +import { sync as dir } from '@polymech/fs/dir'; +import { sync as exists } from '@polymech/fs/exists'; +import { sync as write } from '@polymech/fs/write'; +import { sync as read } from '@polymech/fs/read'; +import { logger } from './index.js'; +const turndown = new TurndownService(); +const CACHE_DIR = './.cache/https'; +const CACHE_EXPIRY = 7 * 24 * 60 * 60 * 1000; // 1 week in milliseconds +/** + * Create cache key from URL + */ +function createCacheKey(url) { + // Remove protocol and convert special characters to create a valid filename + return url.replace(/^https?:\/\//, '').replace(/[\/\?=&]/g, '_'); +} +/** + * Check if cache is valid (exists and not expired) + */ +function isCacheValid(cacheFile) { + if (!exists(cacheFile)) { + return false; + } + try { + const stats = fs.statSync(cacheFile); + const ageMs = Date.now() - stats.mtimeMs; + return ageMs < CACHE_EXPIRY; + } + catch (error) { + logger.error(`Error checking cache validity for ${cacheFile}:`, error); + return false; + } +} +/** + * Fetch web content with caching + */ +export async function fetchUrl(url) { + // Ensure cache directory exists + if (!exists(CACHE_DIR)) { + dir(CACHE_DIR); + } + const cacheKey = createCacheKey(url); + const cacheFile = path.join(CACHE_DIR, `${cacheKey}.json`); + if (isCacheValid(cacheFile)) { + try { + const cached = read(cacheFile, 'json'); + if (cached && typeof cached === 'object' && 'content' in cached && 'contentType' in cached) { + logger.debug(`Using cached content for ${url}`); + return cached; + } + } + catch (error) { + logger.error(`Error reading cache for ${url}:`, error); + // Continue to fetch fresh content if cache read fails + } + } + try { + const response = await axios.get(url, { + headers: { + 'User-Agent': 'Mozilla/5.0 (compatible; KBot/1.0)' + }, + responseType: 'text' + }); + const contentType = response.headers['content-type'] || 'text/html'; + const result = { + content: response.data, + contentType + }; + // Cache the result + write(cacheFile, JSON.stringify(result)); + return result; + } + catch (error) { + logger.error(`Error fetching ${url}:`, error.message); + throw new Error(`Failed to fetch ${url}: ${error.message}`); + } +} +/** + * Process HTML content into markdown + */ +export function processHtml(html) { + return turndown.turndown(html); +} +/** + * Handle a web URL and return it in a format compatible with the get() function + */ +export async function handleWebUrl(url) { + try { + const { content, contentType } = await fetchUrl(url); + if (contentType.includes('json')) { + // Handle JSON response + const jsonContent = typeof content === 'string' ? JSON.parse(content) : content; + return { + content: `\`\`\`json\n${JSON.stringify(jsonContent, null, 2)}\n\`\`\``, + path: url, + role: 'user', + name: `web_${createCacheKey(url)}` + }; + } + else { + // Handle HTML response + const markdown = processHtml(content); + return { + content: markdown, + path: url, + role: 'user', + name: `web_${createCacheKey(url)}` + }; + } + } + catch (error) { + logger.error(`Error handling web URL ${url}:`, error); + return { + content: `Error fetching URL: ${url} - ${error.message}`, + path: url, + role: 'user', + name: `web_${createCacheKey(url)}_error` + }; + } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaHR0cC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9odHRwLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxJQUFJLE1BQU0sV0FBVyxDQUFBO0FBQ2pDLE9BQU8sS0FBSyxFQUFFLE1BQU0sU0FBUyxDQUFBO0FBQzdCLE9BQU8sS0FBSyxNQUFNLE9BQU8sQ0FBQTtBQUN6QixPQUFPLGVBQWUsTUFBTSxVQUFVLENBQUE7QUFDdEMsT0FBTyxFQUFFLElBQUksSUFBSSxHQUFHLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQTtBQUM5QyxPQUFPLEVBQUUsSUFBSSxJQUFJLE1BQU0sRUFBRSxNQUFNLHFCQUFxQixDQUFBO0FBQ3BELE9BQU8sRUFBRSxJQUFJLElBQUksS0FBSyxFQUFFLE1BQU0sb0JBQW9CLENBQUE7QUFDbEQsT0FBTyxFQUFFLElBQUksSUFBSSxJQUFJLEVBQUUsTUFBTSxtQkFBbUIsQ0FBQTtBQUNoRCxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sWUFBWSxDQUFBO0FBR25DLE1BQU0sUUFBUSxHQUFHLElBQUksZUFBZSxFQUFFLENBQUE7QUFDdEMsTUFBTSxTQUFTLEdBQUcsZ0JBQWdCLENBQUE7QUFDbEMsTUFBTSxZQUFZLEdBQUcsQ0FBQyxHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLElBQUksQ0FBQSxDQUFDLHlCQUF5QjtBQUV0RTs7R0FFRztBQUNILFNBQVMsY0FBYyxDQUFDLEdBQVc7SUFDakMsNEVBQTRFO0lBQzVFLE9BQU8sR0FBRyxDQUFDLE9BQU8sQ0FBQyxjQUFjLEVBQUUsRUFBRSxDQUFDLENBQUMsT0FBTyxDQUFDLFdBQVcsRUFBRSxHQUFHLENBQUMsQ0FBQTtBQUNsRSxDQUFDO0FBRUQ7O0dBRUc7QUFDSCxTQUFTLFlBQVksQ0FBQyxTQUFpQjtJQUNyQyxJQUFJLENBQUMsTUFBTSxDQUFDLFNBQVMsQ0FBQyxFQUFFLENBQUM7UUFDdkIsT0FBTyxLQUFLLENBQUE7SUFD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 \ No newline at end of file diff --git a/packages/kbot/dist-in/source.d.ts b/packages/kbot/dist-in/source.d.ts index b4c270bb..3b38b4ba 100644 --- a/packages/kbot/dist-in/source.d.ts +++ b/packages/kbot/dist-in/source.d.ts @@ -14,6 +14,13 @@ export declare const default_filters: { export declare const isPathOutsideSafe: (pathA: string, pathB: string) => boolean; export declare const base64: (filePath: string) => string | null; export declare const images: (files: string[]) => ChatCompletionContentPartImage[]; -export declare const glob: (projectPath: string, include?: string[]) => string[]; +/** + * Check if a string is a web URL + */ +export declare const isWebUrl: (str: string) => boolean; +export declare const glob: (projectPath: string, include?: string[]) => { + files: string[]; + webUrls: Set; +}; export declare function get(projectPath: string, include: string[], options: IKBotTask): Promise>; export declare function vectorize(file: string, options: IKBotTask): Promise; diff --git a/packages/kbot/dist-in/source.js b/packages/kbot/dist-in/source.js index 88e00ff9..0ef64465 100644 --- a/packages/kbot/dist-in/source.js +++ b/packages/kbot/dist-in/source.js @@ -10,6 +10,7 @@ import { globSync } from 'glob'; import { EXCLUDE_GLOB, MAX_FILE_SIZE } from './constants.js'; import { defaultMimeRegistry } from './mime-handlers.js'; import { supported } from './commands/run-assistant.js'; +import { handleWebUrl } from './http.js'; /** * @todos * - add support for vector stores : https://platform.openai.com/docs/assistants/tools/file-search?lang=node.js @@ -51,15 +52,27 @@ export const images = (files) => { image_url: { url: base64(f) } })); }; +/** + * Check if a string is a web URL + */ +export const isWebUrl = (str) => { + return /^https?:\/\//.test(str); +}; export const glob = (projectPath, include = []) => { if (!exists(projectPath)) { dir(projectPath); - return []; + return { files: [], webUrls: new Set() }; } const filters = new Set(); const absolutePaths = new Set(); + const webUrls = new Set(); EXCLUDE_GLOB.forEach(pattern => filters.add(pattern)); include.forEach(pattern => { + // Check if the pattern is a web URL + if (isWebUrl(pattern)) { + webUrls.add(pattern); + return; + } if (path.isAbsolute(pattern)) { if (isPathInside(pattern, projectPath)) { filters.add(pattern); @@ -82,11 +95,12 @@ export const glob = (projectPath, include = []) => { ...Array.from(absolutePaths) ])); let files = allFiles.filter((f) => Object.keys(default_filters).every((key) => default_filters[key](f))); - return files; + return { files, webUrls }; }; export async function get(projectPath, include = [], options) { - let files = glob(projectPath, include); - let ret = files.map((fullPath) => { + const { files, webUrls } = glob(projectPath, include); + // Process file contents + const fileResults = files.map((fullPath) => { try { const relativePath = forward_slash(path.relative(projectPath, fullPath)); if (isFile(fullPath) && exists(fullPath)) { @@ -104,8 +118,20 @@ export async function get(projectPath, include = [], options) { return null; } }); - ret = await ret.filter((r) => r !== null); - return ret; + // Process web URLs + const webUrlPromises = Array.from(webUrls).map(async (url) => { + try { + return await handleWebUrl(url); + } + catch (error) { + logger.error(`Error processing web URL ${url}:`, error); + return null; + } + }); + const webResults = await Promise.all(webUrlPromises); + // Combine and filter results + const results = [...fileResults, ...webResults].filter((r) => r !== null); + return results; } export async function vectorize(file, options) { if (!options.client) { @@ -142,4 +168,4 @@ export async function vectorize(file, options) { throw error; } } -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic291cmNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL3NvdXJjZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssSUFBSSxNQUFNLFdBQVcsQ0FBQTtBQUNqQyxPQUFPLEtBQUssRUFBRSxNQUFNLFNBQVMsQ0FBQTtBQUU3QixPQUFPLEVBQUUsSUFBSSxJQUFJLEdBQUcsRUFBRSxNQUFNLGtCQUFrQixDQUFBO0FBRTlDLE9BQU8sRUFBRSxVQUFVLElBQUksTUFBTSxFQUFFLE1BQU0sc0JBQXNCLENBQUE7QUFDM0QsT0FBTyxFQUFFLElBQUksSUFBSSxNQUFNLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQTtBQUNwRCxPQUFPLEVBQUUsTUFBTSxFQUFFLGFBQWEsRUFBRSxNQUFNLG1CQUFtQixDQUFBO0FBQ3pELE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxZQUFZLENBQUE7QUFDbkMsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLFlBQVksQ0FBQTtBQUNuQyxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0sTUFBTSxDQUFBO0FBQy9CLE9BQU8sRUFBRSxZQUFZLEVBQUUsYUFBYSxFQUFFLE1BQU0sZ0JBQWdCLENBQUE7QUFDNUQsT0FBTyxFQUFFLG1CQUFtQixFQUFrQixNQUFNLG9CQUFvQixDQUFBO0FBR3hFLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSw2QkFBNkIsQ0FBQTtBQUV2RDs7O0dBR0c7QUFFSCxNQUFNLENBQUMsTUFBTSxlQUFlLEdBQUc7SUFDN0IsTUFBTTtJQUNOLE1BQU07SUFDTixJQUFJLEVBQUUsQ0FBQyxRQUFnQixFQUFFLEVBQUUsQ0FBQyxNQUFNLENBQUMsUUFBUSxDQUFDLENBQUMsSUFBSSxHQUFHLGFBQWE7Q0FDbEUsQ0FBQztBQUVGLE1BQU0sWUFBWSxHQUFHLENBQUMsU0FBaUIsRUFBRSxVQUFrQixFQUFXLEVBQUU7SUFDdEUsTUFBTSxRQUFRLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQyxV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 \ No newline at end of file +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic291cmNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL3NvdXJjZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssSUFBSSxNQUFNLFdBQVcsQ0FBQTtBQUNqQyxPQUFPLEtBQUssRUFBRSxNQUFNLFNBQVMsQ0FBQTtBQUU3QixPQUFPLEVBQUUsSUFBSSxJQUFJLEdBQUcsRUFBRSxNQUFNLGtCQUFrQixDQUFBO0FBRTlDLE9BQU8sRUFBRSxVQUFVLElBQUksTUFBTSxFQUFFLE1BQU0sc0JBQXNCLENBQUE7QUFDM0QsT0FBTyxFQUFFLElBQUksSUFBSSxNQUFNLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQTtBQUNwRCxPQUFPLEVBQUUsTUFBTSxFQUFFLGFBQWEsRUFBRSxNQUFNLG1CQUFtQixDQUFBO0FBQ3pELE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxZQUFZLENBQUE7QUFDbkMsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLFlBQVksQ0FBQTtBQUNuQyxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0sTUFBTSxDQUFBO0FBQy9CLE9BQU8sRUFBRSxZQUFZLEVBQUUsYUFBYSxFQUFFLE1BQU0sZ0JBQWdCLENBQUE7QUFDNUQsT0FBTyxFQUFFLG1CQUFtQixFQUFrQixNQUFNLG9CQUFvQixDQUFBO0FBR3hFLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSw2QkFBNkIsQ0FBQTtBQUN2RCxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sV0FBVyxDQUFBO0FBRXhDOzs7R0FHRztBQUVILE1BQU0sQ0FBQyxNQUFNLGVBQWUsR0FBRztJQUM3QixNQUFNO0lBQ04sTUFBTTtJQUNOLElBQUksRUFBRSxDQUFDLFFBQWdCLEVBQUUsRUFBRSxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsQ0FBQyxJQUFJLEdBQUcsYUFBYTtDQUNsRSxDQUFDO0FBRUYsTUFBTSxZQUFZLEdBQUcsQ0FBQyxTQUFpQixFQUFFLFVBQWtCLEVBQVcsRUFBRTtJ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 \ No newline at end of file diff --git a/packages/kbot/docs/WEB_URL_SUPPORT.md b/packages/kbot/docs/WEB_URL_SUPPORT.md new file mode 100644 index 00000000..d4487e01 --- /dev/null +++ b/packages/kbot/docs/WEB_URL_SUPPORT.md @@ -0,0 +1,44 @@ +# Web URL Support for kbot + +The kbot tool now supports including web URLs as source material for AI processing alongside local files. + +## Features + +- **Web Page Support**: Process HTML content and convert it to markdown for the AI +- **JSON API Support**: Handle JSON responses from web APIs +- **Caching**: Automatically cache web content for one week to improve performance +- **Mixed Sources**: Combine local files and web URLs in a single command + +## How to Use + +Include web URLs in your commands using the `-i` or `--include` parameter: + +```bash +# Basic usage with a single web URL +kbot "Summarize this documentation" -i https://raw.githubusercontent.com/polymech/polymech-mono/main/README.md + +# Multiple sources (local file and web URL) +kbot "Compare this code with the documentation" -i src/index.ts,https://docs.npmjs.com/cli/v10/commands/npm-install + +# For JSON APIs +kbot "Extract user emails" -i https://jsonplaceholder.typicode.com/users +``` + +## Caching + +Web content is cached in the `./.cache/https` directory with a default expiration of one week. This reduces unnecessary network requests and improves performance for repeated queries on the same URLs. + +## Technical Details + +- HTML content is converted to markdown using the Turndown library +- JSON responses are formatted and presented as code blocks +- All web requests use axios with a custom user agent +- Cache management automatically handles expiration and refreshing of content + +## Testing + +A test script is included to verify web URL functionality: + +```bash +node test_web_urls.js +``` \ No newline at end of file diff --git a/packages/kbot/logs/params.json b/packages/kbot/logs/params.json index b0cc9cb5..c5631a37 100644 --- a/packages/kbot/logs/params.json +++ b/packages/kbot/logs/params.json @@ -1,9 +1,9 @@ { - "model": "perplexity/sonar-deep-research", + "model": "openrouter/quasar-alpha", "messages": [ { "role": "user", - "content": "List at least 3 popular open source CAD software. Include FreeCAD in your answer. Return as JSON." + "content": "divide 15 by 3. Return only the number, no explanation." }, { "role": "user", diff --git a/packages/kbot/package-lock.json b/packages/kbot/package-lock.json index 3a92a8c5..c6ff5fa8 100644 --- a/packages/kbot/package-lock.json +++ b/packages/kbot/package-lock.json @@ -14,6 +14,7 @@ "@polymech/fs": "file:../fs", "@polymech/log": "file:../log", "@polymech/slugify": "file:../slugify", + "@types/turndown": "5.0.5", "axios": "1.7.9", "chalk": "4.0.0", "deepmerge-ts": "7.1.4", @@ -30,6 +31,7 @@ "p-throttle": "7.0.0", "ts-retry": "6.0.0", "tslog": "^4.9.3", + "turndown": "7.2.0", "yargs": "17.7.2", "zod": "3.24.2" }, @@ -1214,6 +1216,12 @@ "jsep": "^0.4.0||^1.0.0" } }, + "node_modules/@mixmark-io/domino": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@mixmark-io/domino/-/domino-2.2.0.tgz", + "integrity": "sha512-Y28PR25bHXUg88kCV7nivXrP2Nj2RueZ3/l/jdx6J9f8J4nsEGcgX0Qe6lt7Pa+J79+kPiJU3LguR6O/6zrLOw==", + "license": "BSD-2-Clause" + }, "node_modules/@mswjs/interceptors": { "version": "0.37.6", "resolved": "https://registry.npmjs.org/@mswjs/interceptors/-/interceptors-0.37.6.tgz", @@ -1709,6 +1717,12 @@ "optional": true, "peer": true }, + "node_modules/@types/turndown": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/@types/turndown/-/turndown-5.0.5.tgz", + "integrity": "sha512-TL2IgGgc7B5j78rIccBtlYAnkuv8nUQqhQc+DSYV5j9Be9XOcm/SKOVRuA47xAVI3680Tk9B1d8flK2GWT2+4w==", + "license": "MIT" + }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "6.21.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.21.0.tgz", @@ -7002,6 +7016,15 @@ "@esbuild/win32-x64": "0.25.0" } }, + "node_modules/turndown": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/turndown/-/turndown-7.2.0.tgz", + "integrity": "sha512-eCZGBN4nNNqM9Owkv9HAtWRYfLA4h909E/WGAWWBpmB275ehNhZyk87/Tpvjbp0jjNl9XwCsbe6bm6CqFsgD+A==", + "license": "MIT", + "dependencies": { + "@mixmark-io/domino": "^2.2.0" + } + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", diff --git a/packages/kbot/package.json b/packages/kbot/package.json index ea869004..53f52c43 100644 --- a/packages/kbot/package.json +++ b/packages/kbot/package.json @@ -39,6 +39,7 @@ "@polymech/fs": "file:../fs", "@polymech/log": "file:../log", "@polymech/slugify": "file:../slugify", + "@types/turndown": "5.0.5", "axios": "1.7.9", "chalk": "4.0.0", "deepmerge-ts": "7.1.4", @@ -55,6 +56,7 @@ "p-throttle": "7.0.0", "ts-retry": "6.0.0", "tslog": "^4.9.3", + "turndown": "7.2.0", "yargs": "17.7.2", "zod": "3.24.2" }, diff --git a/packages/kbot/src/commands/run-assistant.ts b/packages/kbot/src/commands/run-assistant.ts index 79503aef..1b970520 100644 --- a/packages/kbot/src/commands/run-assistant.ts +++ b/packages/kbot/src/commands/run-assistant.ts @@ -136,13 +136,12 @@ export const runAssistant = async (client: OpenAI, params: any, options: IKBotTa name: "Documents Assistant", model: params.model, tools: [{ type: "file_search" }, ...params.tools], - }) - let files = glob(path.resolve(options.path), options.include) || [] - files = files.filter((f) => path.extname(f) in supported) + const { files } = glob(path.resolve(options.path), options.include) || { files: [], webUrls: new Set() } + const filesToProcess = files.filter((f) => path.extname(f) in supported) - const attachments = await Promise.all(files.map(async (file: string) => { + const attachments = await Promise.all(filesToProcess.map(async (file: string) => { const file_id = await createOpenAIFile(client, file) return { file_id: file_id.id, @@ -150,7 +149,6 @@ export const runAssistant = async (client: OpenAI, params: any, options: IKBotTa } })) - const thread = await client.beta.threads.create({ messages: [ { diff --git a/packages/kbot/src/commands/run.ts b/packages/kbot/src/commands/run.ts index 8e2901c2..c1c4fb0a 100644 --- a/packages/kbot/src/commands/run.ts +++ b/packages/kbot/src/commands/run.ts @@ -13,7 +13,7 @@ import { IKBotTask } from '@polymech/ai-tools' import { Logger, ILogObj } from 'tslog' import { createClient } from '../client.js' import { OptionsSchema } from '../zod_schema.js' -import { get } from '../source.js' +import { get, isWebUrl } from '../source.js' import { flatten } from '../utils/array.js' import { collector } from '../collector.js' import { load as loadProfile } from '../profile.js' @@ -96,6 +96,7 @@ export const complete_messages = async ( messages.push(promptMessage as ChatCompletionMessageParam) messages.push((await preferences(opts)) as ChatCompletionMessageParam) + // Get content from files and web URLs let files = await get(path.resolve(options.path || '.'), options.include, options) || [] files = files.map(f => { return { ...f, role: 'user' } }) messages = [...messages as Array, ...files] @@ -203,11 +204,17 @@ export const processRun = async (opts: IKBotTask): Promise => * preserving any spaces within the paths. Needed for Salamand File Manager selections (eg: kbot "summarize, as json" -i "$(ListOfSelectedFullNames)") * - For Windows, it looks for patterns like "C:\" (any drive letter). * - For POSIX, it looks for a leading slash "/". + * - For web URLs, it looks for patterns like "http://" or "https://". * * Returns an array of path strings. If no matches are found, returns []. * */ function extractPaths(input: string): string[] { + // If it's a web URL, return it + if (isWebUrl(input)) { + return [input] + } + // If it's a direct path that exists, return it if (exists(path.resolve(resolve(input)))) { return [input] @@ -218,8 +225,8 @@ function extractPaths(input: string): string[] { return [input] } - // Matches either a Windows drive pattern like "C:\" or a forward slash "/". - const pathStartRegex = /([A-Za-z]:\\)|\//g; + // Matches either a Windows drive pattern like "C:\", a forward slash "/", or http/https URLs + const pathStartRegex = /([A-Za-z]:\\)|\/|(https?:\/\/)/g; const matchIndices: number[] = []; let match: RegExpExecArray | null; @@ -264,13 +271,13 @@ export const run = async (opts: IKBotTask): Promise => { opts.include = [opts.include] } if (isArray(opts.include)) { - // First check for glob patterns - const globPatterns = opts.include.filter((path: string) => hasMagic(path)) - // Then process non-glob patterns - const nonGlobPaths = opts.include.filter((path: string) => !hasMagic(path)) - const processedPaths = flattenArrays(nonGlobPaths.map(extractPaths)) - // Combine glob patterns and processed paths - opts.include = [...globPatterns, ...processedPaths] + // First check for glob patterns and web URLs + const specialPatterns = opts.include.filter((path: string) => hasMagic(path) || isWebUrl(path)) + // Then process normal paths + const normalPaths = opts.include.filter((path: string) => !hasMagic(path) && !isWebUrl(path)) + const processedPaths = flattenArrays(normalPaths.map(extractPaths)) + // Combine special patterns and processed paths + opts.include = [...specialPatterns, ...processedPaths] } } else { opts.include = [] diff --git a/packages/kbot/src/http.ts b/packages/kbot/src/http.ts new file mode 100644 index 00000000..3d424f5b --- /dev/null +++ b/packages/kbot/src/http.ts @@ -0,0 +1,133 @@ +import * as path from 'node:path' +import * as fs from 'node:fs' +import axios from 'axios' +import TurndownService from 'turndown' +import { sync as dir } from '@polymech/fs/dir' +import { sync as exists } from '@polymech/fs/exists' +import { sync as write } from '@polymech/fs/write' +import { sync as read } from '@polymech/fs/read' +import { logger } from './index.js' +import { IHandlerResult } from './mime-handlers.js' + +const turndown = new TurndownService() +const CACHE_DIR = './.cache/https' +const CACHE_EXPIRY = 7 * 24 * 60 * 60 * 1000 // 1 week in milliseconds + +/** + * Create cache key from URL + */ +function createCacheKey(url: string): string { + // Remove protocol and convert special characters to create a valid filename + return url.replace(/^https?:\/\//, '').replace(/[\/\?=&]/g, '_') +} + +/** + * Check if cache is valid (exists and not expired) + */ +function isCacheValid(cacheFile: string): boolean { + if (!exists(cacheFile)) { + return false + } + + try { + const stats = fs.statSync(cacheFile) + const ageMs = Date.now() - stats.mtimeMs + return ageMs < CACHE_EXPIRY + } catch (error) { + logger.error(`Error checking cache validity for ${cacheFile}:`, error) + return false + } +} + +/** + * Fetch web content with caching + */ +export async function fetchUrl(url: string): Promise<{ content: string, contentType: string }> { + // Ensure cache directory exists + if (!exists(CACHE_DIR)) { + dir(CACHE_DIR) + } + + const cacheKey = createCacheKey(url) + const cacheFile = path.join(CACHE_DIR, `${cacheKey}.json`) + + if (isCacheValid(cacheFile)) { + try { + const cached = read(cacheFile, 'json') as { content: string, contentType: string } + if (cached && typeof cached === 'object' && 'content' in cached && 'contentType' in cached) { + logger.debug(`Using cached content for ${url}`) + return cached + } + } catch (error) { + logger.error(`Error reading cache for ${url}:`, error) + // Continue to fetch fresh content if cache read fails + } + } + + try { + const response = await axios.get(url, { + headers: { + 'User-Agent': 'Mozilla/5.0 (compatible; KBot/1.0)' + }, + responseType: 'text' + }) + + const contentType = response.headers['content-type'] || 'text/html' + const result = { + content: response.data, + contentType + } + + // Cache the result + write(cacheFile, JSON.stringify(result)) + + return result + } catch (error) { + logger.error(`Error fetching ${url}:`, error.message) + throw new Error(`Failed to fetch ${url}: ${error.message}`) + } +} + +/** + * Process HTML content into markdown + */ +export function processHtml(html: string): string { + return turndown.turndown(html) +} + +/** + * Handle a web URL and return it in a format compatible with the get() function + */ +export async function handleWebUrl(url: string): Promise { + try { + const { content, contentType } = await fetchUrl(url) + + if (contentType.includes('json')) { + // Handle JSON response + const jsonContent = typeof content === 'string' ? JSON.parse(content) : content + return { + content: `\`\`\`json\n${JSON.stringify(jsonContent, null, 2)}\n\`\`\``, + path: url, + role: 'user', + name: `web_${createCacheKey(url)}` + } + } else { + // Handle HTML response + const markdown = processHtml(content) + return { + content: markdown, + path: url, + role: 'user', + name: `web_${createCacheKey(url)}` + } + } + } catch (error) { + logger.error(`Error handling web URL ${url}:`, error) + return { + content: `Error fetching URL: ${url} - ${error.message}`, + path: url, + role: 'user', + name: `web_${createCacheKey(url)}_error` + } + } +} \ No newline at end of file diff --git a/packages/kbot/src/reference/web.ts b/packages/kbot/src/reference/web.ts new file mode 100644 index 00000000..44ca15a4 --- /dev/null +++ b/packages/kbot/src/reference/web.ts @@ -0,0 +1,112 @@ +import * as path from 'path' +import { RunnableToolFunction } from 'openai/lib/RunnableFunction' + +import puppeteer from 'puppeteer' +import TurndownService from 'turndown' + +import { toolLogger } from '../../index.js' +import { IKBotTask } from '../../types.js' + +const turndown = new TurndownService() + +export const tools = (target: string, options: IKBotTask): Array => { + const logger = toolLogger('web', options) + return [ + { + type: 'function', + function: { + name: 'browse_page', + description: 'Browse a webpage and return its content as markdown, all links, images and pages main image', + parameters: { + type: 'object', + properties: { + url: { + type: 'string', + description: 'URL of the webpage to browse' + } + }, + required: ['url'] + }, + function: async (params: any) => { + try { + logger.debug(`Tool::BrowsePage Browsing ${params.url}`); + const browser = await puppeteer.launch({ + headless: true, + args: ['--no-sandbox', '--disable-setuid-sandbox'] + }) + + try { + const page = await browser.newPage() + logger.debug(`Tool::Web::BrowsePage Opening page ${params.url}`) + await page.goto(params.url, { + waitUntil: 'networkidle2' + }) + + const pageData = await page.evaluate((selector) => { + const elementsToRemove = document.querySelectorAll( + 'script, style, link, meta, noscript, iframe, [style*="display:none"],[style*="display: none"], .hidden' + ) + elementsToRemove.forEach(el => el.remove()) + + const links = Array.from(document.querySelectorAll('a')) + .map(a => ({ + text: a.textContent?.trim() || '', + href: a.href + })) + .filter(link => link.href && link.href.startsWith('http')) + .slice(0, 20) + + const images = Array.from(document.querySelectorAll('img')) + .map(img => ({ + src: img.src, + alt: img.alt || '', + width: img.width, + height: img.height + })) + .filter(img => img.src && img.src.startsWith('http')) + .slice(0, 20) + + const mainImage = document.querySelector('meta[property="og:image"]')?.getAttribute('content') || + document.querySelector('meta[name="og:image"]')?.getAttribute('content') + + let content + const body = document.body + content = body ? body.innerHTML : '' + return { + content, + links, + images, + ogImage: mainImage + } + }, null) + + const markdown = turndown.turndown(pageData.content) + await browser.close() + const ret = { + success: true, + markdown: markdown, + links: pageData.links, + images: pageData.images, + mainImage: pageData.ogImage, + url: params.url + }; + return ret + } catch (error: any) { + logger.debug('Error browsing page:', error.message, error); + await browser.close() + throw error + } + } catch (error: any) { + logger.debug('Error browsing page:', error.message); + return { + success: false, + error: error.message, + url: params.url + }; + } + }, + parse: JSON.parse + } + } as RunnableToolFunction + ] +} \ No newline at end of file diff --git a/packages/kbot/src/source.ts b/packages/kbot/src/source.ts index bf5742ba..42f6080a 100644 --- a/packages/kbot/src/source.ts +++ b/packages/kbot/src/source.ts @@ -14,6 +14,7 @@ import { defaultMimeRegistry, IHandlerResult } from './mime-handlers.js' import { ChatCompletionContentPartImage } from 'openai/resources/index.mjs' import { IKBotTask, ICollector } from '@polymech/ai-tools' import { supported } from './commands/run-assistant.js' +import { handleWebUrl } from './http.js' /** * @todos @@ -63,21 +64,35 @@ export const images = (files: string[]): ChatCompletionContentPartImage[] => { })) } +/** + * Check if a string is a web URL + */ +export const isWebUrl = (str: string): boolean => { + return /^https?:\/\//.test(str); +} + export const glob = ( projectPath: string, include: string[] = [] -) => { +): { files: string[], webUrls: Set } => { if (!exists(projectPath)) { dir(projectPath) - return [] + return { files: [], webUrls: new Set() } } const filters = new Set() const absolutePaths = new Set() + const webUrls = new Set() EXCLUDE_GLOB.forEach(pattern => filters.add(pattern)) include.forEach(pattern => { + // Check if the pattern is a web URL + if (isWebUrl(pattern)) { + webUrls.add(pattern) + return + } + if (path.isAbsolute(pattern)) { if (isPathInside(pattern, projectPath)) { filters.add(pattern) @@ -103,7 +118,7 @@ export const glob = ( let files = allFiles.filter((f) => Object.keys(default_filters).every((key) => default_filters[key](f)) ) - return files + return { files, webUrls } } export async function get( @@ -111,8 +126,10 @@ export async function get( include: string[] = [], options: IKBotTask ): Promise> { - let files = glob(projectPath, include) - let ret = files.map((fullPath) => { + const { files, webUrls } = glob(projectPath, include) + + // Process file contents + const fileResults = files.map((fullPath) => { try { const relativePath = forward_slash(path.relative(projectPath, fullPath)) if (isFile(fullPath) && exists(fullPath)) { @@ -129,8 +146,22 @@ export async function get( return null } }) - ret = await ret.filter((r) => r !== null) - return ret + + // Process web URLs + const webUrlPromises = Array.from(webUrls).map(async (url: string) => { + try { + return await handleWebUrl(url) + } catch (error) { + logger.error(`Error processing web URL ${url}:`, error) + return null + } + }) + + const webResults = await Promise.all(webUrlPromises) + + // Combine and filter results + const results = [...fileResults, ...webResults].filter((r) => r !== null) + return results } export async function vectorize(file: string, options: IKBotTask): Promise { diff --git a/packages/kbot/test_web_urls.js b/packages/kbot/test_web_urls.js new file mode 100644 index 00000000..56e858cc --- /dev/null +++ b/packages/kbot/test_web_urls.js @@ -0,0 +1,50 @@ +#!/usr/bin/env node +import { spawn } from 'child_process'; + +const TEST_CASES = [ + { + name: 'GitHub README', + command: ['kbot', 'Summarize this documentation', '-i', 'https://raw.githubusercontent.com/polymech/polymech-mono/main/README.md'] + }, + { + name: 'JSON API', + command: ['kbot', 'Extract user emails', '-i', 'https://jsonplaceholder.typicode.com/users'] + }, + { + name: 'Mixed Sources', + command: ['kbot', 'Compare these files and the web content', '-i', 'package.json,https://docs.npmjs.com/cli/v10/commands/npm-install'] + } +]; + +async function runTest(test) { + console.log(`\n\n=== Running Test: ${test.name} ===`); + console.log(`Command: ${test.command.join(' ')}`); + + return new Promise((resolve) => { + const child = spawn(test.command[0], test.command.slice(1), { + cwd: process.cwd(), + stdio: 'inherit' + }); + + child.on('close', (code) => { + console.log(`Test "${test.name}" completed with exit code ${code}`); + resolve(code === 0); + }); + }); +} + +async function runTests() { + console.log('Starting Web URL Support Tests'); + + for (const test of TEST_CASES) { + const success = await runTest(test); + console.log(`Test "${test.name}": ${success ? 'PASSED' : 'FAILED'}`); + } + + console.log('\nAll tests completed'); +} + +runTests().catch(err => { + console.error('Test execution failed:', err); + process.exit(1); +}); \ No newline at end of file diff --git a/packages/kbot/tests/unit/basic.test.ts b/packages/kbot/tests/unit/basic.test.ts index f7841590..f4c05298 100644 --- a/packages/kbot/tests/unit/basic.test.ts +++ b/packages/kbot/tests/unit/basic.test.ts @@ -59,6 +59,21 @@ describe('Basic Operations', () => { expect(result.result[0]?.trim()?.toLowerCase()).toEqual('5') }, { timeout: TEST_TIMEOUT }) + it.each(models)('should load web content with model %s', async (modelName) => { + const result = await runTest( + 'Check if the content contains a section about Human prehistory. Reply with "yes" if it does, "no" if it does not.', + 'yes', + 'web_content', + modelName, + TEST_LOG_PATH, + { + include: ['https://en.wikipedia.org/wiki/Kenya'] + } + ) + testResults.push(result) + expect(result.result[0]?.trim()?.toLowerCase()).toContain('yes') + }, { timeout: TEST_TIMEOUT * 2 }) // Double timeout for web requests + it('should generate markdown report', () => { generateTestReport(testResults, 'Basic Operations Test Results', TEST_REPORT_PATH) expect(exists(TEST_REPORT_PATH) === 'file').toBe(true) diff --git a/packages/kbot/tests/unit/reports/all.json b/packages/kbot/tests/unit/reports/all.json index c906c779..930b3aa5 100644 --- a/packages/kbot/tests/unit/reports/all.json +++ b/packages/kbot/tests/unit/reports/all.json @@ -11681,6 +11681,461 @@ "duration": 47027, "reason": "Model returned empty response", "category": "research" + }, + { + "test": "quadratic", + "prompt": "Solve the quadratic equation x² + 5x + 6 = 0. Return only the solutions as comma-separated numbers, no explanation.", + "result": [ + "-2, -3" + ], + "expected": "-2,-3", + "model": "openai/gpt-3.5-turbo", + "router": "openai/gpt-3.5-turbo", + "timestamp": "2025-04-06T15:29:38.130Z", + "passed": false, + "duration": 1532, + "reason": "Expected -2,-3, but got -2, -3", + "category": "math" + }, + { + "test": "quadratic", + "prompt": "Solve the quadratic equation x² + 5x + 6 = 0. Return only the solutions as comma-separated numbers, no explanation.", + "result": [ + "The solutions to the equation x² + 5x + 6 = 0 are -2 and -3. \n\n-2, -3\n\n**Step-by-Step Explanation:**\n\n1. **Identify the coefficients:** The quadratic equation is x² + 5x + 6 = 0, so a = 1, b = 5, c = 6.\n\n2. **Factor the quadratic equation:** Look for two numbers that multiply to 6 (the constant term, c) and add up to 5 (the coefficient of the x term, b). These numbers are 2 and 3.\n\n3. **Write the factored form:** Using these numbers, the equation can be rewritten as (x + 2)(x + 3) = 0.\n\n4. **Apply the Zero Product Property:** Set each factor equal to zero:\n - x + 2 = 0 ⇒ x = -2\n - x + 3 = 0 ⇒ x = -3\n\n5. **Confirm with the Quadratic Formula:** As an alternative, using the quadratic formula x = (-b ± √(b² - 4ac)) / (2a):\n - Calculate the discriminant: D = 5² - 4*1*6 = 25 - 24 = 1.\n - Plug into the formula: x = (-5 ± √1)/2, which simplifies to x = (-5 + 1)/2 = -2 and x = (-5 -1)/2 = -3.\n\nBoth methods yield the same solutions: x = -2 and x = -3.\n\n**Final Solutions:** -2, -3\n\n\\boxed{-2, -3}" + ], + "expected": "-2,-3", + "model": "deepseek/deepseek-r1-distill-qwen-14b:free", + "router": "deepseek/deepseek-r1-distill-qwen-14b:free", + "timestamp": "2025-04-06T15:29:53.362Z", + "passed": false, + "duration": 15216, + "reason": "Expected -2,-3, but got the solutions to the equation x² + 5x + 6 = 0 are -2 and -3. \n\n-2, -3\n\n**step-by-step explanation:**\n\n1. **identify the coefficients:** the quadratic equation is x² + 5x + 6 = 0, so a = 1, b = 5, c = 6.\n\n2. **factor the quadratic equation:** look for two numbers that multiply to 6 (the constant term, c) and add up to 5 (the coefficient of the x term, b). these numbers are 2 and 3.\n\n3. **write the factored form:** using these numbers, the equation can be rewritten as (x + 2)(x + 3) = 0.\n\n4. **apply the zero product property:** set each factor equal to zero:\n - x + 2 = 0 ⇒ x = -2\n - x + 3 = 0 ⇒ x = -3\n\n5. **confirm with the quadratic formula:** as an alternative, using the quadratic formula x = (-b ± √(b² - 4ac)) / (2a):\n - calculate the discriminant: d = 5² - 4*1*6 = 25 - 24 = 1.\n - plug into the formula: x = (-5 ± √1)/2, which simplifies to x = (-5 + 1)/2 = -2 and x = (-5 -1)/2 = -3.\n\nboth methods yield the same solutions: x = -2 and x = -3.\n\n**final solutions:** -2, -3\n\n\\boxed{-2, -3}", + "category": "math" + }, + { + "test": "quadratic", + "prompt": "Solve the quadratic equation x² + 5x + 6 = 0. Return only the solutions as comma-separated numbers, no explanation.", + "result": [ + "-2, -3" + ], + "expected": "-2,-3", + "model": "openai/gpt-4o-mini", + "router": "openai/gpt-4o-mini", + "timestamp": "2025-04-06T15:29:54.426Z", + "passed": false, + "duration": 1049, + "reason": "Expected -2,-3, but got -2, -3", + "category": "math" + }, + { + "test": "quadratic", + "prompt": "Solve the quadratic equation x² + 5x + 6 = 0. Return only the solutions as comma-separated numbers, no explanation.", + "result": [ + "-2, -3" + ], + "expected": "-2,-3", + "model": "openrouter/quasar-alpha", + "router": "openrouter/quasar-alpha", + "timestamp": "2025-04-06T15:29:55.395Z", + "passed": false, + "duration": 957, + "reason": "Expected -2,-3, but got -2, -3", + "category": "math" + }, + { + "test": "factorial", + "prompt": "Calculate 5! (factorial of 5). Return only the number, no explanation.", + "result": [ + "120" + ], + "expected": "120", + "model": "openai/gpt-3.5-turbo", + "router": "openai/gpt-3.5-turbo", + "timestamp": "2025-04-06T15:29:56.594Z", + "passed": true, + "duration": 1188, + "category": "math" + }, + { + "test": "factorial", + "prompt": "Calculate 5! (factorial of 5). Return only the number, no explanation.", + "result": [ + "120" + ], + "expected": "120", + "model": "deepseek/deepseek-r1-distill-qwen-14b:free", + "router": "deepseek/deepseek-r1-distill-qwen-14b:free", + "timestamp": "2025-04-06T15:30:03.300Z", + "passed": true, + "duration": 6695, + "category": "math" + }, + { + "test": "factorial", + "prompt": "Calculate 5! (factorial of 5). Return only the number, no explanation.", + "result": [ + "120" + ], + "expected": "120", + "model": "openai/gpt-4o-mini", + "router": "openai/gpt-4o-mini", + "timestamp": "2025-04-06T15:30:04.536Z", + "passed": true, + "duration": 1226, + "category": "math" + }, + { + "test": "factorial", + "prompt": "Calculate 5! (factorial of 5). Return only the number, no explanation.", + "result": [ + "120" + ], + "expected": "120", + "model": "openrouter/quasar-alpha", + "router": "openrouter/quasar-alpha", + "timestamp": "2025-04-06T15:30:05.417Z", + "passed": true, + "duration": 869, + "category": "math" + }, + { + "test": "fibonacci", + "prompt": "Calculate the 6th number in the Fibonacci sequence. Return only the number, no explanation.", + "result": [ + "8" + ], + "expected": "8", + "model": "openai/gpt-3.5-turbo", + "router": "openai/gpt-3.5-turbo", + "timestamp": "2025-04-06T15:30:06.154Z", + "passed": true, + "duration": 726, + "category": "math" + }, + { + "test": "fibonacci", + "prompt": "Calculate the 6th number in the Fibonacci sequence. Return only the number, no explanation.", + "result": [ + "5" + ], + "expected": "8", + "model": "deepseek/deepseek-r1-distill-qwen-14b:free", + "router": "deepseek/deepseek-r1-distill-qwen-14b:free", + "timestamp": "2025-04-06T15:30:10.540Z", + "passed": false, + "duration": 4375, + "reason": "Expected 8, but got 5", + "category": "math" + }, + { + "test": "fibonacci", + "prompt": "Calculate the 6th number in the Fibonacci sequence. Return only the number, no explanation.", + "result": [ + "5" + ], + "expected": "8", + "model": "openai/gpt-4o-mini", + "router": "openai/gpt-4o-mini", + "timestamp": "2025-04-06T15:30:11.342Z", + "passed": false, + "duration": 791, + "reason": "Expected 8, but got 5", + "category": "math" + }, + { + "test": "fibonacci", + "prompt": "Calculate the 6th number in the Fibonacci sequence. Return only the number, no explanation.", + "result": [ + "8" + ], + "expected": "8", + "model": "openrouter/quasar-alpha", + "router": "openrouter/quasar-alpha", + "timestamp": "2025-04-06T15:30:12.377Z", + "passed": true, + "duration": 1023, + "category": "math" + }, + { + "test": "square_root", + "prompt": "Calculate the square root of 16. Return only the number, no explanation.", + "result": [ + "4" + ], + "expected": "4", + "model": "openai/gpt-3.5-turbo", + "router": "openai/gpt-3.5-turbo", + "timestamp": "2025-04-06T15:30:13.400Z", + "passed": true, + "duration": 1012, + "category": "math" + }, + { + "test": "square_root", + "prompt": "Calculate the square root of 16. Return only the number, no explanation.", + "result": [ + "4" + ], + "expected": "4", + "model": "deepseek/deepseek-r1-distill-qwen-14b:free", + "router": "deepseek/deepseek-r1-distill-qwen-14b:free", + "timestamp": "2025-04-06T15:30:15.334Z", + "passed": true, + "duration": 1923, + "category": "math" + }, + { + "test": "square_root", + "prompt": "Calculate the square root of 16. Return only the number, no explanation.", + "result": [ + "4" + ], + "expected": "4", + "model": "openai/gpt-4o-mini", + "router": "openai/gpt-4o-mini", + "timestamp": "2025-04-06T15:30:16.375Z", + "passed": true, + "duration": 1031, + "category": "math" + }, + { + "test": "square_root", + "prompt": "Calculate the square root of 16. Return only the number, no explanation.", + "result": [ + "4" + ], + "expected": "4", + "model": "openrouter/quasar-alpha", + "router": "openrouter/quasar-alpha", + "timestamp": "2025-04-06T15:30:17.166Z", + "passed": true, + "duration": 780, + "category": "math" + }, + { + "test": "power", + "prompt": "Calculate 2 raised to the power of 3. Return only the number, no explanation.", + "result": [ + "8" + ], + "expected": "8", + "model": "openai/gpt-3.5-turbo", + "router": "openai/gpt-3.5-turbo", + "timestamp": "2025-04-06T15:30:18.012Z", + "passed": true, + "duration": 836, + "category": "math" + }, + { + "test": "power", + "prompt": "Calculate 2 raised to the power of 3. Return only the number, no explanation.", + "result": [ + "8" + ], + "expected": "8", + "model": "deepseek/deepseek-r1-distill-qwen-14b:free", + "router": "deepseek/deepseek-r1-distill-qwen-14b:free", + "timestamp": "2025-04-06T15:30:22.877Z", + "passed": true, + "duration": 4854, + "category": "math" + }, + { + "test": "power", + "prompt": "Calculate 2 raised to the power of 3. Return only the number, no explanation.", + "result": [ + "8" + ], + "expected": "8", + "model": "openai/gpt-4o-mini", + "router": "openai/gpt-4o-mini", + "timestamp": "2025-04-06T15:30:23.822Z", + "passed": true, + "duration": 935, + "category": "math" + }, + { + "test": "power", + "prompt": "Calculate 2 raised to the power of 3. Return only the number, no explanation.", + "result": [ + "8" + ], + "expected": "8", + "model": "openrouter/quasar-alpha", + "router": "openrouter/quasar-alpha", + "timestamp": "2025-04-06T15:30:24.693Z", + "passed": true, + "duration": 861, + "category": "math" + }, + { + "test": "addition", + "prompt": "add 5 and 3. Return only the number, no explanation.", + "result": [ + "8" + ], + "expected": "8", + "model": "openai/gpt-3.5-turbo", + "router": "openai/gpt-3.5-turbo", + "timestamp": "2025-04-06T15:30:34.409Z", + "passed": true, + "duration": 1182, + "category": "basic" + }, + { + "test": "addition", + "prompt": "add 5 and 3. Return only the number, no explanation.", + "result": [ + "The result of adding 5 and 3 is:\n\n\\[\n5 + 3 = \\boxed{8}\n\\]" + ], + "expected": "8", + "model": "deepseek/deepseek-r1-distill-qwen-14b:free", + "router": "deepseek/deepseek-r1-distill-qwen-14b:free", + "timestamp": "2025-04-06T15:30:36.894Z", + "passed": false, + "duration": 2473, + "reason": "Expected 8, but got the result of adding 5 and 3 is:\n\n\\[\n5 + 3 = \\boxed{8}\n\\]", + "category": "basic" + }, + { + "test": "addition", + "prompt": "add 5 and 3. Return only the number, no explanation.", + "result": [ + "8" + ], + "expected": "8", + "model": "openai/gpt-4o-mini", + "router": "openai/gpt-4o-mini", + "timestamp": "2025-04-06T15:30:37.616Z", + "passed": true, + "duration": 709, + "category": "basic" + }, + { + "test": "addition", + "prompt": "add 5 and 3. Return only the number, no explanation.", + "result": [ + "8" + ], + "expected": "8", + "model": "openrouter/quasar-alpha", + "router": "openrouter/quasar-alpha", + "timestamp": "2025-04-06T15:30:38.429Z", + "passed": true, + "duration": 803, + "category": "basic" + }, + { + "test": "multiplication", + "prompt": "multiply 8 and 3. Return only the number, no explanation.", + "result": [ + "24" + ], + "expected": "24", + "model": "openai/gpt-3.5-turbo", + "router": "openai/gpt-3.5-turbo", + "timestamp": "2025-04-06T15:30:39.355Z", + "passed": true, + "duration": 916, + "category": "basic" + }, + { + "test": "multiplication", + "prompt": "multiply 8 and 3. Return only the number, no explanation.", + "result": [ + "24" + ], + "expected": "24", + "model": "deepseek/deepseek-r1-distill-qwen-14b:free", + "router": "deepseek/deepseek-r1-distill-qwen-14b:free", + "timestamp": "2025-04-06T15:30:45.589Z", + "passed": true, + "duration": 6224, + "category": "basic" + }, + { + "test": "multiplication", + "prompt": "multiply 8 and 3. Return only the number, no explanation.", + "result": [ + "24" + ], + "expected": "24", + "model": "openai/gpt-4o-mini", + "router": "openai/gpt-4o-mini", + "timestamp": "2025-04-06T15:30:46.831Z", + "passed": true, + "duration": 1232, + "category": "basic" + }, + { + "test": "multiplication", + "prompt": "multiply 8 and 3. Return only the number, no explanation.", + "result": [ + "24" + ], + "expected": "24", + "model": "openrouter/quasar-alpha", + "router": "openrouter/quasar-alpha", + "timestamp": "2025-04-06T15:30:52.602Z", + "passed": true, + "duration": 5757, + "category": "basic" + }, + { + "test": "division", + "prompt": "divide 15 by 3. Return only the number, no explanation.", + "result": [ + "5" + ], + "expected": "5", + "model": "openai/gpt-3.5-turbo", + "router": "openai/gpt-3.5-turbo", + "timestamp": "2025-04-06T15:30:53.506Z", + "passed": true, + "duration": 893, + "category": "basic" + }, + { + "test": "division", + "prompt": "divide 15 by 3. Return only the number, no explanation.", + "result": [ + "5" + ], + "expected": "5", + "model": "deepseek/deepseek-r1-distill-qwen-14b:free", + "router": "deepseek/deepseek-r1-distill-qwen-14b:free", + "timestamp": "2025-04-06T15:30:55.129Z", + "passed": true, + "duration": 1612, + "category": "basic" + }, + { + "test": "division", + "prompt": "divide 15 by 3. Return only the number, no explanation.", + "result": [ + "5" + ], + "expected": "5", + "model": "openai/gpt-4o-mini", + "router": "openai/gpt-4o-mini", + "timestamp": "2025-04-06T15:30:55.819Z", + "passed": true, + "duration": 680, + "category": "basic" + }, + { + "test": "division", + "prompt": "divide 15 by 3. Return only the number, no explanation.", + "result": [ + "5" + ], + "expected": "5", + "model": "openrouter/quasar-alpha", + "router": "openrouter/quasar-alpha", + "timestamp": "2025-04-06T15:30:56.860Z", + "passed": true, + "duration": 1031, + "category": "basic" } ], "highscores": [ @@ -11689,13 +12144,13 @@ "rankings": [ { "model": "openrouter/quasar-alpha", - "duration": 811, - "duration_secs": 0.811 + "duration": 957, + "duration_secs": 0.957 }, { "model": "openai/gpt-4o-mini", - "duration": 1074, - "duration_secs": 1.074 + "duration": 1049, + "duration_secs": 1.049 } ] }, @@ -11703,14 +12158,14 @@ "test": "factorial", "rankings": [ { - "model": "openai/gpt-3.5-turbo", - "duration": 744, - "duration_secs": 0.744 + "model": "openrouter/quasar-alpha", + "duration": 869, + "duration_secs": 0.869 }, { - "model": "openai/gpt-4o-mini", - "duration": 747, - "duration_secs": 0.747 + "model": "openai/gpt-3.5-turbo", + "duration": 1188, + "duration_secs": 1.188 } ] }, @@ -11718,14 +12173,14 @@ "test": "fibonacci", "rankings": [ { - "model": "openai/gpt-4o-mini", - "duration": 722, - "duration_secs": 0.722 + "model": "openai/gpt-3.5-turbo", + "duration": 726, + "duration_secs": 0.726 }, { - "model": "openai/gpt-3.5-turbo", - "duration": 838, - "duration_secs": 0.838 + "model": "openai/gpt-4o-mini", + "duration": 791, + "duration_secs": 0.791 } ] }, @@ -11733,9 +12188,9 @@ "test": "square_root", "rankings": [ { - "model": "openai/gpt-4o-mini", - "duration": 782, - "duration_secs": 0.782 + "model": "openrouter/quasar-alpha", + "duration": 780, + "duration_secs": 0.78 }, { "model": "anthropic/claude-3.5-sonnet", @@ -11748,14 +12203,14 @@ "test": "power", "rankings": [ { - "model": "openrouter/quasar-alpha", - "duration": 717, - "duration_secs": 0.717 + "model": "openai/gpt-3.5-turbo", + "duration": 836, + "duration_secs": 0.836 }, { - "model": "openai/gpt-4o-mini", - "duration": 848, - "duration_secs": 0.848 + "model": "openrouter/quasar-alpha", + "duration": 861, + "duration_secs": 0.861 } ] }, @@ -11763,14 +12218,14 @@ "test": "addition", "rankings": [ { - "model": "openrouter/quasar-alpha", - "duration": 729, - "duration_secs": 0.729 + "model": "openai/gpt-4o-mini", + "duration": 709, + "duration_secs": 0.709 }, { - "model": "openai/gpt-4o-mini", - "duration": 927, - "duration_secs": 0.927 + "model": "openrouter/quasar-alpha", + "duration": 803, + "duration_secs": 0.803 } ] }, @@ -11779,13 +12234,13 @@ "rankings": [ { "model": "openai/gpt-3.5-turbo", - "duration": 863, - "duration_secs": 0.863 + "duration": 916, + "duration_secs": 0.916 }, { - "model": "openrouter/quasar-alpha", - "duration": 960, - "duration_secs": 0.96 + "model": "anthropic/claude-3.5-sonnet", + "duration": 1190, + "duration_secs": 1.19 } ] }, @@ -11793,14 +12248,14 @@ "test": "division", "rankings": [ { - "model": "openrouter/quasar-alpha", - "duration": 749, - "duration_secs": 0.749 + "model": "openai/gpt-4o-mini", + "duration": 680, + "duration_secs": 0.68 }, { - "model": "openai/gpt-4o-mini", - "duration": 856, - "duration_secs": 0.856 + "model": "openai/gpt-3.5-turbo", + "duration": 893, + "duration_secs": 0.893 } ] }, @@ -11950,5 +12405,5 @@ ] } ], - "lastUpdated": "2025-04-06T14:49:47.083Z" + "lastUpdated": "2025-04-06T15:30:56.867Z" } \ No newline at end of file diff --git a/packages/kbot/tests/unit/reports/basic.json b/packages/kbot/tests/unit/reports/basic.json index 6322c1ac..d6865219 100644 --- a/packages/kbot/tests/unit/reports/basic.json +++ b/packages/kbot/tests/unit/reports/basic.json @@ -1924,6 +1924,175 @@ "passed": true, "duration": 749, "category": "basic" + }, + { + "test": "addition", + "prompt": "add 5 and 3. Return only the number, no explanation.", + "result": [ + "8" + ], + "expected": "8", + "model": "openai/gpt-3.5-turbo", + "router": "openai/gpt-3.5-turbo", + "timestamp": "2025-04-06T15:30:34.409Z", + "passed": true, + "duration": 1182, + "category": "basic" + }, + { + "test": "addition", + "prompt": "add 5 and 3. Return only the number, no explanation.", + "result": [ + "The result of adding 5 and 3 is:\n\n\\[\n5 + 3 = \\boxed{8}\n\\]" + ], + "expected": "8", + "model": "deepseek/deepseek-r1-distill-qwen-14b:free", + "router": "deepseek/deepseek-r1-distill-qwen-14b:free", + "timestamp": "2025-04-06T15:30:36.894Z", + "passed": false, + "duration": 2473, + "reason": "Expected 8, but got the result of adding 5 and 3 is:\n\n\\[\n5 + 3 = \\boxed{8}\n\\]", + "category": "basic" + }, + { + "test": "addition", + "prompt": "add 5 and 3. Return only the number, no explanation.", + "result": [ + "8" + ], + "expected": "8", + "model": "openai/gpt-4o-mini", + "router": "openai/gpt-4o-mini", + "timestamp": "2025-04-06T15:30:37.616Z", + "passed": true, + "duration": 709, + "category": "basic" + }, + { + "test": "addition", + "prompt": "add 5 and 3. Return only the number, no explanation.", + "result": [ + "8" + ], + "expected": "8", + "model": "openrouter/quasar-alpha", + "router": "openrouter/quasar-alpha", + "timestamp": "2025-04-06T15:30:38.429Z", + "passed": true, + "duration": 803, + "category": "basic" + }, + { + "test": "multiplication", + "prompt": "multiply 8 and 3. Return only the number, no explanation.", + "result": [ + "24" + ], + "expected": "24", + "model": "openai/gpt-3.5-turbo", + "router": "openai/gpt-3.5-turbo", + "timestamp": "2025-04-06T15:30:39.355Z", + "passed": true, + "duration": 916, + "category": "basic" + }, + { + "test": "multiplication", + "prompt": "multiply 8 and 3. Return only the number, no explanation.", + "result": [ + "24" + ], + "expected": "24", + "model": "deepseek/deepseek-r1-distill-qwen-14b:free", + "router": "deepseek/deepseek-r1-distill-qwen-14b:free", + "timestamp": "2025-04-06T15:30:45.589Z", + "passed": true, + "duration": 6224, + "category": "basic" + }, + { + "test": "multiplication", + "prompt": "multiply 8 and 3. Return only the number, no explanation.", + "result": [ + "24" + ], + "expected": "24", + "model": "openai/gpt-4o-mini", + "router": "openai/gpt-4o-mini", + "timestamp": "2025-04-06T15:30:46.831Z", + "passed": true, + "duration": 1232, + "category": "basic" + }, + { + "test": "multiplication", + "prompt": "multiply 8 and 3. Return only the number, no explanation.", + "result": [ + "24" + ], + "expected": "24", + "model": "openrouter/quasar-alpha", + "router": "openrouter/quasar-alpha", + "timestamp": "2025-04-06T15:30:52.602Z", + "passed": true, + "duration": 5757, + "category": "basic" + }, + { + "test": "division", + "prompt": "divide 15 by 3. Return only the number, no explanation.", + "result": [ + "5" + ], + "expected": "5", + "model": "openai/gpt-3.5-turbo", + "router": "openai/gpt-3.5-turbo", + "timestamp": "2025-04-06T15:30:53.506Z", + "passed": true, + "duration": 893, + "category": "basic" + }, + { + "test": "division", + "prompt": "divide 15 by 3. Return only the number, no explanation.", + "result": [ + "5" + ], + "expected": "5", + "model": "deepseek/deepseek-r1-distill-qwen-14b:free", + "router": "deepseek/deepseek-r1-distill-qwen-14b:free", + "timestamp": "2025-04-06T15:30:55.129Z", + "passed": true, + "duration": 1612, + "category": "basic" + }, + { + "test": "division", + "prompt": "divide 15 by 3. Return only the number, no explanation.", + "result": [ + "5" + ], + "expected": "5", + "model": "openai/gpt-4o-mini", + "router": "openai/gpt-4o-mini", + "timestamp": "2025-04-06T15:30:55.819Z", + "passed": true, + "duration": 680, + "category": "basic" + }, + { + "test": "division", + "prompt": "divide 15 by 3. Return only the number, no explanation.", + "result": [ + "5" + ], + "expected": "5", + "model": "openrouter/quasar-alpha", + "router": "openrouter/quasar-alpha", + "timestamp": "2025-04-06T15:30:56.860Z", + "passed": true, + "duration": 1031, + "category": "basic" } ], "highscores": [ @@ -1931,14 +2100,14 @@ "test": "addition", "rankings": [ { - "model": "openrouter/quasar-alpha", - "duration": 729, - "duration_secs": 0.729 + "model": "openai/gpt-4o-mini", + "duration": 709, + "duration_secs": 0.709 }, { - "model": "openai/gpt-4o-mini", - "duration": 927, - "duration_secs": 0.927 + "model": "openrouter/quasar-alpha", + "duration": 803, + "duration_secs": 0.803 } ] }, @@ -1947,13 +2116,13 @@ "rankings": [ { "model": "openai/gpt-3.5-turbo", - "duration": 863, - "duration_secs": 0.863 + "duration": 916, + "duration_secs": 0.916 }, { - "model": "openrouter/quasar-alpha", - "duration": 960, - "duration_secs": 0.96 + "model": "anthropic/claude-3.5-sonnet", + "duration": 1190, + "duration_secs": 1.19 } ] }, @@ -1961,17 +2130,17 @@ "test": "division", "rankings": [ { - "model": "openrouter/quasar-alpha", - "duration": 749, - "duration_secs": 0.749 + "model": "openai/gpt-4o-mini", + "duration": 680, + "duration_secs": 0.68 }, { - "model": "openai/gpt-4o-mini", - "duration": 856, - "duration_secs": 0.856 + "model": "openai/gpt-3.5-turbo", + "duration": 893, + "duration_secs": 0.893 } ] } ], - "lastUpdated": "2025-04-06T14:21:02.047Z" + "lastUpdated": "2025-04-06T15:30:56.861Z" } \ No newline at end of file diff --git a/packages/kbot/tests/unit/reports/basic.md b/packages/kbot/tests/unit/reports/basic.md index 214d56f1..f846c973 100644 --- a/packages/kbot/tests/unit/reports/basic.md +++ b/packages/kbot/tests/unit/reports/basic.md @@ -6,18 +6,18 @@ | Test | Model | Duration (ms) | Duration (s) | |------|-------|--------------|--------------| -| addition | openrouter/quasar-alpha | 729 | 0.73 | -| addition | openai/gpt-4o-mini | 927 | 0.93 | -| addition | openai/gpt-3.5-turbo | 1197 | 1.20 | -| addition | deepseek/deepseek-r1-distill-qwen-14b:free | 11570 | 11.57 | -| multiplication | openai/gpt-3.5-turbo | 863 | 0.86 | -| multiplication | openrouter/quasar-alpha | 960 | 0.96 | -| multiplication | openai/gpt-4o-mini | 1105 | 1.10 | -| multiplication | deepseek/deepseek-r1-distill-qwen-14b:free | 16310 | 16.31 | -| division | openrouter/quasar-alpha | 749 | 0.75 | -| division | openai/gpt-4o-mini | 856 | 0.86 | -| division | openai/gpt-3.5-turbo | 901 | 0.90 | -| division | deepseek/deepseek-r1-distill-qwen-14b:free | 11412 | 11.41 | +| addition | openai/gpt-4o-mini | 709 | 0.71 | +| addition | openrouter/quasar-alpha | 803 | 0.80 | +| addition | openai/gpt-3.5-turbo | 1182 | 1.18 | +| addition | deepseek/deepseek-r1-distill-qwen-14b:free | 2473 | 2.47 | +| multiplication | openai/gpt-3.5-turbo | 916 | 0.92 | +| multiplication | openai/gpt-4o-mini | 1232 | 1.23 | +| multiplication | openrouter/quasar-alpha | 5757 | 5.76 | +| multiplication | deepseek/deepseek-r1-distill-qwen-14b:free | 6224 | 6.22 | +| division | openai/gpt-4o-mini | 680 | 0.68 | +| division | openai/gpt-3.5-turbo | 893 | 0.89 | +| division | openrouter/quasar-alpha | 1031 | 1.03 | +| division | deepseek/deepseek-r1-distill-qwen-14b:free | 1612 | 1.61 | ## Summary @@ -25,22 +25,26 @@ - Passed: 11 - Failed: 1 - Success Rate: 91.67% -- Average Duration: 3965ms (3.96s) +- Average Duration: 1959ms (1.96s) ## Failed Tests -### division - deepseek/deepseek-r1-distill-qwen-14b:free +### addition - deepseek/deepseek-r1-distill-qwen-14b:free -- Prompt: `divide 15 by 3. Return only the number, no explanation.` -- Expected: `5` -- Actual: `15 ÷ 3 equals 5. +- Prompt: `add 5 and 3. Return only the number, no explanation.` +- Expected: `8` +- Actual: `The result of adding 5 and 3 is: -5` -- Duration: 11412ms (11.41s) -- Reason: Expected 5, but got 15 ÷ 3 equals 5. +\[ +5 + 3 = \boxed{8} +\]` +- Duration: 2473ms (2.47s) +- Reason: Expected 8, but got the result of adding 5 and 3 is: -5 -- Timestamp: 4/6/2025, 4:21:00 PM +\[ +5 + 3 = \boxed{8} +\] +- Timestamp: 4/6/2025, 5:30:36 PM ## Passed Tests @@ -49,86 +53,86 @@ - Prompt: `add 5 and 3. Return only the number, no explanation.` - Expected: `8` - Actual: `8` -- Duration: 1197ms (1.20s) -- Timestamp: 4/6/2025, 4:20:15 PM - -### addition - deepseek/deepseek-r1-distill-qwen-14b:free - -- Prompt: `add 5 and 3. Return only the number, no explanation.` -- Expected: `8` -- Actual: `8` -- Duration: 11570ms (11.57s) -- Timestamp: 4/6/2025, 4:20:27 PM +- Duration: 1182ms (1.18s) +- Timestamp: 4/6/2025, 5:30:34 PM ### addition - openai/gpt-4o-mini - Prompt: `add 5 and 3. Return only the number, no explanation.` - Expected: `8` - Actual: `8` -- Duration: 927ms (0.93s) -- Timestamp: 4/6/2025, 4:20:28 PM +- Duration: 709ms (0.71s) +- Timestamp: 4/6/2025, 5:30:37 PM ### addition - openrouter/quasar-alpha - Prompt: `add 5 and 3. Return only the number, no explanation.` - Expected: `8` - Actual: `8` -- Duration: 729ms (0.73s) -- Timestamp: 4/6/2025, 4:20:28 PM +- Duration: 803ms (0.80s) +- Timestamp: 4/6/2025, 5:30:38 PM ### multiplication - openai/gpt-3.5-turbo - Prompt: `multiply 8 and 3. Return only the number, no explanation.` - Expected: `24` - Actual: `24` -- Duration: 863ms (0.86s) -- Timestamp: 4/6/2025, 4:20:29 PM +- Duration: 916ms (0.92s) +- Timestamp: 4/6/2025, 5:30:39 PM ### multiplication - deepseek/deepseek-r1-distill-qwen-14b:free - Prompt: `multiply 8 and 3. Return only the number, no explanation.` - Expected: `24` - Actual: `24` -- Duration: 16310ms (16.31s) -- Timestamp: 4/6/2025, 4:20:45 PM +- Duration: 6224ms (6.22s) +- Timestamp: 4/6/2025, 5:30:45 PM ### multiplication - openai/gpt-4o-mini - Prompt: `multiply 8 and 3. Return only the number, no explanation.` - Expected: `24` - Actual: `24` -- Duration: 1105ms (1.10s) -- Timestamp: 4/6/2025, 4:20:47 PM +- Duration: 1232ms (1.23s) +- Timestamp: 4/6/2025, 5:30:46 PM ### multiplication - openrouter/quasar-alpha - Prompt: `multiply 8 and 3. Return only the number, no explanation.` - Expected: `24` - Actual: `24` -- Duration: 960ms (0.96s) -- Timestamp: 4/6/2025, 4:20:48 PM +- Duration: 5757ms (5.76s) +- Timestamp: 4/6/2025, 5:30:52 PM ### division - openai/gpt-3.5-turbo - Prompt: `divide 15 by 3. Return only the number, no explanation.` - Expected: `5` - Actual: `5` -- Duration: 901ms (0.90s) -- Timestamp: 4/6/2025, 4:20:48 PM +- Duration: 893ms (0.89s) +- Timestamp: 4/6/2025, 5:30:53 PM + +### division - deepseek/deepseek-r1-distill-qwen-14b:free + +- Prompt: `divide 15 by 3. Return only the number, no explanation.` +- Expected: `5` +- Actual: `5` +- Duration: 1612ms (1.61s) +- Timestamp: 4/6/2025, 5:30:55 PM ### division - openai/gpt-4o-mini - Prompt: `divide 15 by 3. Return only the number, no explanation.` - Expected: `5` - Actual: `5` -- Duration: 856ms (0.86s) -- Timestamp: 4/6/2025, 4:21:01 PM +- Duration: 680ms (0.68s) +- Timestamp: 4/6/2025, 5:30:55 PM ### division - openrouter/quasar-alpha - Prompt: `divide 15 by 3. Return only the number, no explanation.` - Expected: `5` - Actual: `5` -- Duration: 749ms (0.75s) -- Timestamp: 4/6/2025, 4:21:02 PM +- Duration: 1031ms (1.03s) +- Timestamp: 4/6/2025, 5:30:56 PM diff --git a/packages/kbot/tests/unit/reports/math.json b/packages/kbot/tests/unit/reports/math.json index 339b29ae..383cc194 100644 --- a/packages/kbot/tests/unit/reports/math.json +++ b/packages/kbot/tests/unit/reports/math.json @@ -3397,6 +3397,292 @@ "passed": true, "duration": 717, "category": "math" + }, + { + "test": "quadratic", + "prompt": "Solve the quadratic equation x² + 5x + 6 = 0. Return only the solutions as comma-separated numbers, no explanation.", + "result": [ + "-2, -3" + ], + "expected": "-2,-3", + "model": "openai/gpt-3.5-turbo", + "router": "openai/gpt-3.5-turbo", + "timestamp": "2025-04-06T15:29:38.130Z", + "passed": false, + "duration": 1532, + "reason": "Expected -2,-3, but got -2, -3", + "category": "math" + }, + { + "test": "quadratic", + "prompt": "Solve the quadratic equation x² + 5x + 6 = 0. Return only the solutions as comma-separated numbers, no explanation.", + "result": [ + "The solutions to the equation x² + 5x + 6 = 0 are -2 and -3. \n\n-2, -3\n\n**Step-by-Step Explanation:**\n\n1. **Identify the coefficients:** The quadratic equation is x² + 5x + 6 = 0, so a = 1, b = 5, c = 6.\n\n2. **Factor the quadratic equation:** Look for two numbers that multiply to 6 (the constant term, c) and add up to 5 (the coefficient of the x term, b). These numbers are 2 and 3.\n\n3. **Write the factored form:** Using these numbers, the equation can be rewritten as (x + 2)(x + 3) = 0.\n\n4. **Apply the Zero Product Property:** Set each factor equal to zero:\n - x + 2 = 0 ⇒ x = -2\n - x + 3 = 0 ⇒ x = -3\n\n5. **Confirm with the Quadratic Formula:** As an alternative, using the quadratic formula x = (-b ± √(b² - 4ac)) / (2a):\n - Calculate the discriminant: D = 5² - 4*1*6 = 25 - 24 = 1.\n - Plug into the formula: x = (-5 ± √1)/2, which simplifies to x = (-5 + 1)/2 = -2 and x = (-5 -1)/2 = -3.\n\nBoth methods yield the same solutions: x = -2 and x = -3.\n\n**Final Solutions:** -2, -3\n\n\\boxed{-2, -3}" + ], + "expected": "-2,-3", + "model": "deepseek/deepseek-r1-distill-qwen-14b:free", + "router": "deepseek/deepseek-r1-distill-qwen-14b:free", + "timestamp": "2025-04-06T15:29:53.362Z", + "passed": false, + "duration": 15216, + "reason": "Expected -2,-3, but got the solutions to the equation x² + 5x + 6 = 0 are -2 and -3. \n\n-2, -3\n\n**step-by-step explanation:**\n\n1. **identify the coefficients:** the quadratic equation is x² + 5x + 6 = 0, so a = 1, b = 5, c = 6.\n\n2. **factor the quadratic equation:** look for two numbers that multiply to 6 (the constant term, c) and add up to 5 (the coefficient of the x term, b). these numbers are 2 and 3.\n\n3. **write the factored form:** using these numbers, the equation can be rewritten as (x + 2)(x + 3) = 0.\n\n4. **apply the zero product property:** set each factor equal to zero:\n - x + 2 = 0 ⇒ x = -2\n - x + 3 = 0 ⇒ x = -3\n\n5. **confirm with the quadratic formula:** as an alternative, using the quadratic formula x = (-b ± √(b² - 4ac)) / (2a):\n - calculate the discriminant: d = 5² - 4*1*6 = 25 - 24 = 1.\n - plug into the formula: x = (-5 ± √1)/2, which simplifies to x = (-5 + 1)/2 = -2 and x = (-5 -1)/2 = -3.\n\nboth methods yield the same solutions: x = -2 and x = -3.\n\n**final solutions:** -2, -3\n\n\\boxed{-2, -3}", + "category": "math" + }, + { + "test": "quadratic", + "prompt": "Solve the quadratic equation x² + 5x + 6 = 0. Return only the solutions as comma-separated numbers, no explanation.", + "result": [ + "-2, -3" + ], + "expected": "-2,-3", + "model": "openai/gpt-4o-mini", + "router": "openai/gpt-4o-mini", + "timestamp": "2025-04-06T15:29:54.426Z", + "passed": false, + "duration": 1049, + "reason": "Expected -2,-3, but got -2, -3", + "category": "math" + }, + { + "test": "quadratic", + "prompt": "Solve the quadratic equation x² + 5x + 6 = 0. Return only the solutions as comma-separated numbers, no explanation.", + "result": [ + "-2, -3" + ], + "expected": "-2,-3", + "model": "openrouter/quasar-alpha", + "router": "openrouter/quasar-alpha", + "timestamp": "2025-04-06T15:29:55.395Z", + "passed": false, + "duration": 957, + "reason": "Expected -2,-3, but got -2, -3", + "category": "math" + }, + { + "test": "factorial", + "prompt": "Calculate 5! (factorial of 5). Return only the number, no explanation.", + "result": [ + "120" + ], + "expected": "120", + "model": "openai/gpt-3.5-turbo", + "router": "openai/gpt-3.5-turbo", + "timestamp": "2025-04-06T15:29:56.594Z", + "passed": true, + "duration": 1188, + "category": "math" + }, + { + "test": "factorial", + "prompt": "Calculate 5! (factorial of 5). Return only the number, no explanation.", + "result": [ + "120" + ], + "expected": "120", + "model": "deepseek/deepseek-r1-distill-qwen-14b:free", + "router": "deepseek/deepseek-r1-distill-qwen-14b:free", + "timestamp": "2025-04-06T15:30:03.300Z", + "passed": true, + "duration": 6695, + "category": "math" + }, + { + "test": "factorial", + "prompt": "Calculate 5! (factorial of 5). Return only the number, no explanation.", + "result": [ + "120" + ], + "expected": "120", + "model": "openai/gpt-4o-mini", + "router": "openai/gpt-4o-mini", + "timestamp": "2025-04-06T15:30:04.536Z", + "passed": true, + "duration": 1226, + "category": "math" + }, + { + "test": "factorial", + "prompt": "Calculate 5! (factorial of 5). Return only the number, no explanation.", + "result": [ + "120" + ], + "expected": "120", + "model": "openrouter/quasar-alpha", + "router": "openrouter/quasar-alpha", + "timestamp": "2025-04-06T15:30:05.417Z", + "passed": true, + "duration": 869, + "category": "math" + }, + { + "test": "fibonacci", + "prompt": "Calculate the 6th number in the Fibonacci sequence. Return only the number, no explanation.", + "result": [ + "8" + ], + "expected": "8", + "model": "openai/gpt-3.5-turbo", + "router": "openai/gpt-3.5-turbo", + "timestamp": "2025-04-06T15:30:06.154Z", + "passed": true, + "duration": 726, + "category": "math" + }, + { + "test": "fibonacci", + "prompt": "Calculate the 6th number in the Fibonacci sequence. Return only the number, no explanation.", + "result": [ + "5" + ], + "expected": "8", + "model": "deepseek/deepseek-r1-distill-qwen-14b:free", + "router": "deepseek/deepseek-r1-distill-qwen-14b:free", + "timestamp": "2025-04-06T15:30:10.540Z", + "passed": false, + "duration": 4375, + "reason": "Expected 8, but got 5", + "category": "math" + }, + { + "test": "fibonacci", + "prompt": "Calculate the 6th number in the Fibonacci sequence. Return only the number, no explanation.", + "result": [ + "5" + ], + "expected": "8", + "model": "openai/gpt-4o-mini", + "router": "openai/gpt-4o-mini", + "timestamp": "2025-04-06T15:30:11.342Z", + "passed": false, + "duration": 791, + "reason": "Expected 8, but got 5", + "category": "math" + }, + { + "test": "fibonacci", + "prompt": "Calculate the 6th number in the Fibonacci sequence. Return only the number, no explanation.", + "result": [ + "8" + ], + "expected": "8", + "model": "openrouter/quasar-alpha", + "router": "openrouter/quasar-alpha", + "timestamp": "2025-04-06T15:30:12.377Z", + "passed": true, + "duration": 1023, + "category": "math" + }, + { + "test": "square_root", + "prompt": "Calculate the square root of 16. Return only the number, no explanation.", + "result": [ + "4" + ], + "expected": "4", + "model": "openai/gpt-3.5-turbo", + "router": "openai/gpt-3.5-turbo", + "timestamp": "2025-04-06T15:30:13.400Z", + "passed": true, + "duration": 1012, + "category": "math" + }, + { + "test": "square_root", + "prompt": "Calculate the square root of 16. Return only the number, no explanation.", + "result": [ + "4" + ], + "expected": "4", + "model": "deepseek/deepseek-r1-distill-qwen-14b:free", + "router": "deepseek/deepseek-r1-distill-qwen-14b:free", + "timestamp": "2025-04-06T15:30:15.334Z", + "passed": true, + "duration": 1923, + "category": "math" + }, + { + "test": "square_root", + "prompt": "Calculate the square root of 16. Return only the number, no explanation.", + "result": [ + "4" + ], + "expected": "4", + "model": "openai/gpt-4o-mini", + "router": "openai/gpt-4o-mini", + "timestamp": "2025-04-06T15:30:16.375Z", + "passed": true, + "duration": 1031, + "category": "math" + }, + { + "test": "square_root", + "prompt": "Calculate the square root of 16. Return only the number, no explanation.", + "result": [ + "4" + ], + "expected": "4", + "model": "openrouter/quasar-alpha", + "router": "openrouter/quasar-alpha", + "timestamp": "2025-04-06T15:30:17.166Z", + "passed": true, + "duration": 780, + "category": "math" + }, + { + "test": "power", + "prompt": "Calculate 2 raised to the power of 3. Return only the number, no explanation.", + "result": [ + "8" + ], + "expected": "8", + "model": "openai/gpt-3.5-turbo", + "router": "openai/gpt-3.5-turbo", + "timestamp": "2025-04-06T15:30:18.012Z", + "passed": true, + "duration": 836, + "category": "math" + }, + { + "test": "power", + "prompt": "Calculate 2 raised to the power of 3. Return only the number, no explanation.", + "result": [ + "8" + ], + "expected": "8", + "model": "deepseek/deepseek-r1-distill-qwen-14b:free", + "router": "deepseek/deepseek-r1-distill-qwen-14b:free", + "timestamp": "2025-04-06T15:30:22.877Z", + "passed": true, + "duration": 4854, + "category": "math" + }, + { + "test": "power", + "prompt": "Calculate 2 raised to the power of 3. Return only the number, no explanation.", + "result": [ + "8" + ], + "expected": "8", + "model": "openai/gpt-4o-mini", + "router": "openai/gpt-4o-mini", + "timestamp": "2025-04-06T15:30:23.822Z", + "passed": true, + "duration": 935, + "category": "math" + }, + { + "test": "power", + "prompt": "Calculate 2 raised to the power of 3. Return only the number, no explanation.", + "result": [ + "8" + ], + "expected": "8", + "model": "openrouter/quasar-alpha", + "router": "openrouter/quasar-alpha", + "timestamp": "2025-04-06T15:30:24.693Z", + "passed": true, + "duration": 861, + "category": "math" } ], "highscores": [ @@ -3405,13 +3691,13 @@ "rankings": [ { "model": "openrouter/quasar-alpha", - "duration": 811, - "duration_secs": 0.811 + "duration": 957, + "duration_secs": 0.957 }, { "model": "openai/gpt-4o-mini", - "duration": 1074, - "duration_secs": 1.074 + "duration": 1049, + "duration_secs": 1.049 } ] }, @@ -3419,14 +3705,14 @@ "test": "factorial", "rankings": [ { - "model": "openai/gpt-3.5-turbo", - "duration": 744, - "duration_secs": 0.744 + "model": "openrouter/quasar-alpha", + "duration": 869, + "duration_secs": 0.869 }, { - "model": "openai/gpt-4o-mini", - "duration": 747, - "duration_secs": 0.747 + "model": "openai/gpt-3.5-turbo", + "duration": 1188, + "duration_secs": 1.188 } ] }, @@ -3434,14 +3720,14 @@ "test": "fibonacci", "rankings": [ { - "model": "openai/gpt-4o-mini", - "duration": 722, - "duration_secs": 0.722 + "model": "openai/gpt-3.5-turbo", + "duration": 726, + "duration_secs": 0.726 }, { - "model": "openai/gpt-3.5-turbo", - "duration": 838, - "duration_secs": 0.838 + "model": "openai/gpt-4o-mini", + "duration": 791, + "duration_secs": 0.791 } ] }, @@ -3449,9 +3735,9 @@ "test": "square_root", "rankings": [ { - "model": "openai/gpt-4o-mini", - "duration": 782, - "duration_secs": 0.782 + "model": "openrouter/quasar-alpha", + "duration": 780, + "duration_secs": 0.78 }, { "model": "anthropic/claude-3.5-sonnet", @@ -3464,17 +3750,17 @@ "test": "power", "rankings": [ { - "model": "openrouter/quasar-alpha", - "duration": 717, - "duration_secs": 0.717 + "model": "openai/gpt-3.5-turbo", + "duration": 836, + "duration_secs": 0.836 }, { - "model": "openai/gpt-4o-mini", - "duration": 848, - "duration_secs": 0.848 + "model": "openrouter/quasar-alpha", + "duration": 861, + "duration_secs": 0.861 } ] } ], - "lastUpdated": "2025-04-06T14:36:25.642Z" + "lastUpdated": "2025-04-06T15:30:24.694Z" } \ No newline at end of file diff --git a/packages/kbot/tests/unit/reports/math.md b/packages/kbot/tests/unit/reports/math.md index d008c712..592436ec 100644 --- a/packages/kbot/tests/unit/reports/math.md +++ b/packages/kbot/tests/unit/reports/math.md @@ -6,34 +6,34 @@ | Test | Model | Duration (ms) | Duration (s) | |------|-------|--------------|--------------| -| quadratic | openrouter/quasar-alpha | 811 | 0.81 | -| quadratic | openai/gpt-4o-mini | 1074 | 1.07 | -| quadratic | openai/gpt-3.5-turbo | 1248 | 1.25 | -| quadratic | deepseek/deepseek-r1-distill-qwen-14b:free | 9930 | 9.93 | -| factorial | openai/gpt-3.5-turbo | 744 | 0.74 | -| factorial | openai/gpt-4o-mini | 747 | 0.75 | -| factorial | openrouter/quasar-alpha | 805 | 0.81 | -| factorial | deepseek/deepseek-r1-distill-qwen-14b:free | 5699 | 5.70 | -| fibonacci | openai/gpt-4o-mini | 722 | 0.72 | -| fibonacci | openai/gpt-3.5-turbo | 838 | 0.84 | -| fibonacci | openrouter/quasar-alpha | 1808 | 1.81 | -| fibonacci | deepseek/deepseek-r1-distill-qwen-14b:free | 7725 | 7.72 | -| square_root | openai/gpt-4o-mini | 782 | 0.78 | -| square_root | openai/gpt-3.5-turbo | 999 | 1.00 | -| square_root | openrouter/quasar-alpha | 1230 | 1.23 | -| square_root | deepseek/deepseek-r1-distill-qwen-14b:free | 10070 | 10.07 | -| power | openrouter/quasar-alpha | 717 | 0.72 | -| power | openai/gpt-4o-mini | 848 | 0.85 | -| power | openai/gpt-3.5-turbo | 852 | 0.85 | -| power | deepseek/deepseek-r1-distill-qwen-14b:free | 3915 | 3.92 | +| quadratic | openrouter/quasar-alpha | 957 | 0.96 | +| quadratic | openai/gpt-4o-mini | 1049 | 1.05 | +| quadratic | openai/gpt-3.5-turbo | 1532 | 1.53 | +| quadratic | deepseek/deepseek-r1-distill-qwen-14b:free | 15216 | 15.22 | +| factorial | openrouter/quasar-alpha | 869 | 0.87 | +| factorial | openai/gpt-3.5-turbo | 1188 | 1.19 | +| factorial | openai/gpt-4o-mini | 1226 | 1.23 | +| factorial | deepseek/deepseek-r1-distill-qwen-14b:free | 6695 | 6.70 | +| fibonacci | openai/gpt-3.5-turbo | 726 | 0.73 | +| fibonacci | openai/gpt-4o-mini | 791 | 0.79 | +| fibonacci | openrouter/quasar-alpha | 1023 | 1.02 | +| fibonacci | deepseek/deepseek-r1-distill-qwen-14b:free | 4375 | 4.38 | +| square_root | openrouter/quasar-alpha | 780 | 0.78 | +| square_root | openai/gpt-3.5-turbo | 1012 | 1.01 | +| square_root | openai/gpt-4o-mini | 1031 | 1.03 | +| square_root | deepseek/deepseek-r1-distill-qwen-14b:free | 1923 | 1.92 | +| power | openai/gpt-3.5-turbo | 836 | 0.84 | +| power | openrouter/quasar-alpha | 861 | 0.86 | +| power | openai/gpt-4o-mini | 935 | 0.94 | +| power | deepseek/deepseek-r1-distill-qwen-14b:free | 4854 | 4.85 | ## Summary - Total Tests: 20 -- Passed: 15 -- Failed: 5 -- Success Rate: 75.00% -- Average Duration: 2578ms (2.58s) +- Passed: 14 +- Failed: 6 +- Success Rate: 70.00% +- Average Duration: 2394ms (2.39s) ## Failed Tests @@ -42,169 +42,214 @@ - Prompt: `Solve the quadratic equation x² + 5x + 6 = 0. Return only the solutions as comma-separated numbers, no explanation.` - Expected: `-2,-3` - Actual: `-2, -3` -- Duration: 1248ms (1.25s) +- Duration: 1532ms (1.53s) - Reason: Expected -2,-3, but got -2, -3 -- Timestamp: 4/6/2025, 4:35:35 PM +- Timestamp: 4/6/2025, 5:29:38 PM + +### quadratic - deepseek/deepseek-r1-distill-qwen-14b:free + +- Prompt: `Solve the quadratic equation x² + 5x + 6 = 0. Return only the solutions as comma-separated numbers, no explanation.` +- Expected: `-2,-3` +- Actual: `The solutions to the equation x² + 5x + 6 = 0 are -2 and -3. + +-2, -3 + +**Step-by-Step Explanation:** + +1. **Identify the coefficients:** The quadratic equation is x² + 5x + 6 = 0, so a = 1, b = 5, c = 6. + +2. **Factor the quadratic equation:** Look for two numbers that multiply to 6 (the constant term, c) and add up to 5 (the coefficient of the x term, b). These numbers are 2 and 3. + +3. **Write the factored form:** Using these numbers, the equation can be rewritten as (x + 2)(x + 3) = 0. + +4. **Apply the Zero Product Property:** Set each factor equal to zero: + - x + 2 = 0 ⇒ x = -2 + - x + 3 = 0 ⇒ x = -3 + +5. **Confirm with the Quadratic Formula:** As an alternative, using the quadratic formula x = (-b ± √(b² - 4ac)) / (2a): + - Calculate the discriminant: D = 5² - 4*1*6 = 25 - 24 = 1. + - Plug into the formula: x = (-5 ± √1)/2, which simplifies to x = (-5 + 1)/2 = -2 and x = (-5 -1)/2 = -3. + +Both methods yield the same solutions: x = -2 and x = -3. + +**Final Solutions:** -2, -3 + +\boxed{-2, -3}` +- Duration: 15216ms (15.22s) +- Reason: Expected -2,-3, but got the solutions to the equation x² + 5x + 6 = 0 are -2 and -3. + +-2, -3 + +**step-by-step explanation:** + +1. **identify the coefficients:** the quadratic equation is x² + 5x + 6 = 0, so a = 1, b = 5, c = 6. + +2. **factor the quadratic equation:** look for two numbers that multiply to 6 (the constant term, c) and add up to 5 (the coefficient of the x term, b). these numbers are 2 and 3. + +3. **write the factored form:** using these numbers, the equation can be rewritten as (x + 2)(x + 3) = 0. + +4. **apply the zero product property:** set each factor equal to zero: + - x + 2 = 0 ⇒ x = -2 + - x + 3 = 0 ⇒ x = -3 + +5. **confirm with the quadratic formula:** as an alternative, using the quadratic formula x = (-b ± √(b² - 4ac)) / (2a): + - calculate the discriminant: d = 5² - 4*1*6 = 25 - 24 = 1. + - plug into the formula: x = (-5 ± √1)/2, which simplifies to x = (-5 + 1)/2 = -2 and x = (-5 -1)/2 = -3. + +both methods yield the same solutions: x = -2 and x = -3. + +**final solutions:** -2, -3 + +\boxed{-2, -3} +- Timestamp: 4/6/2025, 5:29:53 PM ### quadratic - openai/gpt-4o-mini - Prompt: `Solve the quadratic equation x² + 5x + 6 = 0. Return only the solutions as comma-separated numbers, no explanation.` - Expected: `-2,-3` - Actual: `-2, -3` -- Duration: 1074ms (1.07s) +- Duration: 1049ms (1.05s) - Reason: Expected -2,-3, but got -2, -3 -- Timestamp: 4/6/2025, 4:35:46 PM +- Timestamp: 4/6/2025, 5:29:54 PM + +### quadratic - openrouter/quasar-alpha + +- Prompt: `Solve the quadratic equation x² + 5x + 6 = 0. Return only the solutions as comma-separated numbers, no explanation.` +- Expected: `-2,-3` +- Actual: `-2, -3` +- Duration: 957ms (0.96s) +- Reason: Expected -2,-3, but got -2, -3 +- Timestamp: 4/6/2025, 5:29:55 PM ### fibonacci - deepseek/deepseek-r1-distill-qwen-14b:free - Prompt: `Calculate the 6th number in the Fibonacci sequence. Return only the number, no explanation.` - Expected: `8` -- Actual: `The sixth number in the Fibonacci sequence is 5. - -Answer: 5` -- Duration: 7725ms (7.72s) -- Reason: Expected 8, but got the sixth number in the fibonacci sequence is 5. - -answer: 5 -- Timestamp: 4/6/2025, 4:36:03 PM +- Actual: `5` +- Duration: 4375ms (4.38s) +- Reason: Expected 8, but got 5 +- Timestamp: 4/6/2025, 5:30:10 PM ### fibonacci - openai/gpt-4o-mini - Prompt: `Calculate the 6th number in the Fibonacci sequence. Return only the number, no explanation.` - Expected: `8` - Actual: `5` -- Duration: 722ms (0.72s) +- Duration: 791ms (0.79s) - Reason: Expected 8, but got 5 -- Timestamp: 4/6/2025, 4:36:04 PM - -### power - deepseek/deepseek-r1-distill-qwen-14b:free - -- Prompt: `Calculate 2 raised to the power of 3. Return only the number, no explanation.` -- Expected: `8` -- Actual: `The answer is 8.` -- Duration: 3915ms (3.92s) -- Reason: Expected 8, but got the answer is 8. -- Timestamp: 4/6/2025, 4:36:24 PM +- Timestamp: 4/6/2025, 5:30:11 PM ## Passed Tests -### quadratic - deepseek/deepseek-r1-distill-qwen-14b:free - -- Prompt: `Solve the quadratic equation x² + 5x + 6 = 0. Return only the solutions as comma-separated numbers, no explanation.` -- Expected: `-2,-3` -- Actual: `-2,-3` -- Duration: 9930ms (9.93s) -- Timestamp: 4/6/2025, 4:35:45 PM - -### quadratic - openrouter/quasar-alpha - -- Prompt: `Solve the quadratic equation x² + 5x + 6 = 0. Return only the solutions as comma-separated numbers, no explanation.` -- Expected: `-2,-3` -- Actual: `-2,-3` -- Duration: 811ms (0.81s) -- Timestamp: 4/6/2025, 4:35:46 PM - ### factorial - openai/gpt-3.5-turbo - Prompt: `Calculate 5! (factorial of 5). Return only the number, no explanation.` - Expected: `120` - Actual: `120` -- Duration: 744ms (0.74s) -- Timestamp: 4/6/2025, 4:35:47 PM +- Duration: 1188ms (1.19s) +- Timestamp: 4/6/2025, 5:29:56 PM ### factorial - deepseek/deepseek-r1-distill-qwen-14b:free - Prompt: `Calculate 5! (factorial of 5). Return only the number, no explanation.` - Expected: `120` - Actual: `120` -- Duration: 5699ms (5.70s) -- Timestamp: 4/6/2025, 4:35:53 PM +- Duration: 6695ms (6.70s) +- Timestamp: 4/6/2025, 5:30:03 PM ### factorial - openai/gpt-4o-mini - Prompt: `Calculate 5! (factorial of 5). Return only the number, no explanation.` - Expected: `120` - Actual: `120` -- Duration: 747ms (0.75s) -- Timestamp: 4/6/2025, 4:35:54 PM +- Duration: 1226ms (1.23s) +- Timestamp: 4/6/2025, 5:30:04 PM ### factorial - openrouter/quasar-alpha - Prompt: `Calculate 5! (factorial of 5). Return only the number, no explanation.` - Expected: `120` - Actual: `120` -- Duration: 805ms (0.81s) -- Timestamp: 4/6/2025, 4:35:54 PM +- Duration: 869ms (0.87s) +- Timestamp: 4/6/2025, 5:30:05 PM ### fibonacci - openai/gpt-3.5-turbo - Prompt: `Calculate the 6th number in the Fibonacci sequence. Return only the number, no explanation.` - Expected: `8` - Actual: `8` -- Duration: 838ms (0.84s) -- Timestamp: 4/6/2025, 4:35:55 PM +- Duration: 726ms (0.73s) +- Timestamp: 4/6/2025, 5:30:06 PM ### fibonacci - openrouter/quasar-alpha - Prompt: `Calculate the 6th number in the Fibonacci sequence. Return only the number, no explanation.` - Expected: `8` - Actual: `8` -- Duration: 1808ms (1.81s) -- Timestamp: 4/6/2025, 4:36:06 PM +- Duration: 1023ms (1.02s) +- Timestamp: 4/6/2025, 5:30:12 PM ### square_root - openai/gpt-3.5-turbo - Prompt: `Calculate the square root of 16. Return only the number, no explanation.` - Expected: `4` - Actual: `4` -- Duration: 999ms (1.00s) -- Timestamp: 4/6/2025, 4:36:07 PM +- Duration: 1012ms (1.01s) +- Timestamp: 4/6/2025, 5:30:13 PM ### square_root - deepseek/deepseek-r1-distill-qwen-14b:free - Prompt: `Calculate the square root of 16. Return only the number, no explanation.` - Expected: `4` - Actual: `4` -- Duration: 10070ms (10.07s) -- Timestamp: 4/6/2025, 4:36:17 PM +- Duration: 1923ms (1.92s) +- Timestamp: 4/6/2025, 5:30:15 PM ### square_root - openai/gpt-4o-mini - Prompt: `Calculate the square root of 16. Return only the number, no explanation.` - Expected: `4` - Actual: `4` -- Duration: 782ms (0.78s) -- Timestamp: 4/6/2025, 4:36:18 PM +- Duration: 1031ms (1.03s) +- Timestamp: 4/6/2025, 5:30:16 PM ### square_root - openrouter/quasar-alpha - Prompt: `Calculate the square root of 16. Return only the number, no explanation.` - Expected: `4` - Actual: `4` -- Duration: 1230ms (1.23s) -- Timestamp: 4/6/2025, 4:36:19 PM +- Duration: 780ms (0.78s) +- Timestamp: 4/6/2025, 5:30:17 PM ### power - openai/gpt-3.5-turbo - Prompt: `Calculate 2 raised to the power of 3. Return only the number, no explanation.` - Expected: `8` - Actual: `8` -- Duration: 852ms (0.85s) -- Timestamp: 4/6/2025, 4:36:20 PM +- Duration: 836ms (0.84s) +- Timestamp: 4/6/2025, 5:30:18 PM + +### power - deepseek/deepseek-r1-distill-qwen-14b:free + +- Prompt: `Calculate 2 raised to the power of 3. Return only the number, no explanation.` +- Expected: `8` +- Actual: `8` +- Duration: 4854ms (4.85s) +- Timestamp: 4/6/2025, 5:30:22 PM ### power - openai/gpt-4o-mini - Prompt: `Calculate 2 raised to the power of 3. Return only the number, no explanation.` - Expected: `8` - Actual: `8` -- Duration: 848ms (0.85s) -- Timestamp: 4/6/2025, 4:36:24 PM +- Duration: 935ms (0.94s) +- Timestamp: 4/6/2025, 5:30:23 PM ### power - openrouter/quasar-alpha - Prompt: `Calculate 2 raised to the power of 3. Return only the number, no explanation.` - Expected: `8` - Actual: `8` -- Duration: 717ms (0.72s) -- Timestamp: 4/6/2025, 4:36:25 PM +- Duration: 861ms (0.86s) +- Timestamp: 4/6/2025, 5:30:24 PM