{"id":22917197,"url":"https://github.com/ejfox/vue-use-openrouter","last_synced_at":"2026-02-07T13:30:54.260Z","repository":{"id":267062422,"uuid":"900161509","full_name":"ejfox/vue-use-openrouter","owner":"ejfox","description":null,"archived":false,"fork":false,"pushed_at":"2024-12-08T05:18:35.000Z","size":238,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-10-26T01:39:12.664Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ejfox.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2024-12-08T02:54:30.000Z","updated_at":"2024-12-08T05:18:39.000Z","dependencies_parsed_at":"2024-12-08T04:14:17.372Z","dependency_job_id":"aa4374f6-a143-4056-baef-21620611447d","html_url":"https://github.com/ejfox/vue-use-openrouter","commit_stats":null,"previous_names":["ejfox/vue-use-openrouter"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/ejfox/vue-use-openrouter","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ejfox%2Fvue-use-openrouter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ejfox%2Fvue-use-openrouter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ejfox%2Fvue-use-openrouter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ejfox%2Fvue-use-openrouter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ejfox","download_url":"https://codeload.github.com/ejfox/vue-use-openrouter/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ejfox%2Fvue-use-openrouter/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29195035,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-07T12:38:28.597Z","status":"ssl_error","status_checked_at":"2026-02-07T12:38:23.888Z","response_time":63,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-12-14T06:16:52.819Z","updated_at":"2026-02-07T13:30:54.244Z","avatar_url":"https://github.com/ejfox.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 📦 useOpenRouter\n\nA Vue 3 composable for interacting with OpenRouter's AI models API. Easily integrate multiple AI models (like GPT-4, Claude, etc.) into your Vue applications.\n\n## 🌟 Features\n\n- 🔌 Simple integration with OpenRouter API\n- 🔄 Automatic model switching and management\n- 💰 Built-in cost tracking and token usage\n- 🧠 Temperature control for response creativity\n- 📝 Full conversation history management\n- 🔒 Type-safe with full TypeScript support\n- ⚡ Powered by Vue 3's Composition API\n\n## 📦 Installation\n\n```bash\n# npm\nnpm install use-openrouter\n\n# yarn\nyarn add use-openrouter\n\n# pnpm\npnpm add use-openrouter\n```\n\n## 🚀 Quick Start\n\n```ts\nimport { useOpenRouter } from 'use-openrouter'\n\n// Initialize with your API key\nconst chat = useOpenRouter({\n  apiKey: 'your-api-key',\n  defaultModel: 'anthropic/claude-3-sonnet'\n})\n\n// Send messages and get responses\nawait chat.sendMessage('What is quantum computing?')\nconsole.log(chat.messages.value.at(-1)?.content)\n\n// Track costs\nconsole.log(`Cost: $${chat.chatStats.value.totalCost}`)\n```\n\n## 📖 Usage Guide\n\n### Basic Chat\n\n```ts\nconst chat = useOpenRouter({ apiKey: 'your-api-key' })\n\n// Send a message\nawait chat.sendMessage('Hello AI!')\n\n// Get all messages\nconsole.log(chat.messages.value)\n// [\n//   { role: 'user', content: 'Hello AI!' },\n//   { role: 'assistant', content: 'Hello! How can I help...' }\n// ]\n```\n\n### Switching Models\n\n```ts\n// Get available models\nawait chat.fetchAvailableModels()\n\n// Switch to a different model\nchat.setModel('openai/gpt-4-turbo')\n\n// Check model costs\nconst cost = chat.formatModelCost(chat.currentModel.value)\nconsole.log(`This model costs ${cost} per million tokens`)\n```\n\n### Temperature Control\n\n```ts\n// For creative tasks (more random)\nchat.updateTemperature(1.0)\nawait chat.sendMessage('Write a creative story')\n\n// For factual tasks (more focused)\nchat.updateTemperature(0.1)\nawait chat.sendMessage('What is 123 * 456?')\n```\n\n### Cost Tracking\n\n```ts\n// Track conversation costs\nconsole.log(chat.chatStats.value)\n// {\n//   tokens: 150,\n//   promptTokens: 50,\n//   completionTokens: 100,\n//   cost: 0.002,\n//   totalCost: 0.002\n// }\n\n// Format costs nicely\nconst cost = chat.formatModelCost('anthropic/claude-3-opus')\nconsole.log(cost) // \"$15.00\"\n```\n\n### Error Handling\n\n```ts\ntry {\n  await chat.sendMessage('Hello')\n} catch (err) {\n  if (chat.error.value?.includes('401')) {\n    console.log('Invalid API key')\n  } else if (chat.error.value?.includes('429')) {\n    console.log('Rate limited - wait a bit')\n  }\n}\n```\n\n## 🛠️ API Reference\n\n### Configuration\n\n```ts\ninterface OpenRouterOptions {\n  apiKey?: string          // Your OpenRouter API key\n  temperature?: number     // Initial temperature (0-1)\n  defaultModel?: string    // Starting model\n  enabledModels?: string[] // List of allowed models\n}\n```\n\n### Properties\n\n- `messages` - Conversation history\n- `isLoading` - Request status\n- `error` - Error messages\n- `currentModel` - Active model ID\n- `modelName` - Active model display name\n- `chatStats` - Token and cost tracking\n- `temperature` - Current temperature setting\n\n### Methods\n\n- `sendMessage(content: string)` - Send a message\n- `setModel(modelId: string)` - Switch models\n- `updateTemperature(value: number)` - Adjust temperature\n- `clearChat()` - Reset conversation\n- `fetchAvailableModels()` - Get model list\n\n## 📄 License\n\nMIT License © 2024\n\n## 💡 Design Philosophy\n\nWe've carefully designed this composable to handle all the tricky parts of working with AI APIs:\n\n### 🛡️ Built-in Safeguards\n\n- Temperature is automatically clamped between 0-1\n- Empty messages are rejected\n- API key validation before requests\n- Proper cleanup on component unmount\n- SSR-safe window usage\n\n### ���� Smart Cost Management\n\n- Automatic token counting\n- Running cost totals\n- Smart decimal formatting (more decimals for cheap models)\n- Cost-based model sorting (expensive → cheap)\n- Free model detection\n\n### 🔄 State Management\n\n- Readonly refs where appropriate\n- Automatic model fetching when API key changes\n- Recent models tracking (last 10 used)\n- Conversation history management\n- Proper error state handling\n\n### 🎯 Developer Experience\n\n```ts\n// Everything is typed!\nconst chat = useOpenRouter({\n  apiKey: 'key',\n  temperature: 0.7,\n  defaultModel: 'anthropic/claude-3-sonnet',\n  enabledModels: ['anthropic/claude-3-sonnet', 'openai/gpt-4']\n})\n\n// Costs are always formatted nicely\nchat.formatModelCost('openai/gpt-3.5-turbo') // \"$0.00200\"\nchat.formatModelCost('anthropic/claude-3-opus') // \"$15.00\"\n\n// Models are sorted by cost (expensive first)\nchat.enabledModels.value.forEach(model =\u003e {\n  console.log(`${model.name}: ${chat.formatModelCost(model.id)}`)\n})\n\n// Track all your costs\nconsole.log(chat.chatStats.value)\n// {\n//   tokens: 1500,\n//   promptTokens: 500,    // Input tokens\n//   completionTokens: 1000, // Output tokens\n//   cost: 0.015,          // Current conversation\n//   totalCost: 0.045      // All conversations\n// }\n```\n\n### 🔍 Edge Cases We Handle\n\n- Rate limiting detection\n- Invalid API keys\n- Empty or malformed responses\n- Context length limits\n- Model availability changes\n- Token counting edge cases\n- Cost calculation precision\n- SSR compatibility\n- Component unmounting\n- Type safety throughout\n\n### 🎨 Flexibility\n\n- Use any OpenRouter model\n- Customize temperature per request\n- Track costs across conversations\n- Enable/disable specific models\n- Monitor token usage\n- Handle errors your way\n- Full TypeScript support\n\nWe've aimed to create a composable that's both powerful and pleasant to use, handling all the complex bits while keeping the API clean and intuitive.\n\n## 📚 Documentation\n\nFull API documentation is available at [https://your-username.github.io/use-openrouter/](https://your-username.github.io/use-openrouter/)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fejfox%2Fvue-use-openrouter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fejfox%2Fvue-use-openrouter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fejfox%2Fvue-use-openrouter/lists"}