{"_id":"@bozonx/ai-kit","_rev":"8-f4a79a8358017bf86c02717b12047fd3","name":"@bozonx/ai-kit","dist-tags":{"latest":"0.6.1"},"versions":{"0.1.0":{"name":"@bozonx/ai-kit","version":"0.1.0","author":{"name":"Ivan K"},"license":"MIT","_id":"@bozonx/ai-kit@0.1.0","maintainers":[{"name":"bozonx","email":"ipkozyrin@gmail.com"}],"homepage":"https://github.com/bozonx/ai-kit","bugs":{"url":"https://github.com/bozonx/ai-kit/issues"},"dist":{"shasum":"873dd1e948973156b51490921ec9bc9bd3c083d3","tarball":"https://registry.npmjs.org/@bozonx/ai-kit/-/ai-kit-0.1.0.tgz","fileCount":63,"integrity":"sha512-M7DGcbgKN8OWJnpIZvNS7cVIbXcWsPQADJ6LBREgOlQ24i7y3bW/w+KEoSQEd17fiYicYG9xrd7Vb7HbaeFfxw==","signatures":[{"sig":"MEUCIFgpF9VVFkxfaXr2HMid2zB2k/EbeBlXzJSAMZMBSvvcAiEA2UGyhrvnnX1dRMdK+NvCoeMK4rxV4TS9CvRS4z9F9C4=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":158140},"main":"./dist/index.js","type":"module","_from":"file:bozonx-ai-kit-0.1.0.tgz","types":"./dist/index.d.ts","engines":{"node":">=22.0.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./package.json":"./package.json"},"scripts":{"lint":"eslint \"{src,test}/**/*.ts\" --max-warnings=0","test":"NODE_OPTIONS='--experimental-vm-modules' jest","build":"tsc -p tsconfig.build.json","check":"pnpm lint && pnpm typecheck && pnpm format:check && pnpm test","clean":"rm -rf dist","format":"prettier --write \"src/**/*.ts\" \"test/**/*.ts\"","lint:fix":"eslint \"{src,test}/**/*.ts\" --fix","test:cov":"NODE_OPTIONS='--experimental-vm-modules' jest --coverage","typecheck":"tsc -p tsconfig.json --noEmit && tsc -p tsconfig.spec.json --noEmit","test:watch":"NODE_OPTIONS='--experimental-vm-modules' jest --watch","format:check":"prettier --check \"src/**/*.ts\" \"test/**/*.ts\""},"_npmUser":{"name":"bozonx","email":"ipkozyrin@gmail.com"},"_resolved":"/tmp/92e33c58683cff18965878f3141ac523/bozonx-ai-kit-0.1.0.tgz","_integrity":"sha512-M7DGcbgKN8OWJnpIZvNS7cVIbXcWsPQADJ6LBREgOlQ24i7y3bW/w+KEoSQEd17fiYicYG9xrd7Vb7HbaeFfxw==","repository":{"url":"git+https://github.com/bozonx/ai-kit.git","type":"git"},"_npmVersion":"12.0.2","description":"Reusable core for building AI features: priced model catalog, model policy, provider adapters, retries and prompt assembly","directories":{},"_nodeVersion":"26.7.0","dependencies":{"ai":"^7.0.77","zod":"^4.4.3","js-yaml":"^5.3.0","@ai-sdk/google":"^4.0.50","@ai-sdk/openai":"^4.0.46","@openrouter/ai-sdk-provider":"^3.0.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^30.2.0","eslint":"^9.39.2","ts-jest":"^29.4.6","prettier":"^3.7.4","@eslint/js":"^9.39.2","typescript":"^5.9.3","@types/jest":"^30.0.0","@types/node":"^25.0.8","@jest/globals":"^30.2.0","eslint-plugin-jest":"^29.12.1","eslint-config-prettier":"^10.1.8","eslint-plugin-prettier":"^5.5.5","@typescript-eslint/parser":"^8.53.0","@typescript-eslint/eslint-plugin":"^8.53.0"},"_npmOperationalInternal":{"tmp":"tmp/ai-kit_0.1.0_1787954098350_0.6760083450183698","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@bozonx/ai-kit","version":"0.1.1","author":{"name":"Ivan K"},"license":"MIT","_id":"@bozonx/ai-kit@0.1.1","maintainers":[{"name":"bozonx","email":"ipkozyrin@gmail.com"}],"homepage":"https://github.com/bozonx/ai-kit","bugs":{"url":"https://github.com/bozonx/ai-kit/issues"},"dist":{"shasum":"798eca29777df58922e51fdaf6e19552bccfa0df","tarball":"https://registry.npmjs.org/@bozonx/ai-kit/-/ai-kit-0.1.1.tgz","fileCount":63,"integrity":"sha512-gp+TQcywjSoIliq+ZoaiJas6vjToF2uRVVU06mP6r6IYSONxbU8XIVipOqWvE0Fqgge/YWynfwwFJw4oc8oXjQ==","signatures":[{"sig":"MEYCIQDu/Lm1nR0ETD8f7erFSEseS7eZCm/dlweDeurCQ/P6/AIhAPiFwS5LsaxoyhI/SgZIEVZ1/JAiQcZyeoDKE0syg+uB","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":160715},"main":"./dist/index.js","type":"module","_from":"file:bozonx-ai-kit-0.1.1.tgz","types":"./dist/index.d.ts","engines":{"node":">=22.0.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./package.json":"./package.json"},"scripts":{"lint":"eslint \"{src,test}/**/*.ts\" --max-warnings=0","test":"NODE_OPTIONS='--experimental-vm-modules' jest","build":"tsc -p tsconfig.build.json","check":"pnpm lint && pnpm typecheck && pnpm format:check && pnpm test","clean":"rm -rf dist","format":"prettier --write \"src/**/*.ts\" \"test/**/*.ts\"","lint:fix":"eslint \"{src,test}/**/*.ts\" --fix","test:cov":"NODE_OPTIONS='--experimental-vm-modules' jest --coverage","typecheck":"tsc -p tsconfig.json --noEmit && tsc -p tsconfig.spec.json --noEmit","test:watch":"NODE_OPTIONS='--experimental-vm-modules' jest --watch","format:check":"prettier --check \"src/**/*.ts\" \"test/**/*.ts\""},"_npmUser":{"name":"bozonx","email":"ipkozyrin@gmail.com"},"_resolved":"/tmp/12bcc57272e7d2c68716c015cb50cf84/bozonx-ai-kit-0.1.1.tgz","_integrity":"sha512-gp+TQcywjSoIliq+ZoaiJas6vjToF2uRVVU06mP6r6IYSONxbU8XIVipOqWvE0Fqgge/YWynfwwFJw4oc8oXjQ==","repository":{"url":"git+https://github.com/bozonx/ai-kit.git","type":"git"},"_npmVersion":"12.0.2","description":"Reusable core for building AI features: priced model catalog, model policy, provider adapters, retries and prompt assembly","directories":{},"_nodeVersion":"26.7.0","dependencies":{"ai":"^7.0.77","zod":"^4.4.3","js-yaml":"^5.3.0","@ai-sdk/google":"^4.0.50","@ai-sdk/openai":"^4.0.46","@openrouter/ai-sdk-provider":"^3.0.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^30.2.0","eslint":"^9.39.2","ts-jest":"^29.4.6","prettier":"^3.7.4","@eslint/js":"^9.39.2","typescript":"^5.9.3","@types/jest":"^30.0.0","@types/node":"^25.0.8","@jest/globals":"^30.2.0","eslint-plugin-jest":"^29.12.1","eslint-config-prettier":"^10.1.8","eslint-plugin-prettier":"^5.5.5","@typescript-eslint/parser":"^8.53.0","@typescript-eslint/eslint-plugin":"^8.53.0"},"_npmOperationalInternal":{"tmp":"tmp/ai-kit_0.1.1_1787958893479_0.5123354319138704","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@bozonx/ai-kit","version":"0.2.0","author":{"name":"Ivan K"},"license":"MIT","_id":"@bozonx/ai-kit@0.2.0","maintainers":[{"name":"bozonx","email":"ipkozyrin@gmail.com"}],"homepage":"https://github.com/bozonx/ai-kit","bugs":{"url":"https://github.com/bozonx/ai-kit/issues"},"dist":{"shasum":"05c2f9c08435e5a9d5291b186bdebacd2937ee04","tarball":"https://registry.npmjs.org/@bozonx/ai-kit/-/ai-kit-0.2.0.tgz","fileCount":103,"integrity":"sha512-dg/BDMAzl2SlVHXg6RQ3KjgO5qOquAgalRZMPUeIPEC6KtAnkosmqST3PCb9/NpKdYujpIo3nTE8jeR5RBohBQ==","signatures":[{"sig":"MEUCIFi2YPMaso4wz1MZtqNF2+xvF4EYP3gDKup2720OjWb4AiEAv7hxX8DUhW7+BMztIka+8wTjcCEbqF0I//qhrMuTyk0=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":282972},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22.0.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./package.json":"./package.json"},"gitHead":"904448e24a73c43f328fc3a2c5fa4c24b9bec76d","scripts":{"lint":"eslint \"{src,test}/**/*.ts\" --max-warnings=0","test":"NODE_OPTIONS='--experimental-vm-modules' jest","build":"tsc -p tsconfig.build.json","check":"pnpm lint && pnpm typecheck && pnpm format:check && pnpm test","clean":"rm -rf dist","format":"prettier --write \"src/**/*.ts\" \"test/**/*.ts\"","prepack":"pnpm run clean && pnpm run build","lint:fix":"eslint \"{src,test}/**/*.ts\" --fix","test:cov":"NODE_OPTIONS='--experimental-vm-modules' jest --coverage","typecheck":"tsc -p tsconfig.json --noEmit && tsc -p tsconfig.spec.json --noEmit","test:watch":"NODE_OPTIONS='--experimental-vm-modules' jest --watch","format:check":"prettier --check \"src/**/*.ts\" \"test/**/*.ts\"","prepublishOnly":"pnpm run check"},"_npmUser":{"name":"bozonx","email":"ipkozyrin@gmail.com"},"repository":{"url":"git+https://github.com/bozonx/ai-kit.git","type":"git"},"_npmVersion":"12.0.2","description":"Reusable core for building AI features: priced model catalog, model policy, provider adapters, retries and prompt assembly","directories":{},"_nodeVersion":"26.7.0","dependencies":{"ai":"^7.0.77","ws":"^8.21.3","zod":"^4.4.3","js-yaml":"^5.3.0","@ai-sdk/google":"^4.0.50","@ai-sdk/openai":"^4.0.46","@openrouter/ai-sdk-provider":"^3.0.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"packageManager":"pnpm@10.25.0","devDependencies":{"jest":"^30.2.0","eslint":"^9.39.2","ts-jest":"^29.4.6","prettier":"^3.7.4","@types/ws":"^8.18.1","@eslint/js":"^9.39.2","typescript":"^5.9.3","@types/jest":"^30.0.0","@types/node":"^25.0.8","@jest/globals":"^30.2.0","eslint-plugin-jest":"^29.12.1","eslint-config-prettier":"^10.1.8","eslint-plugin-prettier":"^5.5.5","@typescript-eslint/parser":"^8.53.0","@typescript-eslint/eslint-plugin":"^8.53.0"},"_npmOperationalInternal":{"tmp":"tmp/ai-kit_0.2.0_1788178349001_0.9683364758176087","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@bozonx/ai-kit","version":"0.3.0","author":{"name":"Ivan K"},"license":"MIT","_id":"@bozonx/ai-kit@0.3.0","maintainers":[{"name":"bozonx","email":"ipkozyrin@gmail.com"}],"homepage":"https://github.com/bozonx/ai-kit","bugs":{"url":"https://github.com/bozonx/ai-kit/issues"},"dist":{"shasum":"ca750e6dfb64982efa19b2b434f1593a7e52d294","tarball":"https://registry.npmjs.org/@bozonx/ai-kit/-/ai-kit-0.3.0.tgz","fileCount":188,"integrity":"sha512-tk/6jrpvF32YTg2g/2WNSDIDQ70G1qaKrD+XjatRKuM1woSZfveSx9SpRS7D6I4p3ZXkgE3Mde0htrdzfu2MXQ==","signatures":[{"sig":"MEYCIQDbBPH1k16ujC2f9r78LMCjek1dyVeJHTh1/PAop9smJAIhAKsesrrpIr24ocG/1sDapMMgrgCoGraRfefspnXj0DJM","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEQCIDB6bsfm0TT3Epl7uxODnb+yqypwb608UZ2O2s/pin0JAiAJrTKXG0UyXFNtgPUitdc7fOnUVEkCb15ytlxNDnEH4g==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":575516},"main":"./dist/index.js","type":"module","_from":"file:bozonx-ai-kit-0.3.0.tgz","types":"./dist/index.d.ts","engines":{"node":">=22.0.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./stt":{"types":"./dist/stt/index.d.ts","import":"./dist/stt/index.js"},"./stream":{"types":"./dist/stream/index.d.ts","import":"./dist/stream/index.js"},"./translate":{"types":"./dist/translate/index.d.ts","import":"./dist/translate/index.js"},"./package.json":"./package.json"},"scripts":{"lint":"eslint \"{src,test}/**/*.ts\" --max-warnings=0","test":"NODE_OPTIONS='--experimental-vm-modules' jest","build":"tsc -p tsconfig.build.json","check":"pnpm lint && pnpm typecheck && pnpm format:check && pnpm test","clean":"rm -rf dist","format":"prettier --write \"src/**/*.ts\" \"test/**/*.ts\"","lint:fix":"eslint \"{src,test}/**/*.ts\" --fix","test:cov":"NODE_OPTIONS='--experimental-vm-modules' jest --coverage","typecheck":"tsc -p tsconfig.json --noEmit && tsc -p tsconfig.spec.json --noEmit","test:watch":"NODE_OPTIONS='--experimental-vm-modules' jest --watch","format:check":"prettier --check \"src/**/*.ts\" \"test/**/*.ts\""},"_npmUser":{"name":"bozonx","email":"ipkozyrin@gmail.com"},"_resolved":"/tmp/d3469d23517ceeac1b4380d6d3c4756b/bozonx-ai-kit-0.3.0.tgz","_integrity":"sha512-tk/6jrpvF32YTg2g/2WNSDIDQ70G1qaKrD+XjatRKuM1woSZfveSx9SpRS7D6I4p3ZXkgE3Mde0htrdzfu2MXQ==","repository":{"url":"git+https://github.com/bozonx/ai-kit.git","type":"git"},"_npmVersion":"12.0.2","description":"Reusable core for building AI features: priced model catalog, model policy, provider adapters, retries, tools, embeddings and prompt assembly","directories":{},"sideEffects":false,"_nodeVersion":"26.8.1","dependencies":{"ai":"^7.0.84","js-yaml":"^5.3.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"ws":"^8.21.3","zod":"^4.4.3","jest":"^30.2.0","eslint":"^9.39.2","ts-jest":"^29.4.6","prettier":"^3.7.4","@types/ws":"^8.18.1","@eslint/js":"^9.39.2","typescript":"^5.9.3","@types/jest":"^30.0.0","@types/node":"^25.0.8","@jest/globals":"^30.2.0","@ai-sdk/google":"^4.0.76","@ai-sdk/openai":"^4.0.71","@ai-sdk/anthropic":"^4.0.46","eslint-plugin-jest":"^29.12.1","eslint-config-prettier":"^10.1.8","eslint-plugin-prettier":"^5.5.5","@typescript-eslint/parser":"^8.53.0","@openrouter/ai-sdk-provider":"^3.1.0","@typescript-eslint/eslint-plugin":"^8.53.0"},"peerDependencies":{"ws":"^8.21.3","zod":"^4.0.0","@ai-sdk/google":"^4.0.76","@ai-sdk/openai":"^4.0.71","@ai-sdk/anthropic":"^4.0.46","@openrouter/ai-sdk-provider":"^3.1.0"},"peerDependenciesMeta":{"ws":{"optional":true},"@ai-sdk/google":{"optional":true},"@ai-sdk/openai":{"optional":true},"@ai-sdk/anthropic":{"optional":true},"@openrouter/ai-sdk-provider":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/ai-kit_0.3.0_1790016211241_0.09851362571097333","host":"s3://npm-registry-packages-npm-production"}},"0.4.0":{"name":"@bozonx/ai-kit","version":"0.4.0","author":{"name":"Ivan K"},"license":"MIT","_id":"@bozonx/ai-kit@0.4.0","maintainers":[{"name":"bozonx","email":"ipkozyrin@gmail.com"}],"homepage":"https://github.com/bozonx/ai-kit","bugs":{"url":"https://github.com/bozonx/ai-kit/issues"},"dist":{"shasum":"3714c6b1057f5b102a119a598ca2e5219c8d21ad","tarball":"https://registry.npmjs.org/@bozonx/ai-kit/-/ai-kit-0.4.0.tgz","fileCount":212,"integrity":"sha512-Lx2UdevVk7zKv6Lq8plUmkOdNYyQkhJ8irtTEbji+UyR/FyjgkllZopJUqdO0mRApz04kdsL11b1hC8wEJT3YA==","signatures":[{"sig":"MEUCIARJd21nH/7QqiNpf3DYLnKFmgvltvnZrye2iontl+lxAiEAig2PBbjQtkVJBYqZ4o4FTj9KW3TAEQLRGXt4XeWuJp8=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIBXqifHHZe2UM2/c4nnTwRBI0Z0fm+VY/wo+/lC1wSqYAiEApeC403i3nukud0TxTLWoUuGHqRIzsn1+vnzB3/8Sh/w=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":620719},"main":"./dist/index.js","type":"module","_from":"file:bozonx-ai-kit-0.4.0.tgz","types":"./dist/index.d.ts","engines":{"node":">=22.0.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./stt":{"types":"./dist/stt/index.d.ts","import":"./dist/stt/index.js"},"./node":{"types":"./dist/node/index.d.ts","import":"./dist/node/index.js"},"./stream":{"types":"./dist/stream/index.d.ts","import":"./dist/stream/index.js"},"./translate":{"types":"./dist/translate/index.d.ts","import":"./dist/translate/index.js"},"./package.json":"./package.json"},"scripts":{"lint":"eslint \"{src,test}/**/*.ts\" --max-warnings=0","test":"NODE_OPTIONS='--experimental-vm-modules' jest","build":"tsc -p tsconfig.build.json","check":"pnpm lint && pnpm typecheck && pnpm format:check && pnpm test","clean":"rm -rf dist","format":"prettier --write \"src/**/*.ts\" \"test/**/*.ts\"","lint:fix":"eslint \"{src,test}/**/*.ts\" --fix","test:cov":"NODE_OPTIONS='--experimental-vm-modules' jest --coverage","typecheck":"tsc -p tsconfig.json --noEmit && tsc -p tsconfig.spec.json --noEmit","test:watch":"NODE_OPTIONS='--experimental-vm-modules' jest --watch","format:check":"prettier --check \"src/**/*.ts\" \"test/**/*.ts\""},"_npmUser":{"name":"bozonx","email":"ipkozyrin@gmail.com"},"_resolved":"/tmp/7783232cfef349700587e670dd76d411/bozonx-ai-kit-0.4.0.tgz","_integrity":"sha512-Lx2UdevVk7zKv6Lq8plUmkOdNYyQkhJ8irtTEbji+UyR/FyjgkllZopJUqdO0mRApz04kdsL11b1hC8wEJT3YA==","repository":{"url":"git+https://github.com/bozonx/ai-kit.git","type":"git"},"_npmVersion":"12.0.2","description":"Reusable core for building AI features: priced model catalog, model policy, provider adapters, retries, tools, embeddings and prompt assembly","directories":{},"sideEffects":false,"_nodeVersion":"26.8.1","dependencies":{"ai":"^7.0.84","js-yaml":"^5.3.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"ws":"^8.21.3","zod":"^4.4.3","jest":"^30.2.0","eslint":"^9.39.2","ts-jest":"^29.4.6","prettier":"^3.7.4","@types/ws":"^8.18.1","@eslint/js":"^9.39.2","typescript":"^5.9.3","@types/jest":"^30.0.0","@types/node":"^25.0.8","@jest/globals":"^30.2.0","@ai-sdk/google":"^4.0.76","@ai-sdk/openai":"^4.0.71","@ai-sdk/deepseek":"^3.0.50","@ai-sdk/anthropic":"^4.0.46","eslint-plugin-jest":"^29.12.1","eslint-config-prettier":"^10.1.8","eslint-plugin-prettier":"^5.5.5","@ai-sdk/openai-compatible":"^3.0.53","@typescript-eslint/parser":"^8.53.0","@openrouter/ai-sdk-provider":"^3.1.0","@typescript-eslint/eslint-plugin":"^8.53.0"},"peerDependencies":{"ws":"^8.21.3","zod":"^4.0.0","@ai-sdk/google":"^4.0.76","@ai-sdk/openai":"^4.0.71","@ai-sdk/deepseek":"^3.0.50","@ai-sdk/anthropic":"^4.0.46","@ai-sdk/openai-compatible":"^3.0.53","@openrouter/ai-sdk-provider":"^3.1.0"},"peerDependenciesMeta":{"ws":{"optional":true},"@ai-sdk/google":{"optional":true},"@ai-sdk/openai":{"optional":true},"@ai-sdk/deepseek":{"optional":true},"@ai-sdk/anthropic":{"optional":true},"@ai-sdk/openai-compatible":{"optional":true},"@openrouter/ai-sdk-provider":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/ai-kit_0.4.0_1790022735068_0.5524306972264506","host":"s3://npm-registry-packages-npm-production"}},"0.5.0":{"name":"@bozonx/ai-kit","version":"0.5.0","author":{"name":"Ivan K"},"license":"MIT","_id":"@bozonx/ai-kit@0.5.0","maintainers":[{"name":"bozonx","email":"ipkozyrin@gmail.com"}],"homepage":"https://github.com/bozonx/ai-kit","bugs":{"url":"https://github.com/bozonx/ai-kit/issues"},"dist":{"shasum":"6faeb96fcf50ba87b667b19e003ba4950b35fa78","tarball":"https://registry.npmjs.org/@bozonx/ai-kit/-/ai-kit-0.5.0.tgz","fileCount":220,"integrity":"sha512-fcN6aD+pA1Ok9SZoZ0Lztkr0/rwPhNate6RMjws8YCqD7TBmPpCXCH66MyeE19qCpocE+jiOm45IjVOc+SrxTg==","signatures":[{"sig":"MEQCICX7PAKON6+3428MA1CerFJqsyjWsu2mYYU2e+1J/KdIAiBfnHosY1t5xqG9XrvD/9JFh8HddNSmqY/D8K1tHquWwg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIHu7/xSCKfEFN3j6ygjaBGlybiUBYog9DYTvkFlyH0TNAiEAgFHKEjVCuJnR1YwvWUvWV6OYxyoKxZjDIhuWFi/wotg=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":639404},"main":"./dist/index.js","type":"module","_from":"file:bozonx-ai-kit-0.5.0.tgz","types":"./dist/index.d.ts","engines":{"node":">=22.0.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./stt":{"types":"./dist/stt/index.d.ts","import":"./dist/stt/index.js"},"./node":{"types":"./dist/node/index.d.ts","import":"./dist/node/index.js"},"./stream":{"types":"./dist/stream/index.d.ts","import":"./dist/stream/index.js"},"./translate":{"types":"./dist/translate/index.d.ts","import":"./dist/translate/index.js"},"./package.json":"./package.json"},"scripts":{"lint":"eslint \"{src,test}/**/*.ts\" --max-warnings=0","test":"NODE_OPTIONS='--experimental-vm-modules' jest","build":"tsc -p tsconfig.build.json","check":"pnpm lint && pnpm typecheck && pnpm format:check && pnpm test","clean":"rm -rf dist","format":"prettier --write \"src/**/*.ts\" \"test/**/*.ts\"","lint:fix":"eslint \"{src,test}/**/*.ts\" --fix","test:cov":"NODE_OPTIONS='--experimental-vm-modules' jest --coverage","typecheck":"tsc -p tsconfig.json --noEmit && tsc -p tsconfig.spec.json --noEmit","test:watch":"NODE_OPTIONS='--experimental-vm-modules' jest --watch","format:check":"prettier --check \"src/**/*.ts\" \"test/**/*.ts\""},"_npmUser":{"name":"bozonx","email":"ipkozyrin@gmail.com"},"_resolved":"/tmp/3927f904b2a093905ec952d774e388a6/bozonx-ai-kit-0.5.0.tgz","_integrity":"sha512-fcN6aD+pA1Ok9SZoZ0Lztkr0/rwPhNate6RMjws8YCqD7TBmPpCXCH66MyeE19qCpocE+jiOm45IjVOc+SrxTg==","repository":{"url":"git+https://github.com/bozonx/ai-kit.git","type":"git"},"_npmVersion":"12.0.2","description":"Reusable core for building AI features: priced model catalog, model policy, provider adapters, retries, tools, embeddings and prompt assembly","directories":{},"sideEffects":false,"_nodeVersion":"26.8.1","dependencies":{"ai":"^7.0.84","js-yaml":"^5.3.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"ws":"^8.21.3","zod":"^4.4.3","jest":"^30.2.0","eslint":"^9.39.2","ts-jest":"^29.4.6","prettier":"^3.7.4","@types/ws":"^8.18.1","@eslint/js":"^9.39.2","typescript":"^5.9.3","@types/jest":"^30.0.0","@types/node":"^25.0.8","@jest/globals":"^30.2.0","@ai-sdk/google":"^4.0.76","@ai-sdk/openai":"^4.0.71","@ai-sdk/deepseek":"^3.0.50","@ai-sdk/anthropic":"^4.0.46","eslint-plugin-jest":"^29.12.1","eslint-config-prettier":"^10.1.8","eslint-plugin-prettier":"^5.5.5","@ai-sdk/openai-compatible":"^3.0.53","@typescript-eslint/parser":"^8.53.0","@openrouter/ai-sdk-provider":"^3.1.0","@typescript-eslint/eslint-plugin":"^8.53.0"},"peerDependencies":{"ws":"^8.21.3","zod":"^4.0.0","@ai-sdk/google":"^4.0.76","@ai-sdk/openai":"^4.0.71","@ai-sdk/deepseek":"^3.0.50","@ai-sdk/anthropic":"^4.0.46","@ai-sdk/openai-compatible":"^3.0.53","@openrouter/ai-sdk-provider":"^3.1.0"},"peerDependenciesMeta":{"ws":{"optional":true},"@ai-sdk/google":{"optional":true},"@ai-sdk/openai":{"optional":true},"@ai-sdk/deepseek":{"optional":true},"@ai-sdk/anthropic":{"optional":true},"@ai-sdk/openai-compatible":{"optional":true},"@openrouter/ai-sdk-provider":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/ai-kit_0.5.0_1790207751984_0.034372169498540606","host":"s3://npm-registry-packages-npm-production"}},"0.6.0":{"name":"@bozonx/ai-kit","version":"0.6.0","author":{"name":"Ivan K"},"license":"MIT","_id":"@bozonx/ai-kit@0.6.0","maintainers":[{"name":"bozonx","email":"ipkozyrin@gmail.com"}],"homepage":"https://github.com/bozonx/ai-kit","bugs":{"url":"https://github.com/bozonx/ai-kit/issues"},"dist":{"shasum":"33ba9a1359cdb025fe76b26678d3c8f214d58422","tarball":"https://registry.npmjs.org/@bozonx/ai-kit/-/ai-kit-0.6.0.tgz","fileCount":220,"integrity":"sha512-zCQK8ZcibFeDpkIwxaA8EPDy8F59uFoxzPX9hYigiTwlh4APQeQ87NIaW6VIf+/QO5GEruUNnjFXSvTOR5Z5WQ==","signatures":[{"sig":"MEYCIQDMSSTjq7D/5MKLWnOK68q2pb9LWogaDRXZY9xMOZx0CgIhAMkrWaHHu1cfAVmE2Tcf7S7F7hKF0Jomv6iCeG0mL1Dv","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIQC2D4Pf/x8+rPUi8PFuGAa1L/fbjZW4+Ao/ECmZvF8eAQIgM3REN1fTPwkmOzCCTlwcsBR+EphmcOSHlj7o0C1nwmw=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":672048},"main":"./dist/index.js","type":"module","_from":"file:bozonx-ai-kit-0.6.0.tgz","types":"./dist/index.d.ts","engines":{"node":">=22.0.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./stt":{"types":"./dist/stt/index.d.ts","import":"./dist/stt/index.js"},"./node":{"types":"./dist/node/index.d.ts","import":"./dist/node/index.js"},"./stream":{"types":"./dist/stream/index.d.ts","import":"./dist/stream/index.js"},"./translate":{"types":"./dist/translate/index.d.ts","import":"./dist/translate/index.js"},"./package.json":"./package.json"},"scripts":{"lint":"eslint \"{src,test}/**/*.ts\" --max-warnings=0","test":"NODE_OPTIONS='--experimental-vm-modules' jest","build":"tsc -p tsconfig.build.json","check":"pnpm lint && pnpm typecheck && pnpm format:check && pnpm test","clean":"rm -rf dist","format":"prettier --write \"src/**/*.ts\" \"test/**/*.ts\"","lint:fix":"eslint \"{src,test}/**/*.ts\" --fix","test:cov":"NODE_OPTIONS='--experimental-vm-modules' jest --coverage","typecheck":"tsc -p tsconfig.json --noEmit && tsc -p tsconfig.spec.json --noEmit","test:watch":"NODE_OPTIONS='--experimental-vm-modules' jest --watch","format:check":"prettier --check \"src/**/*.ts\" \"test/**/*.ts\""},"_npmUser":{"name":"bozonx","email":"ipkozyrin@gmail.com"},"_resolved":"/tmp/4fc5d06954add06db21b3eabd862f8a6/bozonx-ai-kit-0.6.0.tgz","_integrity":"sha512-zCQK8ZcibFeDpkIwxaA8EPDy8F59uFoxzPX9hYigiTwlh4APQeQ87NIaW6VIf+/QO5GEruUNnjFXSvTOR5Z5WQ==","repository":{"url":"git+https://github.com/bozonx/ai-kit.git","type":"git"},"_npmVersion":"12.0.2","description":"Reusable core for building AI features: priced model catalog, model policy, provider adapters, retries, tools, embeddings and prompt assembly","directories":{},"sideEffects":false,"_nodeVersion":"26.8.1","dependencies":{"ai":"^7.0.84","js-yaml":"^5.3.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"ws":"^8.21.3","zod":"^4.4.3","jest":"^30.2.0","eslint":"^9.39.2","ts-jest":"^29.4.6","prettier":"^3.7.4","@types/ws":"^8.18.1","@eslint/js":"^9.39.2","typescript":"^5.9.3","@types/jest":"^30.0.0","@types/node":"^25.0.8","@jest/globals":"^30.2.0","@ai-sdk/google":"^4.0.76","@ai-sdk/openai":"^4.0.71","@ai-sdk/deepseek":"^3.0.50","@ai-sdk/anthropic":"^4.0.46","eslint-plugin-jest":"^29.12.1","eslint-config-prettier":"^10.1.8","eslint-plugin-prettier":"^5.5.5","@ai-sdk/openai-compatible":"^3.0.53","@typescript-eslint/parser":"^8.53.0","@openrouter/ai-sdk-provider":"^3.1.0","@typescript-eslint/eslint-plugin":"^8.53.0"},"peerDependencies":{"ws":"^8.21.3","zod":"^4.0.0","@ai-sdk/google":"^4.0.76","@ai-sdk/openai":"^4.0.71","@ai-sdk/deepseek":"^3.0.50","@ai-sdk/anthropic":"^4.0.46","@ai-sdk/openai-compatible":"^3.0.53","@openrouter/ai-sdk-provider":"^3.1.0"},"peerDependenciesMeta":{"ws":{"optional":true},"@ai-sdk/google":{"optional":true},"@ai-sdk/openai":{"optional":true},"@ai-sdk/deepseek":{"optional":true},"@ai-sdk/anthropic":{"optional":true},"@ai-sdk/openai-compatible":{"optional":true},"@openrouter/ai-sdk-provider":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/ai-kit_0.6.0_1790353530225_0.7091015019826967","host":"s3://npm-registry-packages-npm-production"}},"0.6.1":{"_id":"@bozonx/ai-kit@0.6.1","bugs":{"url":"https://github.com/bozonx/ai-kit/issues"},"dist":{"shasum":"f688ff6d346f84d7037a7b616a9b517cc35474a9","tarball":"https://registry.npmjs.org/@bozonx/ai-kit/-/ai-kit-0.6.1.tgz","fileCount":220,"integrity":"sha512-UtYXlVXOp45uzfJsmyFv1dEGVzW/iE4XInc0oUk1oN6dqY6PeFYMXAzRuIQZRvqZUa6DOzaRY2JzkNXGBogUVg==","signatures":[{"sig":"MEUCIEXfV52DBNrWG6upsRTH62SXpRF794UoStSgqMPb/ekPAiEAqdbdYOQsoks14TtNCIt6r3qxYQCjY/FrnS7Bep4O1UM=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQDOZCGzm5YGaKXl1i6NveVMAKHzhPE9OTymB1KcBPimtAIhAPoi2D0pFqYRbI1BVFdVsBUQuUFn0TF/XSPcIXcGgO2J"}],"unpackedSize":672831},"main":"./dist/index.js","name":"@bozonx/ai-kit","type":"module","_from":"file:bozonx-ai-kit-0.6.1.tgz","types":"./dist/index.d.ts","author":{"name":"Ivan K"},"engines":{"node":">=22.0.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./stt":{"types":"./dist/stt/index.d.ts","import":"./dist/stt/index.js"},"./node":{"types":"./dist/node/index.d.ts","import":"./dist/node/index.js"},"./stream":{"types":"./dist/stream/index.d.ts","import":"./dist/stream/index.js"},"./translate":{"types":"./dist/translate/index.d.ts","import":"./dist/translate/index.js"},"./package.json":"./package.json"},"license":"MIT","scripts":{"lint":"eslint \"{src,test}/**/*.ts\" --max-warnings=0","test":"NODE_OPTIONS='--experimental-vm-modules' jest","build":"tsc -p tsconfig.build.json","check":"pnpm lint && pnpm typecheck && pnpm format:check && pnpm test","clean":"rm -rf dist","format":"prettier --write \"src/**/*.ts\" \"test/**/*.ts\"","lint:fix":"eslint \"{src,test}/**/*.ts\" --fix","test:cov":"NODE_OPTIONS='--experimental-vm-modules' jest --coverage","typecheck":"tsc -p tsconfig.json --noEmit && tsc -p tsconfig.spec.json --noEmit","test:watch":"NODE_OPTIONS='--experimental-vm-modules' jest --watch","format:check":"prettier --check \"src/**/*.ts\" \"test/**/*.ts\""},"version":"0.6.1","_npmUser":{"name":"bozonx","email":"ipkozyrin@gmail.com"},"homepage":"https://github.com/bozonx/ai-kit","_resolved":"/tmp/2195056207b2c1be1f59e2af76fbf641/bozonx-ai-kit-0.6.1.tgz","_integrity":"sha512-UtYXlVXOp45uzfJsmyFv1dEGVzW/iE4XInc0oUk1oN6dqY6PeFYMXAzRuIQZRvqZUa6DOzaRY2JzkNXGBogUVg==","repository":{"url":"git+https://github.com/bozonx/ai-kit.git","type":"git"},"_npmVersion":"12.0.2","description":"Reusable core for building AI features: priced model catalog, model policy, provider adapters, retries, tools, embeddings and prompt assembly","directories":{},"maintainers":[{"name":"bozonx","email":"ipkozyrin@gmail.com"}],"sideEffects":false,"_nodeVersion":"26.8.1","dependencies":{"ai":"^7.0.84","js-yaml":"^5.3.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"ws":"^8.21.3","zod":"^4.4.3","jest":"^30.2.0","eslint":"^9.39.2","ts-jest":"^29.4.6","prettier":"^3.7.4","@types/ws":"^8.18.1","@eslint/js":"^9.39.2","typescript":"^5.9.3","@types/jest":"^30.0.0","@types/node":"^25.0.8","@jest/globals":"^30.2.0","@ai-sdk/google":"^4.0.76","@ai-sdk/openai":"^4.0.71","@ai-sdk/deepseek":"^3.0.50","@ai-sdk/anthropic":"^4.0.46","eslint-plugin-jest":"^29.12.1","eslint-config-prettier":"^10.1.8","eslint-plugin-prettier":"^5.5.5","@ai-sdk/openai-compatible":"^3.0.53","@typescript-eslint/parser":"^8.53.0","@openrouter/ai-sdk-provider":"^3.1.0","@typescript-eslint/eslint-plugin":"^8.53.0"},"peerDependencies":{"ws":"^8.21.3","zod":"^4.0.0","@ai-sdk/google":"^4.0.76","@ai-sdk/openai":"^4.0.71","@ai-sdk/deepseek":"^3.0.50","@ai-sdk/anthropic":"^4.0.46","@ai-sdk/openai-compatible":"^3.0.53","@openrouter/ai-sdk-provider":"^3.1.0"},"peerDependenciesMeta":{"ws":{"optional":true},"@ai-sdk/google":{"optional":true},"@ai-sdk/openai":{"optional":true},"@ai-sdk/deepseek":{"optional":true},"@ai-sdk/anthropic":{"optional":true},"@ai-sdk/openai-compatible":{"optional":true},"@openrouter/ai-sdk-provider":{"optional":true}},"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/ai-kit_0.6.1_1790436509013_0.29596124593386164"}}},"time":{"created":"2026-08-28T21:54:58.169Z","modified":"2026-09-26T15:28:29.248Z","0.1.0":"2026-08-28T21:54:58.497Z","0.1.1":"2026-08-28T23:14:53.626Z","0.2.0":"2026-08-31T12:12:29.142Z","0.3.0":"2026-09-21T18:43:31.340Z","0.4.0":"2026-09-21T20:32:15.178Z","0.5.0":"2026-09-23T23:55:52.085Z","0.6.0":"2026-09-25T16:25:30.340Z","0.6.1":"2026-09-26T15:28:29.094Z"},"bugs":{"url":"https://github.com/bozonx/ai-kit/issues"},"author":{"name":"Ivan K"},"license":"MIT","homepage":"https://github.com/bozonx/ai-kit","repository":{"url":"git+https://github.com/bozonx/ai-kit.git","type":"git"},"description":"Reusable core for building AI features: priced model catalog, model policy, provider adapters, retries, tools, embeddings and prompt assembly","maintainers":[{"name":"bozonx","email":"ipkozyrin@gmail.com"}],"readme":"# @bozonx/ai-kit\n\nThe part of an AI feature that is the same in every product.\n\nNot a model router, and no longer a microservice: a library you call in-process.\nIt holds a priced model catalog, the rules for choosing a model and retrying a\ncall, the vocabulary a streamed answer is made of, error classification, and the\nports through which a host supplies keys and observability.\n\nIt deliberately holds nothing about tenants, users, projects, permissions,\nstorage or money. If a component needs one of those words, it belongs to the\napplication, not here — and a test fails when it creeps in.\n\n> **Status: 0.4.0.** The package includes the catalog with multi-provider\n> routes, model-selection policy, provider registries, generation and streaming\n> execution with retries, prompt assembly, cost accounting, ports, error\n> taxonomy, speech-to-text — batch and live — over AssemblyAI, Deepgram, Groq\n> and any OpenAI-compatible server, subtitle rendering, and machine translation\n> over a dedicated engine with a binding glossary and deterministic quality\n> detectors. It runs on a server, in a browser and in a Tauri webview.\n>\n> **Upgrading from 0.3:** `Catalog.fromFile` is now `readCatalogFile` from\n> `@bozonx/ai-kit/node`, and every accounting object and `UsageEvent` carries\n> `priced`. See `docs/CHANGELOG.md`.\n\n## Install\n\n```bash\npnpm add @bozonx/ai-kit\n```\n\nDuring development, consume it through a workspace link so that changes are\nvisible without publishing.\n\n## Entry points\n\n| Import | What is in it |\n|---|---|\n| `@bozonx/ai-kit` | `createAiKit` and everything needed to call it: the catalog, pricing, policy, errors, ports, prompt assembly, tools, chat history compaction, request and result types |\n| `@bozonx/ai-kit/stt` | Speech extras: provider adapters, subtitles, word segmentation, audio helpers (`estimateAudioSeconds`, `SilenceDetector`, `PhraseChunker`, `pcm16ToWav`) |\n| `@bozonx/ai-kit/translate` | Translation extras: the Cloud Translation adapter, parallel text splitting, the binding glossary, the quality detectors |\n| `@bozonx/ai-kit/stream` | The stream-part types and the SSE codec (`encodeSse`, `SseDecoder`) |\n| `@bozonx/ai-kit/node` | What needs Node: `readCatalogFile` and `wsSocketOpener` |\n\nEvery entry point except `/node` loads without Node: the network goes through\nthe `Transport` port, hashing through Web Crypto, and a test walks the import\ngraph of each one to keep it that way. See [Running outside Node](#running-outside-node).\n\nThe kit is the way to call a model. The loops underneath it — retry, fallback,\npricing — are not exported on their own: a consumer that needs something the\nkit does not offer should get it added to the kit rather than reassemble the\nkit's internals by hand.\n\n## The catalog\n\nThe catalog is the main entity, not a lookup table. It says what a model costs,\nwhat it can do, and which tasks it is a candidate for — so changing the model\nbehind a product feature is an edit to a YAML file, not a release.\n\n```yaml\nmodels:\n  - name: gemini-2.5-flash\n    provider: google\n    model: gemini-2.5-flash\n    tier: standard # economy | standard | premium\n    contextSize: 1048576\n    maxOutputTokens: 65536\n    modalities:\n      input: [text, image, audio, pdf]\n      output: [text]\n    capabilities:\n      tools: true\n      structuredOutput: true\n      promptCaching: true\n    pricing:\n      version: '2026-08'\n      # Per million tokens, in micro-units of the currency: 1_000_000 = 1 USD.\n      inputPerMTok: 300000\n      outputPerMTok: 2500000\n      cachedInputPerMTok: 75000\n\ntaskClasses:\n  summarize: [gemini-2.5-flash, gpt-4.1-mini]\n  chat_agentic: [gemini-2.5-pro, claude-sonnet-4.5]\n```\n\n**Task class names are yours.** The library ships no list of them: `summarize`\nand `chat_agentic` above are this example's words, and a product about support\ntickets writes `triage` and `suggest_reply` instead. What the library works out\nfor itself is whether a class is served by language models, speech models or a\ntranslation engine — it reads that off the models nominated for it, and refuses\na catalog whose class mixes two kinds.\n\n```ts\nimport { calculateCost } from '@bozonx/ai-kit';\nimport { readCatalogFile } from '@bozonx/ai-kit/node';\n\n// Throws on a bad price, an unknown model in a task class, a duplicate name.\n// Loudly, at startup — a catalog that is wrong is a bill that is wrong.\n// Outside Node: `Catalog.fromYaml(text)` or `Catalog.fromObject(data)`.\nconst catalog = readCatalogFile('./models.yaml');\n\nconst model = catalog.require('gemini-2.5-flash');\nconst cost = calculateCost(model, {\n  inputTokens: 12_000,\n  cachedInputTokens: 8_000,\n  outputTokens: 900,\n  reasoningTokens: 0,\n});\n// cost.totalMicros, cost.priceVersion — hand these to your own accounting.\n```\n\n`pricing.version` exists so that history stays recomputable after a provider\nchanges prices. Record it with every call; without it a re-pricing turns the\npast into numbers nobody can defend.\n\nEvery model needs its price block — `pricing`, `sttPricing` or `mtPricing` —\nunless the catalog sets `requirePricing: false`. That is for a catalog nobody\nis billed through: a desktop app on the user's own key, a local model. An\nunpriced call is then recorded with `costMicros: 0`, `priceVersion: 'unpriced'`\nand `priced: false`, and a quote carries `priced: false` too — a bare zero is\nwhat a free call looks like, and a billing product must be able to tell the two\napart. Leave it on in anything that charges money.\n\n`tier` is the boundary a fallback may not cross. A premium model quietly\nreplaced by a free one is not a degraded answer, it is a different product.\n\n## Routes: the same model somewhere else\n\nA model definition carries one provider, and that provider is its first route.\n`routes:` adds backups — the same model at another provider, at another price,\ntried in `priority` order:\n\n```yaml\n  - name: claude-sonnet-4.5\n    provider: openrouter\n    model: anthropic/claude-sonnet-4.5\n    pricing: { version: '2026-08', inputPerMTok: 3000000, outputPerMTok: 15000000 }\n    routes:\n      - id: sonnet-direct # your own id, echoed back in the accounting\n        provider: anthropic\n        model: claude-sonnet-4-5\n        priority: 10\n        pricing: { version: '2026-08-direct', inputPerMTok: 3000000, outputPerMTok: 15000000 }\n        capabilities: { structuredOutput: true } # only what this route changes\n```\n\nEvery route of a model is tried before the next model is considered, which is\nwhat makes \"we try another route, never another model\" true for somebody who\npinned a model by name. The call is priced at the route that actually answered,\nand `routeId` travels through `CallAccounting`, the `model` stream part and the\nusage event — so a consumer with its own health automation can report a route\nas unhealthy through `demotedRoutes`, which moves it to the back of the list\nand never removes it.\n\n## Ports\n\nEverything the library needs from the outside arrives through `src/ports.ts`:\n`KeyProvider`, `UsageSink`, `TraceSink`, `AttemptObserver`, `Clock`,\n`Transport`. All are\noptional except keys — a library that cannot be called until five interfaces\nare implemented gets worked around instead of used.\n\n`UsageSink` is optional in practice too. Every result — and the `usage` part of\na stream — carries the full accounting, so a consumer that has to attach a\ntenant to each row can record from the result and leave the sink empty.\n`isProviderFault(kind)` says which failures a route's health should count.\n\nSinks are called best effort. A `UsageSink` that throws does not fail the call\nit was recording — the provider has answered and been paid by then — and is\nreported as a `<name>.usage-failed` span on the `TraceSink` instead. A call\nthat ends without an answer (every candidate failed, the time budget ran out,\nthe caller aborted) is still recorded, at zero cost, with its status and the\nnumber of attempts it took.\n\n`AttemptObserver` hears about every candidate that failed, by `routeId`,\nincluding the ones a fallback then covered for. The result of a call only\nnames the route that answered, so this is what a consumer's route health\nautomation feeds on. `AllCandidatesFailedError.failures` carries the same\n`routeId` for the case where nothing answered.\n\n### A customer's own key\n\nEvery request takes `keys`: credentials for that call only, by provider id,\napplied over the `KeyProvider`. There is no need to build a kit per customer.\n\n```ts\nawait kit.transcribe({\n  policy: { mode: 'auto', taskClass: 'transcription' },\n  source: { url },\n  keys: { deepgram: customerKey },\n});\n```\n\nClients are cached per provider, endpoint, model and a hash of the whole key,\nwith a bounded least-recently-used cache, so per-call keys neither leak memory\nnor share a client between two customers.\n\n## Choosing a model\n\nEvery call takes a `policy`. Only `taskClass` is required:\n\n```ts\n{ taskClass: 'chat' }                               // the catalog's order\n{ taskClass: 'chat', requestedModel: 'gpt-5-mini' } // pinned; mode is implied\n{ taskClass: 'chat', demotedRoutes: unhealthyIds }  // failing routes go last\n```\n\n`mode` may still be given explicitly; left out, a policy is `manual` exactly\nwhen `requestedModel` names something. `demotedRoutes` applies to a pinned\nmodel too — its failing route is tried after its healthy ones.\n\nFor a language-model call the `signals` are optional as well: the size of the\nrequest and whether it carries images are read off `system` and `messages`\n(the same `signalsFor` a consumer can call itself), and what the request asks\nfor — a schema, tools, streaming, an output allowance — is added on top.\n\n## Quoting before a call\n\nA consumer that reserves budget has to hold enough for the dearest candidate\nin the fallback chain, not only the first. `quoteCandidates` lists every\ncandidate `selectCandidates` would try with its worst-case cost — tokens for a\nlanguage model, seconds for speech, characters for an engine — and leaves the\nchoice of maximum to the caller, whose markup may depend on the price:\n\n```ts\nconst quotes = quoteCandidates(policy, kit.catalog, { characters: 12_000 });\nconst hold = Math.max(0, ...quotes.map(quote => quote.costMicros));\n```\n\nFor a language-model call, `kit.plan(request)` does the selection once and\nreturns the candidates, their quotes and the output allowance capped at the\nfirst candidate's limit. Hand it back as `plan` on the same request, and the\ncall tries exactly the candidates the hold was sized for:\n\n```ts\nconst plan = kit.plan(request);\nawait reserve(Math.max(0, ...plan.quotes.map(quote => quote.costMicros)));\nconst result = await kit.generate({ ...request, plan, maxOutputTokens: plan.maxOutputTokens });\n```\n\nEach attempt is sent at most the output its own model can produce, so a\nfallback to a model with a smaller limit is not refused for a number chosen for\nanother one.\n\nSpeech and translation plan the same way. `kit.planTranslation(request)`\nquotes every engine exactly, from the characters in hand;\n`kit.planTranscription(request, { audioSeconds, realtime })` quotes every speech\nmodel for the audio expected. Both return `{ candidates, quotes }`, and both\nrequests accept it back as `plan`.\n\n## Streaming\n\n`StreamPart` is one vocabulary for both ends of the connection —\n`model`, `text-delta`, `reasoning-delta`, `tool-call`, `tool-result`, `sources`,\n`usage`, `error`, `finish`. The consumer's frontend imports the type rather than\ndescribing it a second time, because two hand-written copies of a wire format\ndrift the first time a field is added.\n\n`usage` arrives once, after the answer and before `finish` or `error`. A\nconsumer may stop reading at any point: the provider request is then cancelled\nand the call is still recorded through the `UsageSink`, as `aborted`, with\nwhatever it produced — the answer, reasoning and tool calls alike.\n`callStatusFor(kind)` maps an `error` part's kind to the status to record it\nunder.\n\nThe `usage` part is the full `CallAccounting` that `generate` returns: model,\nroute, `routedBy`, tokens, cost, price version, attempts and latency.\n\nOver HTTP the parts travel as server-sent events, and both halves of that are\nin `@bozonx/ai-kit/stream`, with no Node or AI SDK imports:\n\n```ts\n// Server: write each part wherever the framework lets you write.\nresponse.write(encodeSse(part));\nresponse.write(encodeSse({ id }, 'saved')); // a named event\n\n// Browser: feed decoded text, get complete events back.\nconst decoder = new SseDecoder();\nfor (const { event, data } of decoder.push(textDecoder.decode(chunk, { stream: true }))) {\n  // event === 'message' for a part\n}\n```\n\n## Tools and provider options\n\n`generate` and `stream` take `tools` (defined with the re-exported `tool`),\n`toolChoice` and `maxSteps`. Tools make `needsTools` true, so only candidates\nwhose route can call tools are tried. With `maxSteps` above 1 the SDK runs the\nloop — tool call, tool result, next step — and every step is paid for:\n\n```ts\nimport { tool } from '@bozonx/ai-kit';\n\nconst result = await kit.generate({\n  policy: { mode: 'auto', taskClass: 'chat_agentic', signals: { estimatedInputTokens: 800 } },\n  messages,\n  maxSteps: 4,\n  tools: {\n    search: tool({\n      description: 'Search the web',\n      inputSchema: z.object({ query: z.string() }),\n      execute: ({ query }) => search(query),\n    }),\n  },\n});\n// result.toolCalls, result.steps, result.responseMessages (append for the next turn)\n```\n\nNothing is retried after the first visible part, and a tool call is visible:\na tool with side effects never runs twice because of a retry.\n\n`providerOptions` passes settings for one provider through untouched — a\nthinking budget, a cache breakpoint — keyed by provider id, so a fallback to\nanother provider ignores what was not meant for it.\n\n`signalsFor({ system, messages })` derives `estimatedInputTokens` and\n`hasImages` from the request itself, multi-part messages included.\n\n## Embeddings\n\nThe fourth kind of model. `kit.embed` returns one vector per value and bills\nthe input tokens the provider counted:\n\n```ts\nconst result = await kit.embed({\n  policy: { mode: 'manual', taskClass: 'search_index', requestedModel: 'gemini-embedding-001' },\n  values: chunks,\n});\n// result.embeddings, result.dimensions, result.tokens, result.costMicros\n```\n\nPin the model when the vectors go into an existing index: vectors of two\ndifferent models are not comparable, and only another route of the same model\nis a safe fallback.\n\n## Chat history\n\n`compactHistory` keeps the newest messages that fit a token budget and a\nmessage count, counts a rolling summary against the same budget, and reports\nwhich dropped messages the summary does not cover yet (`unsummarized`,\n`summaryStale`) — so the caller knows when a rebuild is worth a model call.\n\n## Speech\n\nTranscription is the catalog's second kind of model, not a second catalog:\n\n```ts\nconst result = await kit.transcribe({\n  policy: { mode: 'auto', taskClass: 'transcription' },\n  options: { language: 'en', wordTimings: true },\n  source: { url: presignedUrl },\n});\n\nfor await (const part of kit.transcribeStream({\n  policy: { mode: 'auto', taskClass: 'dictation' },\n  options: { language: 'en' },\n  audio: pcm16Frames,\n})) {\n  // 'model' | 'partial' | 'final' | 'usage' | 'error' | 'finish'\n}\n```\n\nThree things about it are worth knowing before the first invoice:\n\nFor batch audio, the provider's reported duration is used when available. If it\nomits duration, the kit reads a complete PCM WAV header or uses the caller's\n`knownAudioSeconds`; other unmeasured formats fail rather than being charged\nfrom a byte-size guess. A `ReadableStream` source is buffered once (up to\n256 MiB) so retry attempts send identical audio.\n\n- **Speech is priced by the hour of audio**, in `sttPricing`, and a model may\n  have that block or `pricing` but never both. Seconds are rounded up to whole\n  seconds before anything is multiplied, because that is how providers bill.\n- **A live session is billed for the time it is open**, not for the words that\n  came out of it. Silence costs the same as talking, which is why a dictation\n  session that nobody is speaking into has to be closed rather than left idle.\n- **`partial` may be rewritten in full; `final` never changes.** Text shown as\n  settled and then altered reads as a bug to whoever is watching it appear.\n\nA speech model can never be routed a language task, or the other way round: the\ncatalog refuses to load when a task class nominates models of two kinds.\n\nWithout a realtime provider, dictation is a series of short batch calls.\n`PhraseChunker` (from `@bozonx/ai-kit/stt`) cuts live PCM into phrases on a\npause, or at a ceiling when nobody pauses, and tells each phrase where it\nstarts in the session so its segments land on one timeline:\n\n```ts\nconst chunker = new PhraseChunker({ maxSeconds: 30, silenceMs: 1_200 });\nfor await (const chunk of microphone) {\n  const phrase = chunker.push(chunk.data);\n  if (phrase) await send(pcm16ToWav(phrase.pcm, 16_000), phrase.offsetMs);\n}\nconst last = chunker.flush();\n```\n\n`renderSubtitles` (from `@bozonx/ai-kit/stt`) turns stored segments into SRT or WebVTT, cutting long cues on\na real pause when word timings are there and proportionally when they are not.\n`segmentWords` is its other half: providers return one flat word list for a\nwhole recording and segments separately, and this puts the two together.\n\n## Translation\n\nThe catalog's third kind of model is a dedicated translation engine, billed by\nthe character:\n\n```ts\nconst result = await kit.translate({\n  policy: { mode: 'auto', taskClass: 'translate_fast' },\n  texts: ['Hello there'],\n  targetLanguage: 'ru',\n  format: 'text',\n});\n// result.translations, result.characters, result.costMicros, result.priceVersion\n```\n\nUnlike a language model, the price is exact before the call: the characters are\ncounted from the text in hand, so a quote shown to a customer and the amount\nfinally charged can be the same number.\n\nThe built-in Cloud Translation adapter is registered as `google-translate`,\nnot `google`: that id is Gemini's, and a `KeyProvider` is asked for a key by\nprovider id — the two products take different credentials.\n\nThree pieces of the surrounding machinery live in `@bozonx/ai-kit/translate`,\nbecause they are the same in every product that translates and quietly wrong\nwhen rewritten from memory. `chunkText` (main entry) cuts long text between\nwords to fit a request limit.\n\n- **`splitParallelText`** — a source and its translation cut into pairs that\n  still correspond, for a repair pass over a long text: at paragraphs when both\n  sides have the same number, then lines, then sentences, and only then\n  proportionally — on a boundary, never through a word.\n- **`glossary.ts`** — a binding glossary, applied three times and differently\n  each time: only the terms that occur in the text go into the prompt, a\n  \"do not translate\" term whose spelling only changed by case is restored\n  deterministically, and any other violated term is reported for repair. A\n  caller that needs an absolute byte-for-byte guarantee should protect those\n  terms before sending text to a machine-translation engine.\n- **`quality.ts`** — deterministic detectors that run on every translation:\n  an empty result, passages left in the source language, lost links and\n  placeholders, a structure that no longer matches, looping, truncation, an\n  unexpected writing system. No model takes part, which is what makes them free\n  to run and explainable to whoever is shown the result.\n- **`runTranslationPipeline`** — one first pass, deterministic checks and at\n  most one optional repair pass. When the first pass detects its source\n  language, the pipeline uses it for same-language checks unless the caller\n  supplied a source language explicitly.\n\n`chunkText` limits each returned string; it does not split one provider call\ninto several requests. Consumers must batch or send the chunks separately when\nthe provider limits the total request body or number of strings.\n\n## Running outside Node\n\n`transport` on `createAiKit` is how the kit reaches the network. Either half may\nbe given alone; the defaults are the platform's `fetch` and `WebSocket`.\n\n```ts\nimport { fetch } from '@tauri-apps/plugin-http';\n\nconst kit = createAiKit({\n  catalog: Catalog.fromObject(catalogData),\n  keys: { get: provider => keychain.get(provider) },\n  transport: { fetch },\n});\n```\n\n- **`fetch`** carries every HTTP request — language models through the AI SDK,\n  speech, translation. In a Tauri app, the HTTP plugin's `fetch` gets past the\n  CORS rules a webview would otherwise apply to provider APIs.\n- **`openSocket`** opens live speech sessions. Every speech provider\n  authenticates one with a request header, which Node, Deno and Bun can send\n  through the platform `WebSocket` and a browser cannot. In a browser, pass an\n  opener that can (a Tauri WebSocket plugin, or a proxy of your own); without\n  one, a live session fails with `invalid_request` rather than being retried as\n  an outage. `wsSocketOpener` from `@bozonx/ai-kit/node` is the `ws`-based\n  opener, for a Node host that prefers it.\n- **Keys in a browser are the user's keys.** A `KeyProvider` in a desktop app\n  reads the user's own key from the OS keychain; a key your company pays for\n  has no place in a web page, and nothing here makes that safe.\n- Anthropic refuses browser-origin requests unless told otherwise; through a\n  Tauri HTTP plugin the request is not browser-origin and nothing extra is\n  needed.\n- Web Crypto's `subtle` exists only in a secure context (HTTPS, `localhost`, a\n  Tauri webview), and the client cache hashes keys with it.\n\n### OpenAI-compatible servers and DeepSeek\n\n`openai-compatible` is a built-in provider for any server that speaks OpenAI's\nAPI — Ollama, LM Studio, vLLM, a company proxy — for chat, embeddings and, in\nthe speech registry, `/audio/transcriptions`. It has no default endpoint, so\nthe catalog sets `baseUrl`, and it sends no `Authorization` header when the\n`KeyProvider` returns an empty key. `deepseek` is built in as well.\n\n```yaml\nrequirePricing: false\nmodels:\n  - name: local-llama\n    provider: openai-compatible\n    model: llama3.1\n    baseUrl: http://localhost:11434/v1\n    tier: standard\n    contextSize: 131072\n    maxOutputTokens: 4096\n```\n\n## Installing only what you use\n\n`zod` is a peer dependency, so the schemas you pass and the ones the package\nvalidates with are the same copy. The provider SDKs (`@ai-sdk/google`,\n`@ai-sdk/openai`, `@ai-sdk/anthropic`, `@ai-sdk/deepseek`,\n`@ai-sdk/openai-compatible`, `@openrouter/ai-sdk-provider`) and `ws` are\noptional peer dependencies, loaded the first time a route asks for one. A\nproduct that only calls OpenAI installs `@ai-sdk/openai` and nothing else; `ws`\nis needed only by `wsSocketOpener`. A missing package produces a sentence\nnaming what to install rather than a module-resolution stack trace.\n\n`@bozonx/ai-kit/stream` holds only the stream-part types and the SSE codec, for\na page that renders a stream the server produced.\n\n## Development\n\n```bash\npnpm install\npnpm check   # lint, typecheck, format, tests\npnpm build\n```\n\n## Licence\n\nMIT.\n","readmeFilename":"README.md"}