@longzai-intelligence-model-gateway/core 0.0.2 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- import{z as e}from"zod";import{DomainError as t}from"@longzai-intelligence/error";import{DomainEvent as n,Entity as r,failure as i,success as a}from"@longzai-intelligence/shared-kernel";import{eq as o,lt as s}from"drizzle-orm";let c=function(e){return e.INVALID_REQUEST=`invalid_request`,e.AUTHENTICATION_FAILED=`authentication_failed`,e.PERMISSION_DENIED=`permission_denied`,e.MODEL_NOT_FOUND=`model_not_found`,e.BUDGET_EXCEEDED=`budget_exceeded`,e.RATE_LIMIT_EXCEEDED=`rate_limit_exceeded`,e.INVALID_API_KEY=`invalid_api_key`,e.INTERNAL_ERROR=`internal_error`,e.ROUTING_ERROR=`routing_error`,e.DATABASE_ERROR=`database_error`,e.CACHE_ERROR=`cache_error`,e.PROVIDER_UNAVAILABLE=`provider_unavailable`,e.PROVIDER_RATE_LIMITED=`provider_rate_limited`,e.PROVIDER_TIMEOUT=`provider_timeout`,e.PROVIDER_ERROR=`provider_error`,e.MODEL_OVERLOADED=`model_overloaded`,e.CONTEXT_LENGTH_EXCEEDED=`context_length_exceeded`,e}({});const l={client:400,server:500,provider:502},u={maxRetries:3,initialInterval:1e3,maxInterval:3e4,multiplier:2,retryableStatusCodes:[429,500,502,503,504],retryableErrorCodes:[`provider_timeout`,`provider_unavailable`,`model_overloaded`]},d={connectTimeout:1e4,readTimeout:6e4,writeTimeout:1e4,requestTimeout:12e4},f={actions:[`fallback_model`,`cache_result`,`reject`],fallbackModels:[],allowCache:!0,maxFallbacks:2},p={retry:u,timeout:d,fallback:f};function m(e,t,n){let r=t/1e3*e.inputPrice,i=n/1e3*e.outputPrice;return Number((r+i).toFixed(8))}function h(e){return e<.01?`$${e.toFixed(6)}`:e<1?`$${e.toFixed(4)}`:`$${e.toFixed(2)}`}function g(e,t){return t<=0?0:Math.min(100,Number((e/t*100).toFixed(2)))}const _=`AES-GCM`;function v(e){let t=``;for(let n=0;n<e.length;n++)t+=String.fromCharCode(e[n]);return btoa(t)}function y(e){let t=atob(e),n=new Uint8Array(t.length);for(let e=0;e<t.length;e++)n[e]=t.charCodeAt(e);return n}async function b(e){let t=new TextEncoder,n=await crypto.subtle.importKey(`raw`,t.encode(e),{name:`PBKDF2`},!1,[`deriveKey`]);return crypto.subtle.deriveKey({name:`PBKDF2`,salt:t.encode(`model-gateway-salt`),iterations:1e5,hash:`SHA-256`},n,{name:_,length:256},!1,[`encrypt`,`decrypt`])}async function x(e,t){let n=await b(t),r=new TextEncoder,i=crypto.getRandomValues(new Uint8Array(12)),a=await crypto.subtle.encrypt({name:_,iv:i,tagLength:128},n,r.encode(e)),o=new Uint8Array(i.length+new Uint8Array(a).length);return o.set(i),o.set(new Uint8Array(a),i.length),v(o)}async function S(e,t){let n=await b(t),r=y(e),i=r.slice(0,12),a=r.slice(12),o=await crypto.subtle.decrypt({name:_,iv:i,tagLength:128},n,a);return new TextDecoder().decode(o)}function C(e){if(!e)return 0;let t=0,n=0;for(let r of e)/[\u4e00-\u9fff\u3400-\u4dbf]/.test(r)?t++:n++;return Math.ceil(t/1.5+n/4)}function w(e){let t=0;for(let n of e)if(t+=4,typeof n.content==`string`)t+=C(n.content);else if(Array.isArray(n.content))for(let e of n.content)e&&typeof e==`object`&&`text`in e&&typeof e.text==`string`&&(t+=C(e.text));return t}const T=Symbol(`CachePort`),E=e.object({requestHash:e.string().min(1),requestVector:e.string().optional(),responseData:e.string().min(1),modelId:e.string().min(1),similarityThreshold:e.number().min(0).max(1).optional(),ttlSeconds:e.number().min(0).optional()});var D=class extends t{constructor(e){super(e,`CACHE_ERROR`),this.name=`CacheError`}},O=class e extends n{cacheEntryId;modelId;static TYPE=`cache:hit`;type=e.TYPE;constructor(e,t,n){super(e),this.cacheEntryId=t,this.modelId=n}},k=class e extends r{get requestHash(){return this._props.requestHash}get requestVector(){return this._props.requestVector}get responseData(){return this._props.responseData}get modelId(){return this._props.modelId}get similarityThreshold(){return this._props.similarityThreshold}get hitCount(){return this._props.hitCount}get expiresAt(){return this._props.expiresAt}get createdAt(){return this._props.createdAt}constructor(e,t){super(e,t)}static create(t,n){let r=new Date,i=(n.ttlSeconds??3600)*1e3,a=n.expiresAt??new Date(r.getTime()+i).toISOString();return new e(t,{requestHash:n.requestHash,requestVector:n.requestVector,responseData:n.responseData,modelId:n.modelId,similarityThreshold:n.similarityThreshold,hitCount:0,expiresAt:a,createdAt:r.toISOString()})}static reconstitute(t,n){return new e(t,n)}recordHit(){this.updateProps(`hitCount`,this._props.hitCount+1)}isExpired(){return new Date(this._props.expiresAt)<new Date}};const A={toDTO(e){return{id:e.id,requestHash:e.requestHash,requestVector:e.requestVector,responseData:e.responseData,modelId:e.modelId,similarityThreshold:e.similarityThreshold,hitCount:e.hitCount,expiresAt:e.expiresAt,createdAt:e.createdAt}},toDTOList(e){return e.map(e=>this.toDTO(e))}},j={toDomain(e){return k.reconstitute(e.id,{requestHash:e.requestHash,requestVector:e.requestVector,responseData:e.responseData,modelId:e.modelId,similarityThreshold:e.similarityThreshold,hitCount:e.hitCount,expiresAt:e.expiresAt,createdAt:e.createdAt})},toOrm(e){return{id:e.id,requestHash:e.requestHash,requestVector:e.requestVector,responseData:e.responseData,modelId:e.modelId,similarityThreshold:e.similarityThreshold,hitCount:e.hitCount,expiresAt:e.expiresAt,createdAt:e.createdAt}}};var M=class{db;schema;constructor(e,t){this.db=e,this.schema=t}async getByHash(e){try{let t=(await this.db.select().from(this.schema.cacheEntries).where(o(this.schema.cacheEntries.requestHash,e)))[0]??null;return a(t?j.toDomain(t):null)}catch(e){return i(new D(`查询缓存条目失败: ${e.message}`))}}async create(e){try{let t=j.toOrm(e);return await this.db.insert(this.schema.cacheEntries).values(t),a(e)}catch(e){return i(new D(`创建缓存条目失败: ${e.message}`))}}async recordHit(e){try{let t=(await this.db.select().from(this.schema.cacheEntries).where(o(this.schema.cacheEntries.id,e)))[0];if(!t)return i(new D(`缓存条目不存在: ${e}`));let n=j.toDomain(t);return n.recordHit(),await this.db.update(this.schema.cacheEntries).set({hitCount:n.hitCount}).where(o(this.schema.cacheEntries.id,e)),a(n)}catch(e){return i(new D(`记录缓存命中失败: ${e.message}`))}}async delete(e){try{return await this.db.delete(this.schema.cacheEntries).where(o(this.schema.cacheEntries.id,e)),a(!0)}catch(e){return i(new D(`删除缓存条目失败: ${e.message}`))}}async deleteExpired(){try{let e=new Date().toISOString();return a((await this.db.delete(this.schema.cacheEntries).where(s(this.schema.cacheEntries.expiresAt,e)))?.changes??0)}catch(e){return i(new D(`清理过期缓存失败: ${e.message}`))}}},N=class{repository;constructor(e){this.repository=e}async execute(e){let t=await this.repository.getByHash(e);if(t.isFailure)return t;let n=t.value;if(!n)return a(null);if(n.isExpired())return await this.repository.delete(n.id),a(null);let r=await this.repository.recordHit(n.id);return r.isFailure?r:a(r.value)}},P=class{repository;constructor(e){this.repository=e}async execute(e){try{let t=`cache_${Date.now()}_${Math.random().toString(36).substring(2,9)}`,n=k.create(t,{requestHash:e.requestHash,requestVector:e.requestVector??null,responseData:e.responseData,modelId:e.modelId,similarityThreshold:e.similarityThreshold??.95,ttlSeconds:e.ttlSeconds,expiresAt:new Date(Date.now()+(e.ttlSeconds??3600)*1e3).toISOString()});return this.repository.create(n)}catch(e){return i(new D(`创建缓存条目失败: ${e.message}`))}}},F=class{repository;constructor(e){this.repository=e}async execute(e){return this.repository.recordHit(e)}},I=class{repository;constructor(e){this.repository=e}async execute(e){return this.repository.delete(e)}},L=class{repository;constructor(e){this.repository=e}async execute(){return this.repository.deleteExpired()}},R=class{store=new Map;constructor(){}async getByHash(e){try{for(let t of this.store.values())if(t.requestHash===e)return t.isExpired()?(this.store.delete(t.id),a(null)):(t.recordHit(),a(A.toDTO(t)));return a(null)}catch(e){return i(new D(`内存缓存查询失败: ${e.message}`))}}async create(e){try{let t=`cache_${Date.now()}_${Math.random().toString(36).substring(2,9)}`,n=k.create(t,{requestHash:e.requestHash,requestVector:e.requestVector??null,responseData:e.responseData,modelId:e.modelId,similarityThreshold:e.similarityThreshold??.95,ttlSeconds:e.ttlSeconds,expiresAt:new Date(Date.now()+(e.ttlSeconds??3600)*1e3).toISOString()});return this.store.set(t,n),a(A.toDTO(n))}catch(e){return i(new D(`内存缓存创建失败: ${e.message}`))}}async recordHit(e){try{let t=this.store.get(e);return t?(t.recordHit(),a(A.toDTO(t))):i(new D(`缓存条目不存在: ${e}`))}catch(e){return i(new D(`内存缓存命中记录失败: ${e.message}`))}}async delete(e){try{return a(this.store.delete(e))}catch(e){return i(new D(`内存缓存删除失败: ${e.message}`))}}async deleteExpired(){try{let e=0;for(let[t,n]of this.store.entries())n.isExpired()&&(this.store.delete(t),e++);return a(e)}catch(e){return i(new D(`内存缓存清理失败: ${e.message}`))}}},z=class{getCacheEntry;createCacheEntry;recordCacheHit;deleteCacheEntry;cleanupCacheEntries;constructor(e){this.getCacheEntry=new N(e),this.createCacheEntry=new P(e),this.recordCacheHit=new F(e),this.deleteCacheEntry=new I(e),this.cleanupCacheEntries=new L(e)}async getByHash(e){let t=await this.getCacheEntry.execute(e);if(t.isFailure)return t;let n=t.value;return a(n?A.toDTO(n):null)}async create(e){let t=await this.createCacheEntry.execute(e);return t.isFailure?t:a(A.toDTO(t.value))}async recordHit(e){let t=await this.recordCacheHit.execute(e);return t.isFailure?t:a(A.toDTO(t.value))}async delete(e){return this.deleteCacheEntry.execute(e)}async deleteExpired(){return this.cleanupCacheEntries.execute()}};function B(e,t){return new z(new M(e,t))}const V=Symbol(`EVENT_PUBLISHER_PORT_TOKEN`);export{T as CACHE_PORT_TOKEN,k as CacheEntryEntity,A as CacheEntryMapper,j as CacheEntryOrmMapper,D as CacheError,O as CacheHitEvent,R as CacheMemoryAdapter,L as CleanupCacheEntriesUseCase,P as CreateCacheEntryUseCase,p as DEFAULT_EXECUTION_STRATEGY,f as DEFAULT_FALLBACK_STRATEGY,u as DEFAULT_RETRY_STRATEGY,d as DEFAULT_TIMEOUT_STRATEGY,I as DeleteCacheEntryUseCase,M as DrizzleCacheRepository,l as ERROR_STATUS_MAP,V as EVENT_PUBLISHER_PORT_TOKEN,c as ErrorCode,N as GetCacheEntryUseCase,F as RecordCacheHitUseCase,g as budgetUsagePercent,m as calculateCost,E as createCacheEntrySchema,B as createCacheSqliteAdapter,S as decrypt,x as encrypt,w as estimateMessagesTokens,C as estimateTokens,h as formatCost};
1
+ import*as e from"zod";import{DomainError as t}from"@longzai-intelligence-error/core";import{DomainEvent as n,Entity as r}from"@longzai-intelligence-shared-kernel/core";let i=function(e){return e.INVALID_REQUEST=`invalid_request`,e.AUTHENTICATION_FAILED=`authentication_failed`,e.PERMISSION_DENIED=`permission_denied`,e.MODEL_NOT_FOUND=`model_not_found`,e.BUDGET_EXCEEDED=`budget_exceeded`,e.RATE_LIMIT_EXCEEDED=`rate_limit_exceeded`,e.INVALID_API_KEY=`invalid_api_key`,e.INTERNAL_ERROR=`internal_error`,e.ROUTING_ERROR=`routing_error`,e.DATABASE_ERROR=`database_error`,e.CACHE_ERROR=`cache_error`,e.PROVIDER_UNAVAILABLE=`provider_unavailable`,e.PROVIDER_RATE_LIMITED=`provider_rate_limited`,e.PROVIDER_TIMEOUT=`provider_timeout`,e.PROVIDER_ERROR=`provider_error`,e.MODEL_OVERLOADED=`model_overloaded`,e.CONTEXT_LENGTH_EXCEEDED=`context_length_exceeded`,e}({});const a={client:400,server:500,provider:502},o={maxRetries:3,initialInterval:1e3,maxInterval:3e4,multiplier:2,retryableStatusCodes:[429,500,502,503,504],retryableErrorCodes:[`provider_timeout`,`provider_unavailable`,`model_overloaded`]},s={connectTimeout:1e4,readTimeout:6e4,writeTimeout:1e4,requestTimeout:12e4},c={actions:[`fallback_model`,`cache_result`,`reject`],fallbackModels:[],allowCache:!0,maxFallbacks:2},l={retry:o,timeout:s,fallback:c};function u(e,t,n){let r=t/1e3*e.inputPrice,i=n/1e3*e.outputPrice;return Number((r+i).toFixed(8))}function d(e){return e<.01?`$${e.toFixed(6)}`:e<1?`$${e.toFixed(4)}`:`$${e.toFixed(2)}`}function f(e,t){return t<=0?0:Math.min(100,Number((e/t*100).toFixed(2)))}const p=`AES-GCM`;function m(e){let t=``;for(let n=0;n<e.length;n++)t+=String.fromCharCode(e[n]);return btoa(t)}function h(e){let t=atob(e),n=new Uint8Array(t.length);for(let e=0;e<t.length;e++)n[e]=t.charCodeAt(e);return n}async function g(e){let t=new TextEncoder,n=await crypto.subtle.importKey(`raw`,t.encode(e),{name:`PBKDF2`},!1,[`deriveKey`]);return crypto.subtle.deriveKey({name:`PBKDF2`,salt:t.encode(`model-gateway-salt`),iterations:1e5,hash:`SHA-256`},n,{name:p,length:256},!1,[`encrypt`,`decrypt`])}async function _(e,t){let n=await g(t),r=new TextEncoder,i=crypto.getRandomValues(new Uint8Array(12)),a=await crypto.subtle.encrypt({name:p,iv:i,tagLength:128},n,r.encode(e)),o=new Uint8Array(i.length+new Uint8Array(a).length);return o.set(i),o.set(new Uint8Array(a),i.length),m(o)}async function v(e,t){let n=await g(t),r=h(e),i=r.slice(0,12),a=r.slice(12),o=await crypto.subtle.decrypt({name:p,iv:i,tagLength:128},n,a);return new TextDecoder().decode(o)}function y(e){if(!e)return 0;let t=0,n=0;for(let r of e)/[\u4e00-\u9fff\u3400-\u4dbf]/.test(r)?t++:n++;return Math.ceil(t/1.5+n/4)}function b(e){let t=0;for(let n of e)if(t+=4,typeof n.content==`string`)t+=y(n.content);else if(Array.isArray(n.content))for(let e of n.content)e&&typeof e==`object`&&`text`in e&&typeof e.text==`string`&&(t+=y(e.text));return t}const x=Symbol(`CachePort`),S=e.object({requestHash:e.string().min(1),requestVector:e.string().optional(),responseData:e.string().min(1),modelId:e.string().min(1),similarityThreshold:e.number().min(0).max(1).optional(),ttlSeconds:e.number().min(0).optional()});var C=class extends t{constructor(e){super(e,`CACHE_ERROR`),this.name=`CacheError`}},w=class e extends n{cacheEntryId;modelId;static TYPE=`cache:hit`;type=e.TYPE;constructor(e,t,n){super(e),this.cacheEntryId=t,this.modelId=n}},T=class e extends r{get requestHash(){return this._props.requestHash}get requestVector(){return this._props.requestVector}get responseData(){return this._props.responseData}get modelId(){return this._props.modelId}get similarityThreshold(){return this._props.similarityThreshold}get hitCount(){return this._props.hitCount}get expiresAt(){return this._props.expiresAt}get createdAt(){return this._props.createdAt}constructor(e,t){super(e,t)}static create(t,n){let r=new Date,i=(n.ttlSeconds??3600)*1e3,a=n.expiresAt??new Date(r.getTime()+i).toISOString();return new e(t,{requestHash:n.requestHash,requestVector:n.requestVector,responseData:n.responseData,modelId:n.modelId,similarityThreshold:n.similarityThreshold,hitCount:0,expiresAt:a,createdAt:r.toISOString()})}static reconstitute(t,n){return new e(t,n)}recordHit(){this.updateProps(`hitCount`,this._props.hitCount+1)}isExpired(){return new Date(this._props.expiresAt)<new Date}};const E={toDTO(e){return{id:e.id,requestHash:e.requestHash,requestVector:e.requestVector,responseData:e.responseData,modelId:e.modelId,similarityThreshold:e.similarityThreshold,hitCount:e.hitCount,expiresAt:e.expiresAt,createdAt:e.createdAt}},toDTOList(e){return e.map(e=>this.toDTO(e))}},D=Symbol(`ModelRepositoryPort`),O=Symbol(`RoutingRuleRepositoryPort`),k=Symbol(`LlmCompletePort`),A=Symbol(`EVENT_PUBLISHER_PORT_TOKEN`);export{x as CACHE_PORT_TOKEN,T as CacheEntryEntity,E as CacheEntryMapper,C as CacheError,w as CacheHitEvent,l as DEFAULT_EXECUTION_STRATEGY,c as DEFAULT_FALLBACK_STRATEGY,o as DEFAULT_RETRY_STRATEGY,s as DEFAULT_TIMEOUT_STRATEGY,a as ERROR_STATUS_MAP,A as EVENT_PUBLISHER_PORT_TOKEN,i as ErrorCode,k as LLM_COMPLETE_PORT_TOKEN,D as MODEL_REPOSITORY_PORT_TOKEN,O as ROUTING_RULE_REPOSITORY_PORT_TOKEN,f as budgetUsagePercent,u as calculateCost,S as createCacheEntrySchema,v as decrypt,_ as encrypt,b as estimateMessagesTokens,y as estimateTokens,d as formatCost};
package/package.json CHANGED
@@ -1,43 +1,49 @@
1
1
  {
2
2
  "name": "@longzai-intelligence-model-gateway/core",
3
- "version": "0.0.2",
4
- "description": "Core types and utilities for Model Gateway - AI model routing, rate limiting, and observability",
3
+ "version": "0.0.4",
5
4
  "private": false,
5
+ "description": "Longzai Intelligence Model Gateway 核心类型与工具函数",
6
+ "keywords": [
7
+ "core",
8
+ "longzai-intelligence",
9
+ "model-gateway",
10
+ "types",
11
+ "utilities"
12
+ ],
6
13
  "license": "UNLICENSED",
7
- "type": "module",
8
14
  "files": [
9
15
  "dist"
10
16
  ],
17
+ "type": "module",
11
18
  "main": "./dist/index.js",
12
19
  "types": "./dist/index.d.ts",
13
- "publishConfig": {
14
- "access": "public"
15
- },
16
20
  "exports": {
17
21
  ".": {
18
22
  "types": "./dist/index.d.ts",
19
23
  "import": "./dist/index.js"
20
24
  }
21
25
  },
26
+ "publishConfig": {
27
+ "access": "public"
28
+ },
22
29
  "scripts": {
23
- "build": "tsgo --build tsconfig/build.json && resolve-aliases -p tsconfig/build.json",
24
- "build:prod": "NODE_ENV=production tsdown",
30
+ "build": "lzi-builder",
31
+ "build:prod": "NODE_ENV=production bun run build",
25
32
  "prepublishOnly": "bun run build:prod",
26
33
  "typecheck": "bun run typecheck:app && bun run typecheck:node && bun run typecheck:test",
27
- "typecheck:app": "tsgo --noEmit -p tsconfig/app.json",
28
- "typecheck:node": "tsgo --noEmit -p tsconfig/node.json",
29
- "typecheck:test": "tsgo --noEmit -p tsconfig/test.json",
34
+ "typecheck:app": "lzi-tsgo typecheck tsconfig/app.json",
35
+ "typecheck:node": "lzi-tsgo typecheck tsconfig/node.json",
36
+ "typecheck:test": "lzi-tsgo typecheck tsconfig/test.json",
30
37
  "lint": "oxlint && oxfmt --check",
31
38
  "lint:fix": "oxlint --fix && oxfmt",
32
39
  "test": "bun test",
33
40
  "test:watch": "bun test --watch",
34
41
  "test:coverage": "bun test --coverage",
35
- "clean": "rm -rf dist"
42
+ "clean": "lzi-dev-cli clean"
36
43
  },
37
44
  "dependencies": {
38
- "@longzai-intelligence/shared-kernel": "^0.1.4",
39
- "@longzai-intelligence/error": "^0.0.5",
40
- "drizzle-orm": "^0.38.0",
45
+ "@longzai-intelligence-error/core": "^0.1.0",
46
+ "@longzai-intelligence-shared-kernel/core": "^0.1.4",
41
47
  "zod": "^4.4.3"
42
48
  },
43
49
  "devDependencies": {}