{"_id":"@armagank/llmrest","_rev":"6-620eda8ea1379ae5866ce5691232ccfd","name":"@armagank/llmrest","dist-tags":{"latest":"5.0.3"},"versions":{"1.0.0":{"name":"@armagank/llmrest","version":"1.0.0","keywords":["llmrest"],"author":{"name":"Ekrem Karakas"},"license":"ISC","_id":"@armagank/llmrest@1.0.0","maintainers":[{"name":"armagank","email":"ekremarmagankarakas@gmail.com"}],"homepage":"https://github.com/ekremarmagankarakas/LLMrest#readme","bugs":{"url":"https://github.com/ekremarmagankarakas/LLMrest/issues"},"dist":{"shasum":"e541eb78cc2caf08952bfdadc43094017ce2c8aa","tarball":"https://registry.npmjs.org/@armagank/llmrest/-/llmrest-1.0.0.tgz","fileCount":9,"integrity":"sha512-gUROUgTv3Ir1r0dkb/FAsdKbgfR88qhT1gvIh7852XpjnTZzziek0z+uQW503QMGgIchRKIRehwFNh4ztJt+JA==","signatures":[{"sig":"MEUCIQCB+ueslVBuUJ0dU7T4ldNFyOyvtUtSYwmoWPNyeSW6xgIgZ3M++uVRjWOvDvNTONs3IwK98gmBTGA+TGKcWLSxq8E=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":7820},"main":"index.js","gitHead":"942837d8d45dd620bb6a39f5a04125fe4cbea824","scripts":{"test":"echo \"Error: no test specified\" && exit 1"},"_npmUser":{"name":"armagank","email":"ekremarmagankarakas@gmail.com"},"repository":{"url":"git+https://github.com/ekremarmagankarakas/LLMrest.git","type":"git"},"_npmVersion":"10.8.2","description":"send request to llms","directories":{},"_nodeVersion":"22.5.1","dependencies":{"openai":"^4.73.1","@anthropic-ai/sdk":"^0.20.8","@google/generative-ai":"^0.17.1"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/llmrest_1.0.0_1733033107845_0.39414141360412325","host":"s3://npm-registry-packages"}},"2.0.0":{"name":"@armagank/llmrest","version":"2.0.0","keywords":["llmrest"],"author":{"name":"Ekrem Karakas"},"license":"ISC","_id":"@armagank/llmrest@2.0.0","maintainers":[{"name":"armagank","email":"ekremarmagankarakas@gmail.com"}],"homepage":"https://github.com/ekremarmagankarakas/LLMrest#readme","bugs":{"url":"https://github.com/ekremarmagankarakas/LLMrest/issues"},"dist":{"shasum":"2ee22e947227c1b43665815440ed2867390960d4","tarball":"https://registry.npmjs.org/@armagank/llmrest/-/llmrest-2.0.0.tgz","fileCount":10,"integrity":"sha512-GPM2qnZTd4j3+rFnRVxC5kDfm7ZVI7+o8Woj3iW3j4GoJ/IU0LPKXi7iYPdT9PIS0yyFNBwOjAQcZXf0hznYXQ==","signatures":[{"sig":"MEUCIQD6On1Tx64xsinZE06k0Y2LDM+I5y0To3Fj1a8pQ2G7OQIgYKRh0f/amfFJS/MMyQaFGx1M8wOvYTNP+XouP0mzowI=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":8937},"main":"index.js","gitHead":"0d7fb20e32697623b14de10509856bbd1d1824d5","scripts":{"test":"echo \"Error: no test specified\" && exit 1"},"_npmUser":{"name":"armagank","email":"ekremarmagankarakas@gmail.com"},"repository":{"url":"git+https://github.com/ekremarmagankarakas/LLMrest.git","type":"git"},"_npmVersion":"10.8.2","description":"send request to llms","directories":{},"_nodeVersion":"22.5.1","dependencies":{"openai":"^4.73.1","@anthropic-ai/sdk":"^0.20.8","@google/generative-ai":"^0.17.1"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/llmrest_2.0.0_1733039576992_0.762699894006549","host":"s3://npm-registry-packages"}},"3.0.0":{"name":"@armagank/llmrest","version":"3.0.0","keywords":["llmrest"],"author":{"name":"Ekrem Karakas"},"license":"ISC","_id":"@armagank/llmrest@3.0.0","maintainers":[{"name":"armagank","email":"ekremarmagankarakas@gmail.com"}],"homepage":"https://github.com/ekremarmagankarakas/LLMrest#readme","bugs":{"url":"https://github.com/ekremarmagankarakas/LLMrest/issues"},"dist":{"shasum":"953a7a1fcd2ec1f70ef6a43d23c6980adb73668e","tarball":"https://registry.npmjs.org/@armagank/llmrest/-/llmrest-3.0.0.tgz","fileCount":10,"integrity":"sha512-LLvMY67ucgTl/X9p3hVN1y1QvjPnOEbNaKf3eWXRox6TIefF2Ccu0sJT7ix5snNFkAzqgiBrCdHJnTeTjfrrUw==","signatures":[{"sig":"MEUCIQC+3JMrhAUqvqB7Olg9W4XtkNn37OufoNA3059bTzUQ7wIgO1scp7OqdpXWBcryAwjsS+Nx3hwGVYT9NKkW56aF+Eo=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":9499},"main":"index.js","gitHead":"09f9afc20b61caa1c3850aa8da7e7b188b07cc92","scripts":{"test":"echo \"Error: no test specified\" && exit 1"},"_npmUser":{"name":"armagank","email":"ekremarmagankarakas@gmail.com"},"repository":{"url":"git+https://github.com/ekremarmagankarakas/LLMrest.git","type":"git"},"_npmVersion":"10.8.2","description":"send request to llms","directories":{},"_nodeVersion":"22.5.1","dependencies":{"openai":"^4.73.1","@anthropic-ai/sdk":"^0.20.8","@google/generative-ai":"^0.17.1"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/llmrest_3.0.0_1733552374106_0.07133550633253671","host":"s3://npm-registry-packages"}},"3.0.1":{"name":"@armagank/llmrest","version":"3.0.1","keywords":["llmrest"],"author":{"name":"Ekrem Karakas"},"license":"ISC","_id":"@armagank/llmrest@3.0.1","maintainers":[{"name":"armagank","email":"ekremarmagankarakas@gmail.com"}],"homepage":"https://github.com/ekremarmagankarakas/LLMrest#readme","bugs":{"url":"https://github.com/ekremarmagankarakas/LLMrest/issues"},"dist":{"shasum":"37e37e7864855b07052995ecad2f903c8e7bc735","tarball":"https://registry.npmjs.org/@armagank/llmrest/-/llmrest-3.0.1.tgz","fileCount":11,"integrity":"sha512-3/OhwlB+Fq5JPQ8ouL7QqCI0GrVfCIBBcxj0XkJzEQPpR84jxGui44X9ieMdbzn6O7Iz8ZIUtUAbF6f6FOYcwQ==","signatures":[{"sig":"MEQCIF5A9CO9Sj0Zv1QUi76kYHdBh/atju3v9jtDch2yMv+lAiBA0wdIuSOU+4QljEpxk0xrJ42sC/69Fga55fLLxyGYQQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":19380},"main":"index.js","gitHead":"a2e56134cf98629e1a36478450b8e00360c97cd9","scripts":{"test":"echo \"Error: no test specified\" && exit 1"},"_npmUser":{"name":"armagank","email":"ekremarmagankarakas@gmail.com"},"repository":{"url":"git+https://github.com/ekremarmagankarakas/LLMrest.git","type":"git"},"_npmVersion":"9.2.0","description":"send request to llms","directories":{},"_nodeVersion":"18.19.1","dependencies":{"openai":"^4.73.1","@anthropic-ai/sdk":"^0.20.8","@google/generative-ai":"^0.17.1"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/llmrest_3.0.1_1740700566476_0.37363353670728006","host":"s3://npm-registry-packages-npm-production"}},"4.0.1":{"name":"@armagank/llmrest","version":"4.0.1","keywords":["llmrest"],"author":{"name":"Ekrem Karakas"},"license":"ISC","_id":"@armagank/llmrest@4.0.1","maintainers":[{"name":"armagank","email":"ekremarmagankarakas@gmail.com"}],"homepage":"https://github.com/ekremarmagankarakas/LLMrest#readme","bugs":{"url":"https://github.com/ekremarmagankarakas/LLMrest/issues"},"dist":{"shasum":"4a987ed8c97b41ce68cd595892ce5fe844b2b845","tarball":"https://registry.npmjs.org/@armagank/llmrest/-/llmrest-4.0.1.tgz","fileCount":12,"integrity":"sha512-DLeHszvi7J7N972a6NKduF779tpnqy6S9glhG+8C9OQXdE0nBtHWqQmcU3JI20XHAQHzttFGamBNcepbGTcKRA==","signatures":[{"sig":"MEYCIQDEhzMddFn6z1AHwFkensOwgTUK6X7DQWjkt+TlexCGeQIhALYMZ6GttEe8oPDfN0kDqPUIEbrDuz51HT06VAveAjnm","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":23550},"main":"index.js","gitHead":"b3b9af22345eec46c78ec6cb2fbbd55741b117c0","scripts":{"test":"jest"},"_npmUser":{"name":"armagank","email":"ekremarmagankarakas@gmail.com"},"repository":{"url":"git+https://github.com/ekremarmagankarakas/LLMrest.git","type":"git"},"_npmVersion":"11.4.2","description":"send request to llms","directories":{},"_nodeVersion":"22.15.0","dependencies":{"openai":"^4.73.1","@anthropic-ai/sdk":"^0.20.8","@google/generative-ai":"^0.17.1"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^30.0.0"},"_npmOperationalInternal":{"tmp":"tmp/llmrest_4.0.1_1749817654477_0.8415712924533334","host":"s3://npm-registry-packages-npm-production"}},"5.0.3":{"name":"@armagank/llmrest","version":"5.0.3","description":"Send requests to multiple LLMs concurrently","main":"dist/index.js","types":"dist/index.d.ts","scripts":{"build":"tsc","test":"jest","prepublishOnly":"npm run build"},"repository":{"type":"git","url":"git+https://github.com/ekremarmagankarakas/LLMrest.git"},"keywords":["llmrest","llm","openai","claude","gemini","perplexity"],"author":{"name":"Ekrem Karakas"},"license":"ISC","engines":{"node":">=18.0.0"},"dependencies":{"@anthropic-ai/sdk":"^0.96.0","@google/generative-ai":"^0.24.1","openai":"^6.37.0"},"devDependencies":{"@types/jest":"^29.5.0","@types/node":"^20.0.0","jest":"^29.7.0","ts-jest":"^29.1.0","typescript":"^5.4.0"},"bugs":{"url":"https://github.com/ekremarmagankarakas/LLMrest/issues"},"homepage":"https://github.com/ekremarmagankarakas/LLMrest#readme","gitHead":"886570615a78c2a028c64c7c3a3bf4a439dbfa60","_id":"@armagank/llmrest@5.0.3","_nodeVersion":"26.0.0","_npmVersion":"11.12.1","dist":{"integrity":"sha512-oGt8IEd1FF1L1W6KcRgxLfMDmOuZGPKnxSLLU7MLIc0Eprwx0wE6vhInWPEvtBi0zCaBApVV0qRvuDzuVMqlrg==","shasum":"2d67417f8851643e865662c44e2de6d6f45e0e3c","tarball":"https://registry.npmjs.org/@armagank/llmrest/-/llmrest-5.0.3.tgz","fileCount":54,"unpackedSize":51357,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQCe991h/MDPFQUQjCyESZldpysq08Ph2umHnryU4anZuAIhALNZ9Le8LMHHduIdx771V/CWcXZoKHqbjS551zMCbSuJ"}]},"_npmUser":{"name":"armagank","email":"ekremarmagankarakas@gmail.com"},"directories":{},"maintainers":[{"name":"armagank","email":"ekremarmagankarakas@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/llmrest_5.0.3_1778831727360_0.457458521797137"},"_hasShrinkwrap":false}},"time":{"created":"2024-12-01T06:05:07.786Z","modified":"2026-05-15T07:55:27.629Z","1.0.0":"2024-12-01T06:05:08.031Z","2.0.0":"2024-12-01T07:52:57.156Z","3.0.0":"2024-12-07T06:19:34.296Z","3.0.1":"2025-02-27T23:56:06.633Z","4.0.1":"2025-06-13T12:27:34.647Z","5.0.3":"2026-05-15T07:55:27.523Z"},"bugs":{"url":"https://github.com/ekremarmagankarakas/LLMrest/issues"},"author":{"name":"Ekrem Karakas"},"license":"ISC","homepage":"https://github.com/ekremarmagankarakas/LLMrest#readme","keywords":["llmrest","llm","openai","claude","gemini","perplexity"],"repository":{"type":"git","url":"git+https://github.com/ekremarmagankarakas/LLMrest.git"},"description":"Send requests to multiple LLMs concurrently","maintainers":[{"name":"armagank","email":"ekremarmagankarakas@gmail.com"}],"readme":"# LLMrest\n\nA unified TypeScript library for querying multiple LLM providers concurrently — OpenAI, Anthropic Claude, Google Gemini, and Perplexity — from a single client.\n\n[![npm version](https://img.shields.io/npm/v/@armagank/llmrest.svg)](https://www.npmjs.com/package/@armagank/llmrest)\n[![License: ISC](https://img.shields.io/badge/License-ISC-blue.svg)](https://opensource.org/licenses/ISC)\n\n## Features\n\n- **Concurrent requests** — fan out to multiple models in parallel, results arrive as each completes\n- **Unified interface** — one client, four providers\n- **Per-model messages** — send different prompts to different models in a single call\n- **Streaming callbacks** — responses delivered via `onResponse` as each model finishes\n- **Content moderation** — optional OpenAI moderation check before sending\n- **Input size validation** — optional byte-limit enforcement before sending\n- **Full TypeScript** — complete type definitions included\n- **Extensible** — register custom providers via `ModelRegistry`\n\n## Requirements\n\n- Node.js >= 18.0.0\n\n## Installation\n\n```bash\nnpm install @armagank/llmrest\n```\n\n## Quick Start\n\n```typescript\nimport { LLMClient } from '@armagank/llmrest';\n\nconst client = new LLMClient({\n  apiKeys: {\n    openai: process.env.OPENAI_API_KEY,\n    claude: process.env.ANTHROPIC_API_KEY,\n    gemini: process.env.GEMINI_API_KEY,\n    perplexity: process.env.PERPLEXITY_API_KEY,\n  },\n});\n\n// CommonJS\nconst { createAIClient } = require('@armagank/llmrest');\nconst client = createAIClient({ apiKeys: { ... } });\n```\n\nYou only need to provide API keys for the providers you intend to use.\n\n## API\n\n### `createChat(params)`\n\nSend the same messages to multiple models concurrently.\n\n```typescript\nconst result = await client.createChat({\n  models: ['gpt-4o', 'claude-sonnet-4-6', 'gemini-2.5-flash'],\n  messages: [\n    { role: 'system', content: 'You are a helpful assistant.' },\n    { role: 'user', content: 'What is the capital of France?' },\n  ],\n  maxInput: 100_000,  // bytes (optional)\n  maxOutput: 1_000,   // tokens (optional)\n  moderationEnabled: false,\n});\n\n// result: Record<modelId, string | { error: string }>\nconsole.log(result['gpt-4o']);            // \"The capital of France is Paris.\"\nconsole.log(result['claude-sonnet-4-6']); // \"Paris is the capital of France.\"\n```\n\n| Parameter | Type | Required | Description |\n|---|---|---|---|\n| `models` | `string[]` | Yes | Model IDs to query |\n| `messages` | `Message[]` | Yes | Chat messages |\n| `maxInput` | `number` | No | Max input size in bytes |\n| `maxOutput` | `number` | No | Max output tokens |\n| `moderationEnabled` | `boolean` | No | Run OpenAI content moderation first |\n\n### `createChatMessages(params)`\n\nSend different messages to different models in one call.\n\n```typescript\nconst result = await client.createChatMessages({\n  models: ['gpt-4o', 'claude-sonnet-4-6'],\n  messages: {\n    'gpt-4o': [\n      { role: 'system', content: 'You are a coding assistant.' },\n      { role: 'user', content: 'Write a TypeScript hello world.' },\n    ],\n    'claude-sonnet-4-6': [\n      { role: 'system', content: 'You are a poet.' },\n      { role: 'user', content: 'Write a haiku about TypeScript.' },\n    ],\n  },\n  maxOutput: 500,\n});\n```\n\n### `createChatStreaming(params)`\n\nDispatch requests concurrently; receive each result via callback as it arrives rather than waiting for all to finish.\n\n```typescript\nawait client.createChatStreaming({\n  models: ['gpt-4o', 'claude-sonnet-4-6', 'gemini-2.5-flash'],\n  messages: [{ role: 'user', content: 'Tell me a joke.' }],\n  maxOutput: 300,\n  onResponse: (response) => {\n    if (response.status === 'success') {\n      console.log(`[${response.model}] ${response.data}`);\n    } else {\n      console.error(`[${response.model}] Error: ${response.error}`);\n    }\n  },\n});\n```\n\n`onResponse` receives a `StreamingResponse`:\n\n```typescript\ninterface StreamingResponse {\n  model: string;\n  status: 'success' | 'error';\n  data?: string;   // present on success\n  error?: string;  // present on error\n  timestamp: string;\n}\n```\n\nModel-specific messages also work with streaming:\n\n```typescript\nawait client.createChatStreaming({\n  models: ['gpt-4o', 'claude-sonnet-4-6'],\n  messages: {\n    'gpt-4o': [{ role: 'user', content: 'Explain recursion.' }],\n    'claude-sonnet-4-6': [{ role: 'user', content: 'Explain iteration.' }],\n  },\n  onResponse: (r) => console.log(r),\n});\n```\n\n## Supported Models\n\n### OpenAI\n`gpt-5`, `gpt-5-mini`, `gpt-5-nano`, `gpt-5.1`, `gpt-5.2`, `gpt-5.4`, `gpt-5.4-mini`, `gpt-5.4-nano`, `gpt-4.1`, `gpt-4.1-mini`, `gpt-4.1-nano`, `gpt-4o`, `gpt-4o-mini`, `gpt-4-turbo`, `o1`, `o1-mini`, `o3`, `o3-mini`, `o4-mini`\n\n### Anthropic Claude\n`claude-opus-4-7`, `claude-sonnet-4-6`, `claude-haiku-4-5`, `claude-haiku-4-5-20251001`, `claude-opus-4-6`, `claude-sonnet-4-5`, `claude-opus-4-5`, `claude-opus-4-1`\n\n### Google Gemini\n`gemini-2.5-pro`, `gemini-2.5-flash`, `gemini-2.5-flash-lite`, `gemini-3.1-flash-lite`, `gemini-3-flash-preview`\n\n### Perplexity\n`sonar`, `sonar-pro`, `sonar-reasoning-pro`, `sonar-deep-research`\n\n## Custom Providers\n\nExtend `BaseProvider` to add any model not in the built-in list:\n\n```typescript\nimport { BaseProvider, ModelRegistry } from '@armagank/llmrest';\nimport type { ProviderChatOptions } from '@armagank/llmrest';\n\nclass MyProvider extends BaseProvider {\n  async chat({ messages, maxOutput }: ProviderChatOptions): Promise<string> {\n    // call your API here\n    return 'response text';\n  }\n}\n\nconst registry = new ModelRegistry();\nregistry.registerMany(['my-model-v1', 'my-model-v2'], new MyProvider());\n```\n\n## Error Handling\n\nFailed models never throw — they return an error object in the result map. Only pre-flight errors (bad config, moderation rejection, input too large) throw.\n\n```typescript\nconst result = await client.createChat({\n  models: ['gpt-4o', 'claude-sonnet-4-6'],\n  messages: [{ role: 'user', content: 'Hello' }],\n});\n\nfor (const [model, response] of Object.entries(result)) {\n  if (typeof response === 'string') {\n    console.log(`${model}: ${response}`);\n  } else {\n    console.error(`${model} failed: ${response.error}`);\n  }\n}\n```\n\n## License\n\nISC\n","readmeFilename":"README.md"}