{"id":28122751,"url":"https://github.com/fireproof-storage/call-ai","last_synced_at":"2025-05-14T08:14:44.605Z","repository":{"id":283567454,"uuid":"952190786","full_name":"fireproof-storage/call-ai","owner":"fireproof-storage","description":"Simple helper function for streaming AI chat with JSON Schema","archived":false,"fork":false,"pushed_at":"2025-05-13T21:55:32.000Z","size":2434,"stargazers_count":2,"open_issues_count":2,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-05-13T23:08:55.937Z","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":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/fireproof-storage.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"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":"2025-03-20T22:02:09.000Z","updated_at":"2025-05-13T21:55:36.000Z","dependencies_parsed_at":"2025-03-20T23:26:59.674Z","dependency_job_id":"772e6ee3-1668-4365-9196-d073fc48b3c2","html_url":"https://github.com/fireproof-storage/call-ai","commit_stats":null,"previous_names":["fireproof-storage/call-ai"],"tags_count":18,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fireproof-storage%2Fcall-ai","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fireproof-storage%2Fcall-ai/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fireproof-storage%2Fcall-ai/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fireproof-storage%2Fcall-ai/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fireproof-storage","download_url":"https://codeload.github.com/fireproof-storage/call-ai/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254057677,"owners_count":22007544,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":"2025-05-14T08:14:43.189Z","updated_at":"2025-05-14T08:14:44.596Z","avatar_url":"https://github.com/fireproof-storage.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# call-ai\n\nA lightweight library for making AI API calls with streaming support.\n\n## Installation\n\n```bash\nnpm install call-ai\n# or\nyarn add call-ai\n# or\npnpm add call-ai\n```\n\n## Usage\n\n```typescript\nimport { callAi } from 'call-ai';\n\n// Basic usage with string prompt (non-streaming by default)\nconst response = await callAi('Explain quantum computing in simple terms', {\n  apiKey: 'your-api-key',\n  model: 'gpt-4'\n});\n\n// The response is the complete text\nconsole.log(response);\n\n// With streaming enabled (returns an AsyncGenerator)\nconst generator = callAi('Tell me a story', {\n  apiKey: 'your-api-key',\n  model: 'gpt-4',\n  stream: true\n});\n\n// Process streaming updates\nfor await (const chunk of generator) {\n  console.log(chunk); // Streaming updates as they arrive\n}\n\n// Using message array for more control\nconst messages = [\n  { role: 'system', content: 'You are a helpful assistant.' },\n  { role: 'user', content: 'Explain quantum computing in simple terms' }\n];\n\nconst response = await callAi(messages, {\n  apiKey: 'your-api-key',\n  model: 'gpt-4'\n});\n\nconsole.log(response);\n\n// Using schema for structured output\nconst schema = {\n  name: \"exercise_summary\",\n  properties: {\n    title: { type: 'string' },\n    summary: { type: 'string' },\n    points: { type: 'array', items: { type: 'string' } }\n  },\n  required: ['title', 'summary']\n};\n\nconst response = await callAi('Summarize the benefits of exercise', {\n  apiKey: 'your-api-key',\n  schema: schema\n});\n\nconst structuredOutput = JSON.parse(response);\nconsole.log(structuredOutput.title);\n\n// Streaming with schema for OpenRouter structured JSON output\nconst schema = {\n  properties: {\n    title: { type: 'string' },\n    items: { \n      type: 'array', \n      items: { \n        type: 'object',\n        properties: {\n          name: { type: 'string' },\n          description: { type: 'string' }\n        }\n      } \n    }\n  }\n};\n\nconst generator = callAi('Create a list of sci-fi books', {\n  apiKey: 'your-api-key',\n  stream: true,\n  schema: schema\n});\n\nfor await (const chunk of generator) {\n  console.log(chunk); // Shows the partial JSON as it's being generated\n}\n```\n\n## Features\n\n- 🔄 Streaming responses via AsyncGenerator when `stream: true`\n- 🧩 Structured JSON outputs with schema validation\n- 🔌 Full compatibility with OpenRouter's JSON schema format for structured outputs\n- 📝 Support for message arrays with system, user, and assistant roles\n- 🔧 TypeScript support with full type definitions\n- ✅ Works in Node.js and browser environments\n\n## Supported LLM Providers\n\nCall-AI supports all models available through OpenRouter, including:\n\n- OpenAI models (GPT-4, GPT-3.5, etc.)\n- Anthropic Claude\n- Gemini\n- Llama 3\n- Mistral\n- And many more\n\n## Choosing a model\n\nDifferent LLMs have different strengths when working with structured data. Based on our testing, here's a guide to help you choose the right model for your schema needs:\n\n### Schema Complexity Guide\n\n| Model Family | Grade | Simple Flat Schema | Complex Flat Schema | Nested Schema | Best For |\n|--------------|-------|-------------------|---------------------|---------------|----------|\n| OpenAI       | A     | ✅ Excellent      | ✅ Excellent        | ✅ Excellent  | Most reliable for all schema types |\n| Gemini       | A     | ✅ Excellent      | ✅ Excellent        | ✅ Good       | Good all-around performance, especially with flat schemas |\n| Claude       | B     | ✅ Excellent      | ⚠️ Good (occasional JSON errors) | ✅ Good | Simple schemas, robust handling of complex prompts |\n| Llama 3      | C     | ✅ Good           | ✅ Good             | ❌ Poor       | Simpler flat schemas, may struggle with nested structures |\n| Deepseek     | C     | ✅ Good           | ✅ Good             | ❌ Poor       | Basic flat schemas only |\n\n### Schema Structure Recommendations\n\n1. **Flat schemas perform better across all models**. If you need maximum compatibility, avoid deeply nested structures.\n\n2. **Field names matter**. Some models have preferences for certain property naming patterns:\n   - Use simple, common naming patterns like `name`, `type`, `items`, `price` \n   - Avoid deeply nested object hierarchies (more than 2 levels deep)\n   - Keep array items simple (strings or flat objects)\n\n3. **Model-specific considerations**:\n   - **OpenAI models**: Best overall schema adherence and handle complex nesting well\n   - **Claude models**: Great for simple schemas, occasional JSON formatting issues with complex structures\n   - **Gemini models**: Good general performance, handles array properties well\n   - **Llama/Mistral/Deepseek**: Strong with flat schemas, but often ignore nesting structure and provide their own organization\n\n4. **For mission-critical applications** requiring schema adherence, use OpenAI models or implement fallback mechanisms.\n\n## Setting API Keys\n\nYou can provide your API key in three ways:\n\n1. Directly in the options:\n```typescript\nconst response = await callAi('Hello', { apiKey: 'your-api-key' });\n```\n\n2. Set globally in the browser:\n```typescript\nwindow.CALLAI_API_KEY = 'your-api-key';\nconst response = await callAi('Hello');\n```\n\n3. Use environment variables in Node.js (with a custom implementation):\n```typescript\n// Example of environment variable integration\nimport { callAi } from 'call-ai';\nconst apiKey = process.env.OPENAI_API_KEY || process.env.OPENROUTER_API_KEY;\nconst response = await callAi('Hello', { apiKey });\n```\n\n## API\n\n```typescript\n// Main function\nfunction callAi(\n  prompt: string | Message[],\n  options?: CallAIOptions\n): Promise\u003cstring\u003e | AsyncGenerator\u003cstring, string, unknown\u003e\n\n// Types\ntype Message = {\n  role: 'user' | 'system' | 'assistant';\n  content: string;\n};\n\ninterface Schema {\n  /**\n   * Optional schema name that will be sent to the model provider if supported\n   */\n  name?: string;\n  properties: Record\u003cstring, any\u003e;\n  required?: string[];\n  additionalProperties?: boolean;\n}\n\ninterface CallAIOptions {\n  apiKey?: string;\n  model?: string;\n  endpoint?: string;\n  stream?: boolean;\n  schema?: Schema | null;\n  [key: string]: any;\n}\n```\n\n### Options\n\n* `apiKey`: Your API key (can also be set via window.CALLAI_API_KEY)\n* `model`: Model identifier (default: 'openrouter/auto')\n* `endpoint`: API endpoint (default: 'https://openrouter.ai/api/v1/chat/completions')\n* `stream`: Enable streaming responses (default: false)\n* `schema`: Optional JSON schema for structured output\n* Any other options are passed directly to the API (temperature, max_tokens, etc.)\n\n## License\n\nMIT or Apache-2.0, at your option\n\n## Contributing and Release Process\n\n### Development\n\n1. Fork the repository\n2. Make your changes\n3. Add tests for new functionality\n4. Run tests: `npm test`\n5. Run type checking: `npm run typecheck`\n6. Create a pull request\n\n### Integration Tests\n\nThe project includes integration tests that make real API calls to verify functionality with actual LLM models:\n\n1. Copy `.env.example` to `.env` and add your OpenRouter API key\n2. Run integration tests: `npm run test:integration`\n\nNote: Integration tests are excluded from the normal test suite to avoid making API calls during CI/CD. They require a valid API key to execute and will be skipped if no key is provided.\n\n### Release Process\n\nThis library uses GitHub Actions to automate the release process:\n\n1. Update the version in `package.json` (follow semver)\n2. Update `CHANGELOG.md` with details of changes\n3. Commit changes: `git commit -am \"Release vX.Y.Z\"`\n4. Create a git tag: `git tag -a vX.Y.Z -m \"Version X.Y.Z\"`\n5. Push changes and tag: `git push origin main vX.Y.Z`\n\nThe GitHub workflow in `.github/workflows/publish.yml` will:\n- Automatically trigger when a new tag is pushed\n- Run tests and type checking\n- Verify the tag signature\n- Publish the package to npm\n\nWhen making significant changes, remember to:\n- Document breaking changes in the changelog\n- Update documentation to reflect API changes\n- Update TypeScript types","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffireproof-storage%2Fcall-ai","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffireproof-storage%2Fcall-ai","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffireproof-storage%2Fcall-ai/lists"}