{"_id":"@arulcornelious/ngx-ai","_rev":"8-bc8493ae8071466b3af35876e6a89208","name":"@arulcornelious/ngx-ai","dist-tags":{"latest":"1.0.0"},"versions":{"0.1.0":{"name":"@arulcornelious/ngx-ai","version":"0.1.0","keywords":["angular","openai","grok","xai","llm","ai","chatgpt","chat-completions","streaming","rxjs","typescript"],"author":{"url":"https://arulcornelious.com","name":"Arul Cornelious","email":"arulcornelious@gmail.com"},"license":"MIT","_id":"@arulcornelious/ngx-ai@0.1.0","maintainers":[{"name":"arulcornelious","email":"arulcornelious@gmail.com"}],"homepage":"https://github.com/arul1998/ngx-ai#readme","bugs":{"url":"https://github.com/arul1998/ngx-ai/issues"},"dist":{"shasum":"773f567e66001a7b640b06c0f092f3f9d2948a94","tarball":"https://registry.npmjs.org/@arulcornelious/ngx-ai/-/ngx-ai-0.1.0.tgz","fileCount":6,"integrity":"sha512-reZQNwiy+RYc3e0CfxTy02uZ2sieZ0AuTytBiuzYVC1zyUkDcqq8xvibPO6DBLz0s/5SyyilQFJPVTlrwgcq8w==","signatures":[{"sig":"MEYCIQCOUJTxsbwwhjjULCLk8R1ijtJRqFGz7gDDD5XOicgG4gIhAMGLSil0p+XBU+TKSHhOKa3Lu96hwRXOsU9zEcsmQ+zo","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":43064},"type":"module","module":"fesm2022/arulcornelious-ngx-ai.mjs","exports":{".":{"types":"./types/arulcornelious-ngx-ai.d.ts","default":"./fesm2022/arulcornelious-ngx-ai.mjs"},"./package.json":{"default":"./package.json"}},"gitHead":"aab43660d8425de97a217e28b800c79415ded1b3","typings":"types/arulcornelious-ngx-ai.d.ts","_npmUser":{"name":"arulcornelious","email":"arulcornelious@gmail.com"},"repository":{"url":"git+https://github.com/arul1998/ngx-ai.git","type":"git"},"_npmVersion":"11.16.0","description":"RxJS-friendly Angular client for OpenAI-compatible chat APIs (OpenAI, xAI Grok, or your own proxy) with first-class streaming support.","directories":{},"sideEffects":false,"_nodeVersion":"26.3.0","dependencies":{"tslib":"^2.3.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"rxjs":"^6.5.3 || ^7.4.0","@angular/core":">=17.0.0","@angular/common":">=17.0.0"},"_npmOperationalInternal":{"tmp":"tmp/ngx-ai_0.1.0_1785704176976_0.9915631200577617","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@arulcornelious/ngx-ai","version":"0.2.0","keywords":["angular","openai","grok","xai","llm","ai","chatgpt","chat-completions","streaming","rxjs","typescript"],"author":{"url":"https://arulcornelious.com","name":"Arul Cornelious","email":"arulcornelious@gmail.com"},"license":"MIT","_id":"@arulcornelious/ngx-ai@0.2.0","maintainers":[{"name":"arulcornelious","email":"arulcornelious@gmail.com"}],"homepage":"https://github.com/arul1998/ngx-ai#readme","bugs":{"url":"https://github.com/arul1998/ngx-ai/issues"},"dist":{"shasum":"0a20e8b66c12ef0c73707dfed07bdf3aa845e019","tarball":"https://registry.npmjs.org/@arulcornelious/ngx-ai/-/ngx-ai-0.2.0.tgz","fileCount":6,"integrity":"sha512-uAl1OA2/otZ5/XKUSgBHFI7j9dzOduVSqufqNDjtwgWV5pel8wKRkpZgU+i2MxFTBAZrE4aRjIzCFN3FLMM4GA==","signatures":[{"sig":"MEUCIERJH5Zc4WXDt0gk11bR3OCzGxjpVolGF/uB7o7tczV8AiEAi3qLjDgANJ5UPecVqDMTPiWtdKKHMVl4wYu7g/mhPG8=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":58863},"type":"module","module":"fesm2022/arulcornelious-ngx-ai.mjs","exports":{".":{"types":"./types/arulcornelious-ngx-ai.d.ts","default":"./fesm2022/arulcornelious-ngx-ai.mjs"},"./package.json":{"default":"./package.json"}},"gitHead":"b96f8818e0c6f26738eeb1ab959374aac9ae7a08","typings":"types/arulcornelious-ngx-ai.d.ts","_npmUser":{"name":"arulcornelious","email":"arulcornelious@gmail.com"},"repository":{"url":"git+https://github.com/arul1998/ngx-ai.git","type":"git"},"_npmVersion":"11.16.0","description":"RxJS-friendly Angular client for OpenAI-compatible chat APIs (OpenAI, xAI Grok, or your own proxy) with first-class streaming support.","directories":{},"sideEffects":false,"_nodeVersion":"26.3.0","dependencies":{"tslib":"^2.3.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"rxjs":"^6.5.3 || ^7.4.0","@angular/core":">=17.0.0","@angular/common":">=17.0.0"},"_npmOperationalInternal":{"tmp":"tmp/ngx-ai_0.2.0_1787748793942_0.3518649306946122","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@arulcornelious/ngx-ai","version":"0.3.0","keywords":["angular","openai","grok","xai","llm","ai","chatgpt","chat-completions","streaming","rxjs","typescript"],"author":{"url":"https://arulcornelious.com","name":"Arul Cornelious","email":"arulcornelious@gmail.com"},"license":"MIT","_id":"@arulcornelious/ngx-ai@0.3.0","maintainers":[{"name":"arulcornelious","email":"arulcornelious@gmail.com"}],"homepage":"https://github.com/arul1998/ngx-ai#readme","bugs":{"url":"https://github.com/arul1998/ngx-ai/issues"},"dist":{"shasum":"28018b671a102c68e58d7bea3ae03267e2914f44","tarball":"https://registry.npmjs.org/@arulcornelious/ngx-ai/-/ngx-ai-0.3.0.tgz","fileCount":6,"integrity":"sha512-EJR1+MvwnzSyKvEAzjDvJCUVuY1Nc022D1Y2EXUhLtqdm07Jq74w92XZXKk3NQ/rxv8ykVL8V2dr51Cp5ocr9g==","signatures":[{"sig":"MEUCIGuV95Eeajyiv/7LgTyCd3D7ttpFTMlSOT6zyIouV6wHAiEAuBHOm/5yEOMUwLVYt5xQm/xixktLiGLD4ZPP3a1orrk=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":77061},"type":"module","module":"fesm2022/arulcornelious-ngx-ai.mjs","exports":{".":{"types":"./types/arulcornelious-ngx-ai.d.ts","default":"./fesm2022/arulcornelious-ngx-ai.mjs"},"./package.json":{"default":"./package.json"}},"gitHead":"1322dbd1c17fc069916385e0a49a140f0eba4456","typings":"types/arulcornelious-ngx-ai.d.ts","_npmUser":{"name":"arulcornelious","email":"arulcornelious@gmail.com"},"repository":{"url":"git+https://github.com/arul1998/ngx-ai.git","type":"git"},"_npmVersion":"11.16.0","description":"RxJS-friendly Angular client for OpenAI-compatible chat APIs (OpenAI, xAI Grok, or your own proxy) with first-class streaming support.","directories":{},"sideEffects":false,"_nodeVersion":"26.3.0","dependencies":{"tslib":"^2.3.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"rxjs":"^6.5.3 || ^7.4.0","@angular/core":">=17.0.0","@angular/common":">=17.0.0"},"_npmOperationalInternal":{"tmp":"tmp/ngx-ai_0.3.0_1787749660916_0.809249463637068","host":"s3://npm-registry-packages-npm-production"}},"0.4.0":{"name":"@arulcornelious/ngx-ai","version":"0.4.0","keywords":["angular","openai","grok","xai","llm","ai","chatgpt","chat-completions","streaming","rxjs","typescript"],"author":{"url":"https://arulcornelious.com","name":"Arul Cornelious","email":"arulcornelious@gmail.com"},"license":"MIT","_id":"@arulcornelious/ngx-ai@0.4.0","maintainers":[{"name":"arulcornelious","email":"arulcornelious@gmail.com"}],"homepage":"https://github.com/arul1998/ngx-ai#readme","bugs":{"url":"https://github.com/arul1998/ngx-ai/issues"},"dist":{"shasum":"a1cd772d6bd5588e5ecfef27f3160cbd93328f7b","tarball":"https://registry.npmjs.org/@arulcornelious/ngx-ai/-/ngx-ai-0.4.0.tgz","fileCount":6,"integrity":"sha512-dcgeXy4Gm2lia3gDVrDsT3lIaWIhJKb6Mb+8vQ9vXkY3eCcXniemTphWP9IY+v1/o2j4oWGX0tnHo3OWVOUW7Q==","signatures":[{"sig":"MEQCID/qAxWs+M3DCe/FiE4CavHtYv22KyLT3BiNLOmwh5QAAiAhFs3ETCplZHYgivNrWY5kp+9ao8bOTqR7DUg5hUtxig==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":81670},"type":"module","module":"fesm2022/arulcornelious-ngx-ai.mjs","exports":{".":{"types":"./types/arulcornelious-ngx-ai.d.ts","default":"./fesm2022/arulcornelious-ngx-ai.mjs"},"./package.json":{"default":"./package.json"}},"gitHead":"70332776ae8ba1b10fb3ccd493b23b95e3b3e292","typings":"types/arulcornelious-ngx-ai.d.ts","_npmUser":{"name":"arulcornelious","email":"arulcornelious@gmail.com"},"repository":{"url":"git+https://github.com/arul1998/ngx-ai.git","type":"git"},"_npmVersion":"11.16.0","description":"RxJS-friendly Angular client for OpenAI-compatible chat APIs (OpenAI, xAI Grok, or your own proxy) with first-class streaming support.","directories":{},"sideEffects":false,"_nodeVersion":"26.3.0","dependencies":{"tslib":"^2.3.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"rxjs":"^6.5.3 || ^7.4.0","@angular/core":">=17.0.0","@angular/common":">=17.0.0"},"_npmOperationalInternal":{"tmp":"tmp/ngx-ai_0.4.0_1787943210522_0.7844584511957802","host":"s3://npm-registry-packages-npm-production"}},"0.5.0":{"name":"@arulcornelious/ngx-ai","version":"0.5.0","keywords":["angular","openai","grok","xai","llm","ai","chatgpt","chat-completions","streaming","rxjs","typescript"],"author":{"url":"https://arulcornelious.com","name":"Arul Cornelious","email":"arulcornelious@gmail.com"},"license":"MIT","_id":"@arulcornelious/ngx-ai@0.5.0","maintainers":[{"name":"arulcornelious","email":"arulcornelious@gmail.com"}],"homepage":"https://github.com/arul1998/ngx-ai#readme","bugs":{"url":"https://github.com/arul1998/ngx-ai/issues"},"dist":{"shasum":"9ec9f0249da88b2171fd89518d3d9fc3c14431c1","tarball":"https://registry.npmjs.org/@arulcornelious/ngx-ai/-/ngx-ai-0.5.0.tgz","fileCount":6,"integrity":"sha512-ih5ycxtVRSn8WacO5StgjzKinXfImEMcb+XLcGxs5++3vDseOuTUy9RNIZpWBmqmqHmvbZ0n/v3L+NH1zx7mRw==","signatures":[{"sig":"MEQCIBC2ogDYE3YwC8uPhVJAr2J5O/JjAIuU5BkoW0juckaOAiAm0KXO8WiPxmPlI27OA+nZCf3OaE6WXtaepGbh6wor+g==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":88455},"type":"module","module":"fesm2022/arulcornelious-ngx-ai.mjs","exports":{".":{"types":"./types/arulcornelious-ngx-ai.d.ts","default":"./fesm2022/arulcornelious-ngx-ai.mjs"},"./package.json":{"default":"./package.json"}},"gitHead":"bbf903b06511929fa40fc31a9744dec471f20def","typings":"types/arulcornelious-ngx-ai.d.ts","_npmUser":{"name":"arulcornelious","email":"arulcornelious@gmail.com"},"repository":{"url":"git+https://github.com/arul1998/ngx-ai.git","type":"git"},"_npmVersion":"11.16.0","description":"RxJS-friendly Angular client for OpenAI-compatible chat APIs (OpenAI, xAI Grok, or your own proxy) with first-class streaming support.","directories":{},"sideEffects":false,"_nodeVersion":"26.3.0","dependencies":{"tslib":"^2.3.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"rxjs":"^6.5.3 || ^7.4.0","@angular/core":">=17.0.0","@angular/common":">=17.0.0"},"_npmOperationalInternal":{"tmp":"tmp/ngx-ai_0.5.0_1787943828832_0.28788202650577843","host":"s3://npm-registry-packages-npm-production"}},"0.6.0":{"name":"@arulcornelious/ngx-ai","version":"0.6.0","keywords":["angular","openai","grok","xai","llm","ai","chatgpt","chat-completions","streaming","rxjs","typescript"],"author":{"url":"https://arulcornelious.com","name":"Arul Cornelious","email":"arulcornelious@gmail.com"},"license":"MIT","_id":"@arulcornelious/ngx-ai@0.6.0","maintainers":[{"name":"arulcornelious","email":"arulcornelious@gmail.com"}],"homepage":"https://github.com/arul1998/ngx-ai#readme","bugs":{"url":"https://github.com/arul1998/ngx-ai/issues"},"dist":{"shasum":"0ed1868cb5e98e3f41eca94eb61c77d8515d19f2","tarball":"https://registry.npmjs.org/@arulcornelious/ngx-ai/-/ngx-ai-0.6.0.tgz","fileCount":6,"integrity":"sha512-1Wi3K2osZg+JMe6PIHSFk7i9QmXCWHUI2OTFF+f6xdbDo5OkJGQATjZyoTDQwlG0S9jkjEItwQLHbhfwMHMYmA==","signatures":[{"sig":"MEQCIDFQ5NvbiTGR5wrd8BcQnC1CDtG7ROxGcXntklkfVYDjAiBdrSSH6yEP3TNwiZd1vvbsjAKwj+R08GbyJVu6ebxDjA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":88776},"type":"module","module":"fesm2022/arulcornelious-ngx-ai.mjs","exports":{".":{"types":"./types/arulcornelious-ngx-ai.d.ts","default":"./fesm2022/arulcornelious-ngx-ai.mjs"},"./package.json":{"default":"./package.json"}},"gitHead":"807b53c2c7ef1e1823a7ff5ed0923c4c063fe853","typings":"types/arulcornelious-ngx-ai.d.ts","_npmUser":{"name":"arulcornelious","email":"arulcornelious@gmail.com"},"repository":{"url":"git+https://github.com/arul1998/ngx-ai.git","type":"git"},"_npmVersion":"11.16.0","description":"RxJS-friendly Angular client for OpenAI-compatible chat APIs (OpenAI, xAI Grok, or your own proxy) with first-class streaming support.","directories":{},"sideEffects":false,"_nodeVersion":"26.3.0","dependencies":{"tslib":"^2.3.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"rxjs":"^6.5.3 || ^7.4.0","@angular/core":">=17.0.0","@angular/common":">=17.0.0"},"_npmOperationalInternal":{"tmp":"tmp/ngx-ai_0.6.0_1788188084853_0.6079623650606216","host":"s3://npm-registry-packages-npm-production"}},"0.7.0":{"name":"@arulcornelious/ngx-ai","version":"0.7.0","keywords":["angular","openai","grok","xai","llm","ai","chatgpt","chat-completions","streaming","rxjs","typescript"],"author":{"url":"https://arulcornelious.com","name":"Arul Cornelious","email":"arulcornelious@gmail.com"},"license":"MIT","_id":"@arulcornelious/ngx-ai@0.7.0","maintainers":[{"name":"arulcornelious","email":"arulcornelious@gmail.com"}],"homepage":"https://github.com/arul1998/ngx-ai#readme","bugs":{"url":"https://github.com/arul1998/ngx-ai/issues"},"dist":{"shasum":"1b7cda3e1ddcf58268fd7847be4134a79386691a","tarball":"https://registry.npmjs.org/@arulcornelious/ngx-ai/-/ngx-ai-0.7.0.tgz","fileCount":6,"integrity":"sha512-NbhBNLFlxtS5aXB+BeiQccETk6LIZiug+SjiS1/NGxOf/CCJXR4SuSjKXRjPzGCX+VV56YHRqlhcc2UZsgym1A==","signatures":[{"sig":"MEYCIQC/cKd9CMyixM+R1LB2Tb0E+i0P7qKx8KRseFQGmHVzgwIhAMUL/5MHr5EnkL6RwTJhPKaV/XUmaIEtI41UiYF5Pt+0","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":94793},"type":"module","module":"fesm2022/arulcornelious-ngx-ai.mjs","exports":{".":{"types":"./types/arulcornelious-ngx-ai.d.ts","default":"./fesm2022/arulcornelious-ngx-ai.mjs"},"./package.json":{"default":"./package.json"}},"gitHead":"ca082acfbeea17e5380a9b5e8ee0778e74973d9e","typings":"types/arulcornelious-ngx-ai.d.ts","_npmUser":{"name":"arulcornelious","email":"arulcornelious@gmail.com"},"repository":{"url":"git+https://github.com/arul1998/ngx-ai.git","type":"git"},"_npmVersion":"11.16.0","description":"RxJS-friendly Angular client for OpenAI-compatible chat APIs (OpenAI, xAI Grok, or your own proxy) with first-class streaming support.","directories":{},"sideEffects":false,"_nodeVersion":"26.3.0","dependencies":{"tslib":"^2.3.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"rxjs":"^6.5.3 || ^7.4.0","@angular/core":">=17.0.0","@angular/common":">=17.0.0"},"_npmOperationalInternal":{"tmp":"tmp/ngx-ai_0.7.0_1788188572923_0.8452394189839225","host":"s3://npm-registry-packages-npm-production"}},"1.0.0":{"name":"@arulcornelious/ngx-ai","version":"1.0.0","publishConfig":{"access":"public"},"description":"RxJS-friendly Angular client for OpenAI-compatible chat APIs (OpenAI, xAI Grok, or your own proxy) with first-class streaming support.","keywords":["angular","openai","grok","xai","llm","ai","chatgpt","chat-completions","streaming","rxjs","typescript"],"author":{"name":"Arul Cornelious","email":"arulcornelious@gmail.com","url":"https://arulcornelious.com"},"license":"MIT","homepage":"https://github.com/arul1998/ngx-ai#readme","repository":{"type":"git","url":"git+https://github.com/arul1998/ngx-ai.git"},"bugs":{"url":"https://github.com/arul1998/ngx-ai/issues"},"peerDependencies":{"@angular/common":">=17.0.0","@angular/core":">=17.0.0","rxjs":"^6.5.3 || ^7.4.0"},"dependencies":{"tslib":"^2.3.0"},"sideEffects":false,"module":"fesm2022/arulcornelious-ngx-ai.mjs","typings":"types/arulcornelious-ngx-ai.d.ts","exports":{"./package.json":{"default":"./package.json"},".":{"types":"./types/arulcornelious-ngx-ai.d.ts","default":"./fesm2022/arulcornelious-ngx-ai.mjs"}},"type":"module","gitHead":"ea1132772d256691a056c48b5cdc4185ef09e1ef","_id":"@arulcornelious/ngx-ai@1.0.0","_nodeVersion":"26.3.0","_npmVersion":"11.16.0","dist":{"integrity":"sha512-HBEJxg5XnsfUKtdouiJgfxBv6hu/7XNNUmoqQ/jWiCisDbYIeDMnZhQwrTJH22ndhopTgHm477425q1QWsWrtw==","shasum":"0060af40949faf6855c5b2688fa3eda81095420e","tarball":"https://registry.npmjs.org/@arulcornelious/ngx-ai/-/ngx-ai-1.0.0.tgz","fileCount":6,"unpackedSize":95362,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQCOJQqrJr9r5fLEVUlh4H5Chd/1MGviVTjb5esv2tYsHQIgW6i3kPr8ABEXXhWqzROhWfyZLxU9QOqm3ymmqzR8dRs="}]},"_npmUser":{"name":"arulcornelious","email":"arulcornelious@gmail.com"},"directories":{},"maintainers":[{"name":"arulcornelious","email":"arulcornelious@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/ngx-ai_1.0.0_1788346685276_0.3502374928357401"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-02T20:56:16.836Z","modified":"2026-09-02T10:58:05.580Z","0.1.0":"2026-08-02T20:56:17.122Z","0.2.0":"2026-08-26T12:53:14.080Z","0.3.0":"2026-08-26T13:07:41.060Z","0.4.0":"2026-08-28T18:53:30.680Z","0.5.0":"2026-08-28T19:03:48.973Z","0.6.0":"2026-08-31T14:54:44.990Z","0.7.0":"2026-08-31T15:02:53.073Z","1.0.0":"2026-09-02T10:58:05.429Z"},"bugs":{"url":"https://github.com/arul1998/ngx-ai/issues"},"author":{"name":"Arul Cornelious","email":"arulcornelious@gmail.com","url":"https://arulcornelious.com"},"license":"MIT","homepage":"https://github.com/arul1998/ngx-ai#readme","keywords":["angular","openai","grok","xai","llm","ai","chatgpt","chat-completions","streaming","rxjs","typescript"],"repository":{"type":"git","url":"git+https://github.com/arul1998/ngx-ai.git"},"description":"RxJS-friendly Angular client for OpenAI-compatible chat APIs (OpenAI, xAI Grok, or your own proxy) with first-class streaming support.","maintainers":[{"name":"arulcornelious","email":"arulcornelious@gmail.com"}],"readme":"# ngx-ai\n\n[![npm version](https://img.shields.io/npm/v/@arulcornelious/ngx-ai.svg)](https://www.npmjs.com/package/@arulcornelious/ngx-ai)\n[![npm downloads](https://img.shields.io/npm/dm/@arulcornelious/ngx-ai.svg)](https://www.npmjs.com/package/@arulcornelious/ngx-ai)\n[![CI](https://github.com/arul1998/ngx-ai/actions/workflows/ci.yml/badge.svg)](https://github.com/arul1998/ngx-ai/actions/workflows/ci.yml)\n[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](./LICENSE)\n\n**RxJS-friendly Angular client for OpenAI-compatible chat APIs** — OpenAI, xAI Grok, or your own backend proxy — with first-class **streaming**.\n\n- 🅰️ **Angular-native** — a `provideNgxAi()` provider, an injectable service, and a signal-backed `injectAiChat()` store. No modules, no boilerplate.\n- ⚡ **Signals-first** — `injectAiChat()` exposes `messages()`, `response()`, `loading()`, `streaming()` and `error()` as signals your templates react to automatically.\n- 🌊 **Streaming built in** — subscribe to tokens as they arrive; unsubscribe to abort.\n- 🛠️ **Tool calling & structured output** — typed `tools` / `tool_calls` and a `json<T>()` helper for JSON responses.\n- 🔌 **Provider presets** — `openai` and `grok` out of the box, plus `custom` for your proxy.\n- 🧩 **Typed, RxJS-first API** — everything returns `Observable`s that compose with the rest of your app.\n- 🔐 **Safe by default** — refuses to ship an API key to the browser unless you explicitly opt in.\n\n> **Compatibility:** built and CI-tested on Angular 22 (Node 20 & 22). The\n> library uses only APIs available since Angular 16 — signals, `inject`,\n> standalone providers — so the `>=17` peer range is intentionally conservative.\n> Hit a snag on an older version? [Open an issue](https://github.com/arul1998/ngx-ai/issues).\n\n## Installation\n\n```bash\nnpm install @arulcornelious/ngx-ai\n```\n\n## Quick start\n\nRegister the provider once (standalone bootstrap shown):\n\n```ts\nimport { bootstrapApplication } from '@angular/platform-browser';\nimport { provideHttpClient } from '@angular/common/http';\nimport { provideNgxAi } from '@arulcornelious/ngx-ai';\nimport { App } from './app/app';\n\nbootstrapApplication(App, {\n  providers: [\n    provideHttpClient(),\n    // Recommended: route through your own backend so the API key stays server-side.\n    provideNgxAi({ provider: 'custom', baseUrl: '/api/ai' }),\n  ],\n});\n```\n\nInject the service and chat:\n\n```ts\nimport { Component, inject, signal } from '@angular/core';\nimport { NgxAiChatService } from '@arulcornelious/ngx-ai';\n\n@Component({\n  selector: 'app-chat',\n  template: `\n    <button (click)=\"ask()\">Ask</button>\n    <p>{{ answer() }}</p>\n  `,\n})\nexport class ChatComponent {\n  private readonly ai = inject(NgxAiChatService);\n  readonly answer = signal('');\n\n  ask() {\n    this.ai\n      .chat([{ role: 'user', content: 'Explain RxJS in one sentence.' }])\n      .subscribe((res) => this.answer.set(res.content));\n  }\n}\n```\n\n## Streaming\n\n`stream()` emits one chunk per server-sent event and completes when the model is done. Unsubscribing aborts the request.\n\n```ts\nask() {\n  this.answer.set('');\n  this.ai\n    .stream([{ role: 'user', content: 'Write a haiku about Angular.' }])\n    .subscribe({\n      next: (chunk) => this.answer.update((t) => t + chunk.delta),\n      complete: () => console.log('done'),\n    });\n}\n```\n\n## Signals API\n\nPrefer signals over subscriptions? `injectAiChat()` gives you a reactive chat\nstore that manages the conversation for you. Call it from a component (an\ninjection context) and bind straight to the signals — no manual subscribe, and\nin-flight requests are aborted automatically when the component is destroyed.\n\n```ts\nimport { Component } from '@angular/core';\nimport { injectAiChat } from '@arulcornelious/ngx-ai';\n\n@Component({\n  selector: 'app-chat',\n  template: `\n    @for (m of chat.messages(); track $index) {\n      <p>\n        <b>{{ m.role }}:</b> {{ m.content }}\n      </p>\n    }\n    @if (chat.streaming()) {\n      <p>…</p>\n    }\n    @if (chat.error(); as e) {\n      <p class=\"error\">{{ e.message }}</p>\n    }\n    <button (click)=\"chat.stream('Explain Angular signals in one line')\">Ask</button>\n  `,\n})\nexport class ChatComponent {\n  readonly chat = injectAiChat({ system: 'You are concise.' });\n}\n```\n\n| Member           | Type                    | Description                                            |\n| ---------------- | ----------------------- | ------------------------------------------------------ |\n| `messages()`     | `Signal<ChatMessage[]>` | The conversation; the assistant reply updates live.    |\n| `response()`     | `Signal<string>`        | The latest assistant message text.                     |\n| `loading()`      | `Signal<boolean>`       | `true` during a non-streaming `send()`.                |\n| `streaming()`    | `Signal<boolean>`       | `true` while `stream()` is producing tokens.           |\n| `error()`        | `Signal<Error \\| null>` | The most recent error, cleared when a request starts.  |\n| `send(prompt)`   | `void`                  | Send a message and await the full reply.               |\n| `stream(prompt)` | `void`                  | Send a message and stream the reply token-by-token.    |\n| `abort()`        | `void`                  | Cancel an in-flight stream, keeping text so far.       |\n| `reset()`        | `void`                  | Reset to the initial (optionally system-seeded) state. |\n\n`send()` and `stream()` accept the same `ChatCompletionOptions` as the service.\n\n## Structured output\n\n`json<T>()` asks the model for a JSON object and parses the reply into `T`. It\nsets `response_format` to `{ type: 'json_object' }` by default, and raises a\nreadable error if the model returns something that isn't valid JSON.\n\n```ts\ninterface Weather {\n  city: string;\n  celsius: number;\n}\n\nthis.ai\n  .json<Weather>([{ role: 'user', content: 'Weather in Paris as JSON: city, celsius' }])\n  .subscribe((w) => console.log(w.city, w.celsius));\n```\n\nNeed a strict schema? Pass your own `responseFormat` (e.g. a provider\n`json_schema` spec) and it overrides the default:\n\n```ts\nthis.ai.json<Weather>(messages, {\n  responseFormat: {\n    type: 'json_schema',\n    json_schema: {\n      name: 'weather',\n      schema: {\n        type: 'object',\n        properties: { city: { type: 'string' }, celsius: { type: 'number' } },\n        required: ['city', 'celsius'],\n      },\n    },\n  },\n});\n```\n\n## Tool calling\n\nExpose functions to the model with `tools`, then run whichever calls it asks\nfor and feed the results back as `tool` messages. `arguments` arrives as a JSON\n**string** — parse it before use.\n\n```ts\nconst tools = [\n  {\n    type: 'function' as const,\n    function: {\n      name: 'get_weather',\n      description: 'Get the current weather for a city',\n      parameters: {\n        type: 'object',\n        properties: { city: { type: 'string' } },\n        required: ['city'],\n      },\n    },\n  },\n];\n\nconst messages: ChatMessage[] = [{ role: 'user', content: \"What's the weather in Paris?\" }];\n\nthis.ai.chat(messages, { tools }).subscribe((res) => {\n  for (const call of res.toolCalls ?? []) {\n    const args = JSON.parse(call.function.arguments);\n    const result = getWeather(args.city); // your function\n\n    // Add the assistant's request and your tool result, then ask again.\n    messages.push({ role: 'assistant', content: res.content, tool_calls: res.toolCalls });\n    messages.push({ role: 'tool', tool_call_id: call.id, content: JSON.stringify(result) });\n  }\n  this.ai.chat(messages).subscribe((final) => console.log(final.content));\n});\n```\n\nWhile streaming, tool-call fragments arrive on `chunk.toolCalls` (keyed by\n`index`); concatenate each index's `function.arguments` fragments to rebuild the\nfull call.\n\n## Errors & retries\n\nEvery failed request — streaming or not — rejects with an **`NgxAiError`**\ncarrying a readable message and the HTTP `status`, so you can branch on it:\n\n```ts\nimport { NgxAiError } from '@arulcornelious/ngx-ai';\n\nthis.ai.chat(messages).subscribe({\n  error: (err) => {\n    if (err instanceof NgxAiError && err.status === 429) {\n      // back off and try again later\n    }\n  },\n});\n```\n\nOpt into automatic retries for transient failures (network errors and HTTP\n`5xx`) on the non-streaming calls with exponential backoff — `4xx` responses are\nnever retried:\n\n```ts\nthis.ai.chat(messages, { retry: 2 }).subscribe(/* … */);\n```\n\n## Configuration\n\n| Option                          | Type                             | Default    | Notes                                                   |\n| ------------------------------- | -------------------------------- | ---------- | ------------------------------------------------------- |\n| `provider`                      | `'openai' \\| 'grok' \\| 'custom'` | `'openai'` | Selects preset `baseUrl` and `model`.                   |\n| `baseUrl`                       | `string`                         | preset     | API base. Point at your proxy for browser apps.         |\n| `model`                         | `string`                         | preset     | Default model when a request omits one.                 |\n| `apiKey`                        | `string`                         | –          | Bearer token. Requires `dangerouslyAllowBrowserApiKey`. |\n| `headers`                       | `Record<string,string>`          | –          | Extra headers merged into every request.                |\n| `dangerouslyAllowBrowserApiKey` | `boolean`                        | `false`    | Opt in to shipping a key to the browser.                |\n\n### Provider presets\n\n```ts\nprovideNgxAi({ provider: 'openai' }); // https://api.openai.com/v1, gpt-4o-mini\nprovideNgxAi({ provider: 'grok' }); // https://api.x.ai/v1, grok-2-latest\nprovideNgxAi({ provider: 'custom', baseUrl: '/api/ai' }); // your proxy\n```\n\n## 🔐 A note on API keys\n\nAny key bundled into an Angular app is visible to every visitor. **ngx-ai throws if you set `apiKey` without `dangerouslyAllowBrowserApiKey: true`.** For production, run a thin backend that holds the key and forwards to the provider, then point `baseUrl` at it:\n\n```ts\nprovideNgxAi({ provider: 'custom', baseUrl: '/api/ai' });\n```\n\nThe `custom` provider speaks the standard OpenAI chat-completions shape, so most proxies are a few lines of code.\n\n## API\n\n### `NgxAiChatService`\n\n| Method                        | Returns                              | Description                                 |\n| ----------------------------- | ------------------------------------ | ------------------------------------------- |\n| `chat(messages, options?)`    | `Observable<ChatCompletionResponse>` | One complete response.                      |\n| `complete(prompt, options?)`  | `Observable<string>`                 | Convenience wrapper emitting just the text. |\n| `json<T>(messages, options?)` | `Observable<T>`                      | Structured output, parsed into `T`.         |\n| `stream(messages, options?)`  | `Observable<ChatStreamChunk>`        | Token-by-token streaming.                   |\n\n`ChatCompletionOptions`: `model`, `temperature`, `maxTokens`, `topP`, `stop`,\n`responseFormat`, `tools`, `toolChoice`, `retry`, `signal`, `extraBody`.\n\n## Demo\n\nThe repo ships a runnable Angular app that exercises streaming chat via\n`injectAiChat()`, cancellation, and live error handling. Clone the repo, then:\n\n```bash\nnpm install\nnpm run build   # build the library the demo consumes\nnpm start       # http://localhost:4200\n```\n\n## Stability\n\nAs of **v1.0.0** the public API is stable and follows\n[Semantic Versioning](https://semver.org/): breaking changes to the exported\nsurface (`provideNgxAi`, `NgxAiChatService`, `injectAiChat`, `NgxAiError`, and\nthe exported types) will only land in a new major version.\n\n> **Migrating from 0.x:** the only breaking type change during the 0.x line was\n> `ChatMessage.content`, which became `string | null` in 0.5.0 to support\n> assistant messages that contain only tool calls. If you read `content` as a\n> plain `string`, coalesce it: `msg.content ?? ''`.\n\n## Contributing\n\nIssues and PRs welcome — see [CONTRIBUTING.md](https://github.com/arul1998/ngx-ai/blob/main/CONTRIBUTING.md).\n\n## License\n\n[MIT](./LICENSE) © Arul Cornelious\n","readmeFilename":"README.md"}