bazis 0.96.1

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.
Files changed (513) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +146 -0
  3. package/cli/build.ts +147 -0
  4. package/cli/codegen.ts +40 -0
  5. package/cli/generateModule.ts +187 -0
  6. package/cli/generateProject.ts +183 -0
  7. package/cli/main.ts +125 -0
  8. package/cli/moduleRegistration.ts +127 -0
  9. package/cli/naming.ts +124 -0
  10. package/cli/parseCli.ts +151 -0
  11. package/cli/templates/module.ts +497 -0
  12. package/cli/templates/pack.ts +76 -0
  13. package/cli/templates/passport.ts +178 -0
  14. package/core/agent/AgentContextBuilder.ts +567 -0
  15. package/core/agent/AgentDataDefinition.ts +8 -0
  16. package/core/agent/AgentRegistry.ts +539 -0
  17. package/core/agent/AgentRuntime.ts +47 -0
  18. package/core/agent/AgentToolExecutor.ts +2130 -0
  19. package/core/agent/AgentToolHooks.ts +39 -0
  20. package/core/agent/ModelProvider.ts +21 -0
  21. package/core/agent/README.md +229 -0
  22. package/core/agent/Tool.contract.ts +20 -0
  23. package/core/agent/decorators/Agent.ts +11 -0
  24. package/core/agent/decorators/Prompt.ts +11 -0
  25. package/core/agent/decorators/Task.ts +29 -0
  26. package/core/agent/decorators/Tool.ts +12 -0
  27. package/core/agent/errors.ts +43 -0
  28. package/core/agent/generated/catalog.ts +26 -0
  29. package/core/agent/index.ts +170 -0
  30. package/core/agent/internal/AgentExecutionDriver.ts +1497 -0
  31. package/core/agent/internal/AgentExecutionState.ts +775 -0
  32. package/core/agent/internal/AgentJsonSchema.ts +150 -0
  33. package/core/agent/internal/AgentModelBinding.ts +57 -0
  34. package/core/agent/internal/Schema.contract.ts +36 -0
  35. package/core/agent/internal/ToolAudit.projector.ts +163 -0
  36. package/core/agent/internal/ToolContract.validator.ts +102 -0
  37. package/core/agent/metadata.ts +398 -0
  38. package/core/agent/moduleContributions-v1.ts +113 -0
  39. package/core/agent/semantic.ts +903 -0
  40. package/core/agent/session/codec.ts +33 -0
  41. package/core/agent/session/contracts.ts +96 -0
  42. package/core/agent/session/entities.ts +84 -0
  43. package/core/agent/session/protector.ts +92 -0
  44. package/core/app/index.ts +5 -0
  45. package/core/app/runApp.ts +293 -0
  46. package/core/app/ui/index.ts +29 -0
  47. package/core/app/ui/uiProfileResolver.ts +966 -0
  48. package/core/app/ui/uiSurfaceHosting.ts +38 -0
  49. package/core/app/ui/uiSurfaceHttp.ts +476 -0
  50. package/core/background/BackgroundService.ts +223 -0
  51. package/core/background/backgroundModule.ts +42 -0
  52. package/core/background/decorator.ts +43 -0
  53. package/core/background/delay.ts +27 -0
  54. package/core/background/index.ts +15 -0
  55. package/core/cache/COMPATIBILITY.md +13 -0
  56. package/core/cache/ICache.ts +71 -0
  57. package/core/cache/MemoryCache.ts +394 -0
  58. package/core/cache/README.md +83 -0
  59. package/core/cache/SPEC.md +1355 -0
  60. package/core/cache/cacheModule.ts +21 -0
  61. package/core/cache/decorators/Cacheable.ts +38 -0
  62. package/core/cache/decorators/CacheableRedis.ts +39 -0
  63. package/core/cache/decorators/OutputCache.ts +33 -0
  64. package/core/cache/decorators/OutputRedisCache.ts +33 -0
  65. package/core/cache/decorators/cacheableMetadata.ts +78 -0
  66. package/core/cache/decorators/cacheableRedisMetadata.ts +81 -0
  67. package/core/cache/decorators/outputCacheMetadata.ts +71 -0
  68. package/core/cache/decorators/outputRedisCacheMetadata.ts +77 -0
  69. package/core/cache/di/classProviderHook.ts +26 -0
  70. package/core/cache/distributed/CacheCodec.ts +5 -0
  71. package/core/cache/distributed/DistributedCache.ts +403 -0
  72. package/core/cache/distributed/DistributedCacheDriver.ts +83 -0
  73. package/core/cache/distributed/DistributedCacheStores.ts +28 -0
  74. package/core/cache/distributed/IDistributedCache.ts +40 -0
  75. package/core/cache/distributed/NamedCacheRegistry.ts +23 -0
  76. package/core/cache/distributed/codecs.ts +32 -0
  77. package/core/cache/distributed/index.ts +19 -0
  78. package/core/cache/errors/CacheError.ts +16 -0
  79. package/core/cache/http/CachedHttpPayload.ts +213 -0
  80. package/core/cache/http/applyClientCacheHeaders.ts +61 -0
  81. package/core/cache/http/buildOutputCacheKey.ts +154 -0
  82. package/core/cache/http/buildRedisOutputCacheKey.ts +16 -0
  83. package/core/cache/http/composeOutputCache.ts +130 -0
  84. package/core/cache/http/outputCacheMiddleware.ts +111 -0
  85. package/core/cache/http/outputCacheSecurityWarning.ts +58 -0
  86. package/core/cache/http/outputRedisCacheMiddleware.ts +118 -0
  87. package/core/cache/index.ts +97 -0
  88. package/core/cache/internal/AutomaticCacheKey.ts +106 -0
  89. package/core/cache/internal/CacheKeyGuard.ts +56 -0
  90. package/core/cache/internal/buildCacheProviders.ts +146 -0
  91. package/core/cache/internal/normalizeCacheKey.ts +9 -0
  92. package/core/cache/internal/resolveCachePolicy.ts +32 -0
  93. package/core/cache/internal/resolveCacheableRedisPolicy.ts +17 -0
  94. package/core/cache/internal/resolveOutputRedisCachePolicy.ts +17 -0
  95. package/core/cache/providers/cachedProviders.ts +68 -0
  96. package/core/cache/services/cacheProxy.ts +243 -0
  97. package/core/cache/tokens/CACHE_POLICIES.ts +5 -0
  98. package/core/cache/tokens/DISTRIBUTED_CACHE.ts +30 -0
  99. package/core/cache/types/CacheEntry.ts +7 -0
  100. package/core/cache/types/CacheOptions.ts +60 -0
  101. package/core/cache/types/CachePolicy.ts +74 -0
  102. package/core/cache/types/CacheableRedisOptions.ts +23 -0
  103. package/core/cache/types/OutputRedisCacheOptions.ts +25 -0
  104. package/core/di/README.md +104 -0
  105. package/core/di/ServiceCollection.ts +185 -0
  106. package/core/di/ServiceProvider.ts +689 -0
  107. package/core/di/ServiceScope.ts +61 -0
  108. package/core/di/container.ts +38 -0
  109. package/core/di/errors/AmbiguousNamedDependencyError.ts +10 -0
  110. package/core/di/errors/AsyncResolutionRequiredError.ts +12 -0
  111. package/core/di/errors/CircularDependencyError.ts +10 -0
  112. package/core/di/errors/ClassDependenciesMismatchError.ts +15 -0
  113. package/core/di/errors/DiError.ts +6 -0
  114. package/core/di/errors/InvalidProviderError.ts +9 -0
  115. package/core/di/errors/ModuleEncapsulationError.ts +7 -0
  116. package/core/di/errors/ModuleOwnedProviderConflictError.ts +8 -0
  117. package/core/di/errors/NamedDependencyNotFoundError.ts +7 -0
  118. package/core/di/errors/OptionsValidationError.ts +7 -0
  119. package/core/di/errors/ProviderNotFoundError.ts +10 -0
  120. package/core/di/errors/ScopeDisposedError.ts +7 -0
  121. package/core/di/errors/ScopedServiceFromRootError.ts +9 -0
  122. package/core/di/errors/ServiceValidationError.ts +7 -0
  123. package/core/di/errors/index.ts +14 -0
  124. package/core/di/extensions/activator.ts +39 -0
  125. package/core/di/extensions/application.ts +117 -0
  126. package/core/di/extensions/hosted-service.ts +124 -0
  127. package/core/di/extensions/index.ts +23 -0
  128. package/core/di/extensions/options-reloadable.ts +137 -0
  129. package/core/di/extensions/options.ts +91 -0
  130. package/core/di/extensions/service-provider-token.ts +21 -0
  131. package/core/di/index.ts +97 -0
  132. package/core/di/internal/GraphValidator.ts +119 -0
  133. package/core/di/internal/HostedServicePlan.ts +158 -0
  134. package/core/di/internal/NamedTokenIndex.ts +55 -0
  135. package/core/di/internal/OpenGenericRegistration.ts +14 -0
  136. package/core/di/internal/ResolutionPlan.ts +18 -0
  137. package/core/di/internal/ResolutionScopeState.ts +19 -0
  138. package/core/di/internal/ResolutionTracker.ts +153 -0
  139. package/core/di/internal/ScopeLifecycle.ts +159 -0
  140. package/core/di/internal/ServiceRegistration.ts +14 -0
  141. package/core/di/internal/ServiceRegistry.ts +252 -0
  142. package/core/di/internal/classDeps.ts +38 -0
  143. package/core/di/internal/disposal.ts +58 -0
  144. package/core/di/internal/providerDeps.ts +26 -0
  145. package/core/di/module/DI.ts +146 -0
  146. package/core/di/module/Global.ts +25 -0
  147. package/core/di/module/Module.ts +44 -0
  148. package/core/di/module/ModuleRegistrar.ts +69 -0
  149. package/core/di/module/autoDeps.ts +39 -0
  150. package/core/di/module/classProviderHooks.ts +66 -0
  151. package/core/di/module/collectModuleConfigs.ts +57 -0
  152. package/core/di/module/collectModuleControllers.ts +53 -0
  153. package/core/di/module/collectModuleUiProfiles.ts +53 -0
  154. package/core/di/module/createContainer.ts +261 -0
  155. package/core/di/module/encapsulation.ts +416 -0
  156. package/core/di/module/encapsulationHooks.ts +36 -0
  157. package/core/di/module/generatedProviderAttachments.ts +102 -0
  158. package/core/di/module/index.ts +41 -0
  159. package/core/di/module/moduleExtensions.ts +35 -0
  160. package/core/di/module/moduleNameBinding.ts +136 -0
  161. package/core/di/module/moduleOwnedProviderContributors.ts +409 -0
  162. package/core/di/module/providerSelection.ts +90 -0
  163. package/core/di/module/shortcuts.ts +111 -0
  164. package/core/di/module/types/BazisModule.ts +71 -0
  165. package/core/di/module/types/DiRegistrar.ts +24 -0
  166. package/core/di/module/types/index.ts +2 -0
  167. package/core/di/provider/index.ts +26 -0
  168. package/core/di/provider/providerGuards.ts +17 -0
  169. package/core/di/provider/types/AsyncFactoryProvider.ts +15 -0
  170. package/core/di/provider/types/ClassProvider.ts +18 -0
  171. package/core/di/provider/types/FactoryProvider.ts +20 -0
  172. package/core/di/provider/types/KeyedDependency.ts +20 -0
  173. package/core/di/provider/types/LazyDependency.ts +31 -0
  174. package/core/di/provider/types/NamedDependency.ts +16 -0
  175. package/core/di/provider/types/Provider.ts +10 -0
  176. package/core/di/provider/types/ProviderDefinition.ts +11 -0
  177. package/core/di/provider/types/ProviderDependencyList.ts +11 -0
  178. package/core/di/provider/types/ProviderLifetime.ts +1 -0
  179. package/core/di/provider/types/ProviderOwnership.ts +7 -0
  180. package/core/di/provider/types/ResolvedDeps.ts +18 -0
  181. package/core/di/provider/types/ValueProvider.ts +6 -0
  182. package/core/di/provider/types/index.ts +13 -0
  183. package/core/di/token.ts +84 -0
  184. package/core/di/types/BuildServiceProviderOptions.ts +4 -0
  185. package/core/di/types/ServiceKey.ts +1 -0
  186. package/core/di/types/ServiceResolver.ts +16 -0
  187. package/core/di/types/index.ts +3 -0
  188. package/core/generatedFingerprint.ts +60 -0
  189. package/core/generatedRuntime.ts +187 -0
  190. package/core/grpc/Grpc.module.ts +23 -0
  191. package/core/grpc/GrpcBinding.contract.ts +35 -0
  192. package/core/grpc/GrpcCall.ts +73 -0
  193. package/core/grpc/GrpcClient.ts +172 -0
  194. package/core/grpc/GrpcClientCall.ts +267 -0
  195. package/core/grpc/GrpcError.ts +19 -0
  196. package/core/grpc/GrpcRequest.binding.ts +45 -0
  197. package/core/grpc/GrpcServer.ts +204 -0
  198. package/core/grpc/GrpcStatus.ts +8 -0
  199. package/core/grpc/GrpcTransport.ts +174 -0
  200. package/core/grpc/Metadata.ts +73 -0
  201. package/core/grpc/ProtoCodec.ts +225 -0
  202. package/core/grpc/ProtoParser.ts +192 -0
  203. package/core/grpc/ProtoReader.ts +34 -0
  204. package/core/grpc/ProtoSchema.ts +52 -0
  205. package/core/grpc/ServerCredentials.ts +30 -0
  206. package/core/grpc/clientContracts.ts +39 -0
  207. package/core/grpc/contracts.ts +45 -0
  208. package/core/grpc/decorators.ts +82 -0
  209. package/core/grpc/grpcClientProvider.ts +9 -0
  210. package/core/grpc/index.ts +17 -0
  211. package/core/grpc/moduleControllers.ts +38 -0
  212. package/core/grpc/protobuf.ts +80 -0
  213. package/core/grpc/serviceDefinition.ts +20 -0
  214. package/core/http/Authorization/Authorize.ts +52 -0
  215. package/core/http/Authorization/authorizeComposer.ts +31 -0
  216. package/core/http/Authorization/metadata.ts +158 -0
  217. package/core/http/Binding/ParameterBinder.ts +109 -0
  218. package/core/http/Binding/RequestModel.ts +27 -0
  219. package/core/http/Binding/autoBindings.ts +125 -0
  220. package/core/http/Binding/bindings.ts +19 -0
  221. package/core/http/Binding/convert.ts +48 -0
  222. package/core/http/Binding/generatedSpec.ts +18 -0
  223. package/core/http/Binding/listModelRegistry.ts +47 -0
  224. package/core/http/Binding/modelBinder.ts +345 -0
  225. package/core/http/Binding/modelValidator.ts +30 -0
  226. package/core/http/Binding/requestModelRegistry.ts +117 -0
  227. package/core/http/Decorators/attributes.ts +92 -0
  228. package/core/http/Decorators/controller.ts +24 -0
  229. package/core/http/Decorators/metadata.ts +107 -0
  230. package/core/http/Decorators/routes.ts +131 -0
  231. package/core/http/Errors/HttpError.ts +92 -0
  232. package/core/http/HttpContext/HttpContext.ts +148 -0
  233. package/core/http/HttpContext/ResponseBuilder.ts +37 -0
  234. package/core/http/HttpContext/inspectableRedirects.ts +47 -0
  235. package/core/http/HttpContext/principal.ts +24 -0
  236. package/core/http/HttpContext/responseLifetime.ts +45 -0
  237. package/core/http/HttpServer.ts +627 -0
  238. package/core/http/Middleware/accessLog.ts +90 -0
  239. package/core/http/Middleware/cors.ts +160 -0
  240. package/core/http/Middleware/errorHandler.ts +100 -0
  241. package/core/http/Middleware/pipeline.ts +21 -0
  242. package/core/http/Middleware/rateLimit.ts +104 -0
  243. package/core/http/Middleware/securityHeaders.ts +118 -0
  244. package/core/http/Middleware/types.ts +19 -0
  245. package/core/http/OpenApi/generatedOpenApiRegistry.ts +102 -0
  246. package/core/http/OpenApi/openApiDocs.ts +75 -0
  247. package/core/http/OpenApi/openApiDocument.ts +356 -0
  248. package/core/http/README.md +139 -0
  249. package/core/http/Results/HttpResult.ts +19 -0
  250. package/core/http/Results/normalize.ts +93 -0
  251. package/core/http/Results/results.ts +70 -0
  252. package/core/http/Routing/Router.ts +201 -0
  253. package/core/http/Routing/RouterBuilder.ts +184 -0
  254. package/core/http/Routing/template.ts +112 -0
  255. package/core/http/SPEC.md +981 -0
  256. package/core/http/Versioning/VersionReader.ts +20 -0
  257. package/core/http/WebSocketUpgrade.ts +29 -0
  258. package/core/http/composeRouteMiddlewareComposers.ts +21 -0
  259. package/core/http/correlation/createCorrelationIdMiddleware.ts +79 -0
  260. package/core/http/httpModule.ts +48 -0
  261. package/core/http/index.ts +140 -0
  262. package/core/http/middlewareTokens.ts +48 -0
  263. package/core/http/options.ts +134 -0
  264. package/core/http-client/index.ts +105 -0
  265. package/core/infra/Infra.ts +158 -0
  266. package/core/infra/InfraConnector.ts +86 -0
  267. package/core/infra/InfraLifecycle.ts +86 -0
  268. package/core/infra/cache/RedisDistributedCacheBackend.ts +88 -0
  269. package/core/infra/cache/RedisDistributedCacheDriver.ts +186 -0
  270. package/core/infra/cache/index.ts +7 -0
  271. package/core/infra/connectorConfig.ts +29 -0
  272. package/core/infra/connectorIdentity.ts +39 -0
  273. package/core/infra/connectors/codex/CodexAppServer.ts +146 -0
  274. package/core/infra/connectors/codex/CodexAppServerClient.ts +258 -0
  275. package/core/infra/connectors/codex/CodexPolicy.ts +114 -0
  276. package/core/infra/connectors/codex/CodexTurn.ts +133 -0
  277. package/core/infra/connectors/codex/contracts.ts +82 -0
  278. package/core/infra/connectors/codex.ts +26 -0
  279. package/core/infra/connectors/llm.ts +78 -0
  280. package/core/infra/connectors/llmRouter.ts +443 -0
  281. package/core/infra/connectors/openaiCompatible.ts +590 -0
  282. package/core/infra/connectors/openaiTextStream.ts +134 -0
  283. package/core/infra/connectors/opensearch.ts +307 -0
  284. package/core/infra/connectors/postgres.ts +105 -0
  285. package/core/infra/connectors/redis.ts +132 -0
  286. package/core/infra/index.ts +58 -0
  287. package/core/kernel/ApplicationLifetime.ts +91 -0
  288. package/core/kernel/Bazis.ts +73 -0
  289. package/core/kernel/Environment.ts +53 -0
  290. package/core/kernel/Kernel.ts +391 -0
  291. package/core/kernel/KernelBuilder.ts +172 -0
  292. package/core/kernel/LifecycleCoordinator.ts +204 -0
  293. package/core/kernel/README.md +66 -0
  294. package/core/kernel/SupervisedHostedService.ts +147 -0
  295. package/core/kernel/config/ConfigRegistry.ts +48 -0
  296. package/core/kernel/config/Configuration.ts +110 -0
  297. package/core/kernel/config/README.md +62 -0
  298. package/core/kernel/config/Secret.ts +29 -0
  299. package/core/kernel/config/addConfigOptions.ts +63 -0
  300. package/core/kernel/config/defineConfig.ts +211 -0
  301. package/core/kernel/config/sources.ts +123 -0
  302. package/core/kernel/correlation/requestContext.ts +57 -0
  303. package/core/kernel/errors/ConfigKeyMissingError.ts +7 -0
  304. package/core/kernel/errors/KernelError.ts +7 -0
  305. package/core/kernel/errors/ShutdownTimeoutError.ts +7 -0
  306. package/core/kernel/errors/StartupAbortedError.ts +7 -0
  307. package/core/kernel/errors/StartupTimeoutError.ts +7 -0
  308. package/core/kernel/errors/index.ts +5 -0
  309. package/core/kernel/events/EventBus.ts +140 -0
  310. package/core/kernel/events/EventToken.ts +17 -0
  311. package/core/kernel/events/eventSubscribers.ts +126 -0
  312. package/core/kernel/events/kernelEvents.ts +16 -0
  313. package/core/kernel/events/onEvent.ts +32 -0
  314. package/core/kernel/health/HealthCheckContracts.ts +42 -0
  315. package/core/kernel/health/HealthService.ts +93 -0
  316. package/core/kernel/index.ts +96 -0
  317. package/core/kernel/internal/awaitAbortable.ts +18 -0
  318. package/core/kernel/internal/awaitShutdown.ts +21 -0
  319. package/core/kernel/internal/reportDiagnosticFailure.ts +8 -0
  320. package/core/kernel/internal/validateTimeout.ts +8 -0
  321. package/core/kernel/lifecycleHooks.ts +18 -0
  322. package/core/kernel/logging/ConsoleLogger.ts +68 -0
  323. package/core/kernel/logging/Logger.ts +22 -0
  324. package/core/kernel/types/ConfigSource.ts +9 -0
  325. package/core/kernel/types/EnvironmentName.ts +1 -0
  326. package/core/kernel/types/KernelOptions.ts +23 -0
  327. package/core/kernel/types/LifecycleHook.ts +18 -0
  328. package/core/kernel/types/index.ts +4 -0
  329. package/core/orm/DATABASE_PROVIDER.ts +5 -0
  330. package/core/orm/OrmHostedPlan.validator.ts +55 -0
  331. package/core/orm/OrmLifecycle.ts +146 -0
  332. package/core/orm/OrmOwnedStoreLifecycle.ts +96 -0
  333. package/core/orm/buildOrmProviders.ts +152 -0
  334. package/core/orm/databaseConnector.ts +108 -0
  335. package/core/orm/encapsulationHook.ts +19 -0
  336. package/core/orm/index.ts +95 -0
  337. package/core/orm/listQuery.ts +198 -0
  338. package/core/orm/ormModule.ts +173 -0
  339. package/core/orm/ownedStoreContributions.ts +195 -0
  340. package/core/orm/registerRepositories.ts +27 -0
  341. package/core/orm/repository.ts +45 -0
  342. package/core/orm/strictSchemaHostedIdentity.ts +17 -0
  343. package/core/scripts/agent-codegen.ts +1166 -0
  344. package/core/scripts/di-generate-target.ts +90 -0
  345. package/core/scripts/di-generate.ts +1837 -0
  346. package/core/scripts/orm-predicate-codegen.ts +33 -0
  347. package/core/scripts/request-model-codegen.ts +326 -0
  348. package/core/websocket/DESIGN.md +297 -0
  349. package/core/websocket/WsRateLimiter.ts +101 -0
  350. package/core/websocket/adapter/adapter.interface.ts +45 -0
  351. package/core/websocket/adapter/in-memory.adapter.ts +190 -0
  352. package/core/websocket/adapter/redis-delivery-scripts.ts +135 -0
  353. package/core/websocket/adapter/redis-delivery-store.ts +86 -0
  354. package/core/websocket/adapter/redis-operations.ts +33 -0
  355. package/core/websocket/adapter/redis.adapter.ts +218 -0
  356. package/core/websocket/codec/binary.codec.ts +87 -0
  357. package/core/websocket/codec/json.codec.ts +34 -0
  358. package/core/websocket/codec/packet-codec.interface.ts +17 -0
  359. package/core/websocket/decorators.ts +165 -0
  360. package/core/websocket/explorer.ts +126 -0
  361. package/core/websocket/index.ts +78 -0
  362. package/core/websocket/middleware.ts +146 -0
  363. package/core/websocket/packet-codec.ts +75 -0
  364. package/core/websocket/reliable-delivery.ts +56 -0
  365. package/core/websocket/session-creation.ts +16 -0
  366. package/core/websocket/session-manager.ts +856 -0
  367. package/core/websocket/socket-wrapper.ts +314 -0
  368. package/core/websocket/topic-cache.ts +59 -0
  369. package/core/websocket/types.ts +122 -0
  370. package/core/websocket/websocketModule.ts +96 -0
  371. package/core/websocket/ws-dispatch.ts +123 -0
  372. package/core/websocket/ws-server.ts +1707 -0
  373. package/index.ts +281 -0
  374. package/library/boundary/diagnostics-v1.ts +136 -0
  375. package/library/boundary/index.ts +73 -0
  376. package/library/boundary/json/decodeBoundedJsonV1.ts +518 -0
  377. package/library/boundary/json/limits-v1.ts +46 -0
  378. package/library/boundary/json/normalizeBoundedJsonV1.ts +256 -0
  379. package/library/boundary/json/types-v1.ts +11 -0
  380. package/library/boundary/schema/boundarySchemaHashV1.ts +6 -0
  381. package/library/boundary/schema/collectBoundaryValueDiagnosticsV1.ts +325 -0
  382. package/library/boundary/schema/decodeBoundarySchemaV1.ts +646 -0
  383. package/library/boundary/schema/index.ts +8 -0
  384. package/library/boundary/schema/types-v1.ts +99 -0
  385. package/library/boundary/schema/validateBoundaryValueV1.ts +58 -0
  386. package/library/boundary/serialization/canonicalJsonV1.ts +66 -0
  387. package/library/http-client/HttpClient.ts +969 -0
  388. package/library/http-client/HttpClientFactory.ts +45 -0
  389. package/library/http-client/errors.ts +68 -0
  390. package/library/http-client/index.ts +43 -0
  391. package/library/http-client/interceptors.ts +40 -0
  392. package/library/http-client/progress.ts +62 -0
  393. package/library/http-client/redirectProtocol.ts +6 -0
  394. package/library/http-client/serialize.ts +133 -0
  395. package/library/http-client/types.ts +174 -0
  396. package/library/jsonapi/ListQueryError.ts +25 -0
  397. package/library/jsonapi/ListRequest.ts +37 -0
  398. package/library/jsonapi/decorators.ts +161 -0
  399. package/library/jsonapi/document.ts +124 -0
  400. package/library/jsonapi/index.ts +40 -0
  401. package/library/jsonapi/parseListQuery.ts +291 -0
  402. package/library/jsonapi/types.ts +125 -0
  403. package/library/jwt/JwtEncoder.ts +40 -0
  404. package/library/jwt/JwtKeyRing.ts +164 -0
  405. package/library/jwt/JwtValidator.ts +210 -0
  406. package/library/jwt/TokenIssuer.ts +149 -0
  407. package/library/jwt/TokenService.ts +51 -0
  408. package/library/jwt/base64url.ts +61 -0
  409. package/library/jwt/claims.ts +36 -0
  410. package/library/jwt/errors.ts +44 -0
  411. package/library/jwt/index.ts +59 -0
  412. package/library/jwt/limits.ts +8 -0
  413. package/library/jwt/signing/Hs256Algorithm.ts +62 -0
  414. package/library/jwt/signing/Rs256Algorithm.ts +133 -0
  415. package/library/jwt/signing/SigningAlgorithm.ts +18 -0
  416. package/library/jwt/signing/pem.ts +30 -0
  417. package/library/openapi/codegen.ts +875 -0
  418. package/library/openapi/document.ts +326 -0
  419. package/library/openapi/index.ts +13 -0
  420. package/library/openapi/types.ts +69 -0
  421. package/library/openapi/ui.ts +182 -0
  422. package/library/orm/DatabaseFacade.ts +209 -0
  423. package/library/orm/DbContext.ts +107 -0
  424. package/library/orm/DbContextFactory.ts +25 -0
  425. package/library/orm/DbContextOptions.ts +33 -0
  426. package/library/orm/Metadata/DynamicModelBuilder.ts +497 -0
  427. package/library/orm/Metadata/KeyTuple.ts +36 -0
  428. package/library/orm/Metadata/ModelBuilder.ts +299 -0
  429. package/library/orm/Metadata/OrmModel.ts +80 -0
  430. package/library/orm/Metadata/ValueConverter.ts +57 -0
  431. package/library/orm/Metadata/conventions.ts +54 -0
  432. package/library/orm/Metadata/decorators.ts +396 -0
  433. package/library/orm/Metadata/types.ts +140 -0
  434. package/library/orm/Providers/OwnedStoreCatalog.reader.ts +1802 -0
  435. package/library/orm/Providers/PostgresDialect.ts +234 -0
  436. package/library/orm/Providers/PostgresProvider.ts +1494 -0
  437. package/library/orm/Providers/PostgresSchema.decoder.ts +107 -0
  438. package/library/orm/Providers/limits.ts +29 -0
  439. package/library/orm/Providers/operationDeadline.ts +43 -0
  440. package/library/orm/Providers/ormOwnedStoreRuntime.ts +19 -0
  441. package/library/orm/Providers/ormTransactionRuntime.ts +117 -0
  442. package/library/orm/Providers/propertyConversion.ts +14 -0
  443. package/library/orm/Providers/resolvedForeignKey.ts +16 -0
  444. package/library/orm/Providers/transactionCallbacks.ts +45 -0
  445. package/library/orm/Providers/transactionOutcome.ts +82 -0
  446. package/library/orm/Providers/transactionScopes.ts +78 -0
  447. package/library/orm/Providers/types.ts +207 -0
  448. package/library/orm/Query/DbSet.ts +78 -0
  449. package/library/orm/Query/EntityQuery.ts +247 -0
  450. package/library/orm/Query/ImmediateMutations.ts +226 -0
  451. package/library/orm/Query/IncludeLoader.ts +200 -0
  452. package/library/orm/Query/QueryPlan.ts +55 -0
  453. package/library/orm/Query/SqlTranslator.ts +195 -0
  454. package/library/orm/Query/conditions.ts +127 -0
  455. package/library/orm/Query/materialize.ts +39 -0
  456. package/library/orm/README.md +256 -0
  457. package/library/orm/Repository/README.md +684 -0
  458. package/library/orm/Repository/Repository.ts +68 -0
  459. package/library/orm/Saving/CommandBuilder.ts +139 -0
  460. package/library/orm/Saving/ExecutionStrategy.ts +128 -0
  461. package/library/orm/Saving/SaveExecutor.ts +413 -0
  462. package/library/orm/Saving/applyConventions.ts +64 -0
  463. package/library/orm/Schema/CheckExpression.ts +327 -0
  464. package/library/orm/Schema/ExactSchemaVerifier.ts +168 -0
  465. package/library/orm/Schema/ExpectedSchema.ts +43 -0
  466. package/library/orm/Schema/MigrationRunner.ts +146 -0
  467. package/library/orm/Schema/Migrator.ts +73 -0
  468. package/library/orm/Schema/OrmOwnedStore.ts +123 -0
  469. package/library/orm/Schema/OwnedStoreAdmission.ts +752 -0
  470. package/library/orm/Schema/OwnedStoreCanonical.ts +273 -0
  471. package/library/orm/Schema/OwnedStoreCatalog.ts +1325 -0
  472. package/library/orm/Schema/SafeAdditiveSchema.ts +100 -0
  473. package/library/orm/Schema/SchemaAdmission.ts +62 -0
  474. package/library/orm/Schema/SchemaDiffer.ts +78 -0
  475. package/library/orm/Schema/formatSchemaDifferences.ts +62 -0
  476. package/library/orm/Schema/introspection.ts +52 -0
  477. package/library/orm/Schema/physicalColumnTypes.ts +37 -0
  478. package/library/orm/Schema/tableKey.ts +26 -0
  479. package/library/orm/Tracking/ChangeTracker.ts +448 -0
  480. package/library/orm/Tracking/EntityState.ts +13 -0
  481. package/library/orm/Transactions/OrmTransaction.ts +30 -0
  482. package/library/orm/Transactions/TransactionScopeCoordinator.ts +377 -0
  483. package/library/orm/errors.ts +190 -0
  484. package/library/orm/index.ts +162 -0
  485. package/library/orm/runtime.ts +14 -0
  486. package/library/redaction/index.ts +166 -0
  487. package/library/ui/UiProfile.ts +77 -0
  488. package/library/ui/compiled-v1.ts +131 -0
  489. package/library/ui/compiler/compileUiSurfaceV1.ts +717 -0
  490. package/library/ui/compiler/contracts-v1.ts +25 -0
  491. package/library/ui/compiler/index.ts +12 -0
  492. package/library/ui/compiler/openApiIndex.ts +246 -0
  493. package/library/ui/defineUiProfile.ts +340 -0
  494. package/library/ui/diagnostics-v1.ts +33 -0
  495. package/library/ui/index.ts +129 -0
  496. package/library/ui/profile-v1.ts +191 -0
  497. package/library/ui/serialization.ts +130 -0
  498. package/library/ui/uiProfileAuthoring.ts +289 -0
  499. package/library/ui/uiProfileAuthoringMetadata.ts +78 -0
  500. package/library/validation/MessageRegistry.ts +144 -0
  501. package/library/validation/README.md +62 -0
  502. package/library/validation/RuleCompiler.ts +183 -0
  503. package/library/validation/RuleEngine.ts +401 -0
  504. package/library/validation/SPEC.md +579 -0
  505. package/library/validation/ValidationError.ts +37 -0
  506. package/library/validation/ValidationResult.ts +63 -0
  507. package/library/validation/Validator.ts +101 -0
  508. package/library/validation/index.ts +16 -0
  509. package/library/validation/metadata.ts +69 -0
  510. package/library/validation/modelValidatorAdapter.ts +119 -0
  511. package/library/validation/types/ValidationCode.ts +69 -0
  512. package/library/validation/types/ValidatorOptions.ts +153 -0
  513. package/package.json +80 -0
@@ -0,0 +1,82 @@
1
+ export type CodexLoginMethod = "browser" | "device";
2
+ export interface CodexLogin { id: string; method: CodexLoginMethod; url: string; userCode?: string; expiresAt: string }
3
+ export interface CodexStatus {
4
+ configured: boolean; connected: boolean;
5
+ account: { email: string; planType: string } | null;
6
+ login: CodexLogin | null; loginError: string | null; activeRuns: number;
7
+ }
8
+ export interface CodexModel {
9
+ id: string; name: string; isDefault: boolean;
10
+ supportedReasoningEfforts: readonly { reasoningEffort: string; description: string }[];
11
+ defaultReasoningEffort: string | null;
12
+ }
13
+ export interface CodexChatMessage { role: "user" | "assistant"; text: string }
14
+ export interface CodexTool {
15
+ readonly name: string;
16
+ readonly description: string;
17
+ readonly inputSchema: Readonly<Record<string, unknown>>;
18
+ }
19
+ export interface CodexToolCall { readonly id: string; readonly name: string; readonly arguments: unknown; }
20
+ export interface CodexToolResult { readonly text: string; readonly success: boolean; }
21
+ export interface CodexRunInput {
22
+ model?: string; reasoningEffort?: string; instructions: string; messages: readonly CodexChatMessage[];
23
+ signal: AbortSignal; onTextDelta: (text: string) => void;
24
+ tools?: readonly CodexTool[];
25
+ onToolCall?: (call: CodexToolCall, signal: AbortSignal) => Promise<CodexToolResult>;
26
+ }
27
+ export interface CodexConfigShape { enabled: boolean; binary: string; stateDirectory: string }
28
+ /** Narrow application API. Wire RPC, credentials and process handles are private. */
29
+ export interface CodexClient {
30
+ status(): Promise<CodexStatus>;
31
+ login(method: CodexLoginMethod): Promise<CodexStatus>;
32
+ cancelLogin(): Promise<CodexStatus>;
33
+ logout(): Promise<CodexStatus>;
34
+ models(): Promise<readonly CodexModel[]>;
35
+ run(input: CodexRunInput): Promise<string>;
36
+ }
37
+ export type CodexErrorCode =
38
+ | "NOT_CONFIGURED" | "UNAVAILABLE" | "SIGN_IN_REQUIRED" | "BUSY" | "MODEL_UNAVAILABLE" | "REASONING_UNAVAILABLE"
39
+ | "PROTOCOL_ERROR" | "RESPONSE_FAILED" | "TIMEOUT" | "LOGIN_FAILED" | "LOGIN_EXPIRED";
40
+
41
+ const EN_CODEX_MESSAGES: Readonly<Record<CodexErrorCode, string>> = Object.freeze({
42
+ NOT_CONFIGURED: "The ChatGPT connection is not configured on the server.",
43
+ UNAVAILABLE: "Codex App Server is unavailable. Check its installation and settings.",
44
+ SIGN_IN_REQUIRED: "An administrator needs to connect a ChatGPT account.",
45
+ BUSY: "Wait until the current replies or the ChatGPT sign-in finish.",
46
+ MODEL_UNAVAILABLE: "The selected model is not available in the connected ChatGPT account.",
47
+ REASONING_UNAVAILABLE: "The selected reasoning level is not available for this model.",
48
+ PROTOCOL_ERROR: "Codex App Server returned an incompatible response.",
49
+ RESPONSE_FAILED: "ChatGPT did not finish the reply. Check the connection and the account limits.",
50
+ TIMEOUT: "Codex App Server timed out.",
51
+ LOGIN_FAILED: "ChatGPT sign-in failed. Try again; use device-code sign-in if needed.",
52
+ LOGIN_EXPIRED: "The sign-in window expired. Start signing in again.",
53
+ });
54
+
55
+ /** Russian texts for every code: `CodexError.useMessages(RU_CODEX_MESSAGES)` at startup. */
56
+ export const RU_CODEX_MESSAGES: Readonly<Record<CodexErrorCode, string>> = Object.freeze({
57
+ NOT_CONFIGURED: "Подключение ChatGPT не настроено на сервере.",
58
+ UNAVAILABLE: "Codex App Server недоступен. Проверьте его установку и настройки.",
59
+ SIGN_IN_REQUIRED: "Администратору нужно подключить аккаунт ChatGPT.",
60
+ BUSY: "Дождитесь завершения текущих ответов или входа в ChatGPT.",
61
+ MODEL_UNAVAILABLE: "Выбранная модель недоступна в подключённом аккаунте ChatGPT.",
62
+ REASONING_UNAVAILABLE: "Выбранный уровень рассуждений недоступен для этой модели.",
63
+ PROTOCOL_ERROR: "Codex App Server вернул несовместимый ответ.",
64
+ RESPONSE_FAILED: "ChatGPT не завершил ответ. Проверьте подключение и лимиты аккаунта.",
65
+ TIMEOUT: "Время ожидания Codex App Server истекло.",
66
+ LOGIN_FAILED: "Не удалось войти в ChatGPT. Повторите вход; при необходимости используйте вход по коду.",
67
+ LOGIN_EXPIRED: "Время для входа истекло. Начните вход заново.",
68
+ });
69
+
70
+ let messages: Readonly<Record<CodexErrorCode, string>> = EN_CODEX_MESSAGES;
71
+
72
+ /** `message` is user-facing text for `code`; switch its language with `useMessages`. */
73
+ export class CodexError extends Error {
74
+ constructor(readonly code: CodexErrorCode) { super(messages[code]); this.name = "CodexError"; }
75
+
76
+ /** Replace texts for some or all codes (process-wide); missing codes keep English. */
77
+ static useMessages(overrides: Partial<Record<CodexErrorCode, string>>): void {
78
+ messages = Object.freeze({ ...EN_CODEX_MESSAGES, ...overrides });
79
+ }
80
+ }
81
+ export const CODEX_MODEL_ID = /^[A-Za-z0-9][A-Za-z0-9._-]{0,120}$/;
82
+ export const CODEX_REASONING_EFFORT = /^[a-z][a-z0-9_-]{0,31}$/;
@@ -0,0 +1,26 @@
1
+ import { createToken, type InjectionToken } from "../../di";
2
+ import type { AppConfig } from "../../kernel";
3
+ import type { InfraConnector } from "../InfraConnector";
4
+ import { reader, requireValue } from "../connectorConfig";
5
+ import { CodexAppServerClient } from "./codex/CodexAppServerClient";
6
+ import type { CodexClient, CodexConfigShape } from "./codex/contracts";
7
+
8
+ export const CODEX_APP_SERVER: InjectionToken<CodexClient> = createToken<CodexClient>("CodexClient");
9
+
10
+ /** App Server is a full executor; it does not implement the raw AgentModelProvider port. */
11
+ export function codexAppServerConnect(config: AppConfig<CodexConfigShape>): InfraConnector<CodexClient> {
12
+ return {
13
+ token: CODEX_APP_SERVER, config, phase: 0,
14
+ create(configs) {
15
+ const view = reader(config, configs);
16
+ return new CodexAppServerClient({
17
+ enabled: view.get("enabled") as boolean,
18
+ binary: requireValue(view.get("binary"), "binary", "codex-app-server"),
19
+ stateDirectory: requireValue(view.get("stateDirectory"), "stateDirectory", "codex-app-server"),
20
+ });
21
+ },
22
+ connect(client, signal) { return (client as CodexAppServerClient).connect(signal); },
23
+ dispose(client) { return (client as CodexAppServerClient).dispose(); },
24
+ healthCheck(client, signal) { return (client as CodexAppServerClient).healthy(signal); },
25
+ };
26
+ }
@@ -0,0 +1,78 @@
1
+ import type { AppConfig, ConfigRegistry, Secret } from "../../kernel";
2
+ import { AGENT_MODEL_PROVIDER, type AgentModelProvider } from "../../agent";
3
+ import { reader, requireValue } from "../connectorConfig";
4
+ import { InfraError, type InfraConnector } from "../InfraConnector";
5
+ import { identifyConnector } from "../connectorIdentity";
6
+
7
+ /** Safe default for direct provider calls and health checks. */
8
+ export const DEFAULT_LLM_REQUEST_TIMEOUT_MS = 60_000;
9
+
10
+ export interface LlmConfigShape {
11
+ readonly provider: string;
12
+ readonly model: string;
13
+ readonly baseUrl: string;
14
+ readonly apiKey: Secret;
15
+ }
16
+
17
+ export interface LlmConnectionOptions {
18
+ readonly provider: string;
19
+ readonly model: string;
20
+ readonly baseUrl: string;
21
+ readonly apiKey: string;
22
+ /** Request timeout. Defaults to 60s; `0` explicitly disables it. */
23
+ readonly timeoutMs?: number;
24
+ }
25
+
26
+ export interface LlmConnectorOptions {
27
+ /** Request timeout. Defaults to 60s; `0` explicitly disables it. */
28
+ readonly timeoutMs?: number;
29
+ }
30
+
31
+ export interface LlmProviderAdapter {
32
+ create(options: LlmConnectionOptions): AgentModelProvider;
33
+ connect?(provider: AgentModelProvider, signal?: AbortSignal): Promise<void> | void;
34
+ dispose?(provider: AgentModelProvider): Promise<void> | void;
35
+ healthCheck?(provider: AgentModelProvider, signal?: AbortSignal): Promise<boolean> | boolean;
36
+ }
37
+
38
+ export function resolveLlmConnectionOptions<T extends LlmConfigShape>(
39
+ config: AppConfig<T>,
40
+ options: LlmConnectorOptions,
41
+ configs?: ConfigRegistry,
42
+ ): LlmConnectionOptions {
43
+ const c = reader(config, configs);
44
+ const configuredTimeout = options.timeoutMs ?? DEFAULT_LLM_REQUEST_TIMEOUT_MS;
45
+ if (!Number.isSafeInteger(configuredTimeout) || configuredTimeout < 0) {
46
+ throw new InfraError("llm timeoutMs must be a non-negative safe integer");
47
+ }
48
+ return {
49
+ provider: requireValue(c.get("provider"), "provider", "llm"),
50
+ model: requireValue(c.get("model"), "model", "llm"),
51
+ baseUrl: requireValue(c.get("baseUrl"), "baseUrl", "llm"),
52
+ apiKey: (c.get("apiKey") as Secret).reveal(),
53
+ timeoutMs: configuredTimeout,
54
+ };
55
+ }
56
+
57
+ export function llmConnect<T extends LlmConfigShape>(
58
+ config: AppConfig<T>,
59
+ adapter: LlmProviderAdapter,
60
+ options: LlmConnectorOptions = {},
61
+ ): InfraConnector<AgentModelProvider> {
62
+ return identifyConnector({
63
+ token: AGENT_MODEL_PROVIDER,
64
+ config,
65
+ create(configs) {
66
+ return adapter.create(resolveLlmConnectionOptions(config, options, configs));
67
+ },
68
+ connect(provider, signal) {
69
+ return adapter.connect?.(provider, signal);
70
+ },
71
+ dispose(provider) {
72
+ return adapter.dispose?.(provider);
73
+ },
74
+ healthCheck: adapter.healthCheck
75
+ ? (provider, signal) => adapter.healthCheck?.(provider, signal) ?? false
76
+ : undefined,
77
+ }, "llm");
78
+ }
@@ -0,0 +1,443 @@
1
+ import type { AppConfig } from "../../kernel";
2
+ import {
3
+ AGENT_MODEL_PROVIDER,
4
+ agentModelRequest,
5
+ type AgentModelProvider,
6
+ type AgentModelProviderContext,
7
+ type AgentModelRequest,
8
+ type AgentModelResponse,
9
+ } from "../../agent";
10
+ import { InfraError, type InfraConnector } from "../InfraConnector";
11
+ import { redactSensitiveText } from "../../../library/redaction";
12
+ import { awaitAbortable } from "../../kernel/internal/awaitAbortable";
13
+ import {
14
+ resolveLlmConnectionOptions,
15
+ type LlmConfigShape,
16
+ type LlmConnectionOptions,
17
+ type LlmConnectorOptions,
18
+ type LlmProviderAdapter,
19
+ } from "./llm";
20
+
21
+ export interface LlmModelProfileOptions extends LlmConnectorOptions {
22
+ readonly model?: string;
23
+ readonly temperature?: number;
24
+ readonly maxOutputTokens?: number;
25
+ readonly fallback?: string;
26
+ }
27
+
28
+ export interface LlmModelProfile<T extends LlmConfigShape = LlmConfigShape> {
29
+ readonly config: AppConfig<T>;
30
+ readonly adapter: LlmProviderAdapter;
31
+ readonly options: LlmModelProfileOptions;
32
+ }
33
+
34
+ export interface LlmRouterOptions {
35
+ readonly defaultProfile?: string;
36
+ }
37
+
38
+ interface RuntimeProfile {
39
+ readonly name: string;
40
+ readonly adapter: LlmProviderAdapter;
41
+ readonly provider: AgentModelProvider;
42
+ readonly connection: LlmConnectionOptions;
43
+ readonly options: LlmModelProfileOptions;
44
+ }
45
+
46
+ export class LlmModelRouterError extends Error {
47
+ public constructor(message: string) {
48
+ super(message);
49
+ this.name = "LlmModelRouterError";
50
+ }
51
+ }
52
+
53
+ function nonEmptyText(value: string | undefined, field: string): string | undefined {
54
+ if (value === undefined) {
55
+ return undefined;
56
+ }
57
+ const trimmed = value.trim();
58
+ if (trimmed.length === 0) {
59
+ throw new InfraError(`${field} must be a non-empty string when provided.`);
60
+ }
61
+ return trimmed;
62
+ }
63
+
64
+ function profileEntries(profiles: Readonly<Record<string, LlmModelProfile>>): readonly (readonly [string, LlmModelProfile])[] {
65
+ const entries = Object.entries(profiles).map(([name, profile]) => [
66
+ name,
67
+ Object.freeze({ ...profile, options: normalizeProfileOptions(profile.options, `llmRouter.${name}`) }),
68
+ ] as const);
69
+ if (entries.length === 0) {
70
+ throw new InfraError("llmRouter requires at least one model profile.");
71
+ }
72
+ for (let index = 0; index < entries.length; index += 1) {
73
+ const [name] = entries[index] as [string, LlmModelProfile];
74
+ const normalized = nonEmptyText(name, `llmRouter.profile[${index}]`);
75
+ if (normalized !== name) {
76
+ throw new InfraError(`llmRouter profile name "${name}" must not have surrounding whitespace.`);
77
+ }
78
+ }
79
+ return Object.freeze(entries);
80
+ }
81
+
82
+ function defaultProfileName(
83
+ entries: readonly (readonly [string, LlmModelProfile])[],
84
+ options: LlmRouterOptions,
85
+ ): string {
86
+ const requested = nonEmptyText(options.defaultProfile, "llmRouter.defaultProfile");
87
+ if (requested !== undefined) {
88
+ if (!entries.some(([name]) => name === requested)) {
89
+ throw new InfraError(`llmRouter defaultProfile "${requested}" is not registered.`);
90
+ }
91
+ return requested;
92
+ }
93
+ if (entries.length === 1) {
94
+ return entries[0]![0];
95
+ }
96
+ if (entries.some(([name]) => name === "default")) {
97
+ return "default";
98
+ }
99
+ throw new InfraError("llmRouter with multiple profiles requires defaultProfile or a profile named \"default\".");
100
+ }
101
+
102
+ function ensureFallbacksValid(entries: readonly (readonly [string, LlmModelProfile])[]): void {
103
+ const names = new Set(entries.map(([name]) => name));
104
+ for (let index = 0; index < entries.length; index += 1) {
105
+ const [name, profile] = entries[index] as readonly [string, LlmModelProfile];
106
+ const fallback = nonEmptyText(profile.options.fallback, `llmRouter.${name}.fallback`);
107
+ if (fallback === undefined) {
108
+ continue;
109
+ }
110
+ if (fallback === name) {
111
+ throw new InfraError(`llmRouter profile "${name}" cannot fallback to itself.`);
112
+ }
113
+ if (!names.has(fallback)) {
114
+ throw new InfraError(`llmRouter profile "${name}" fallback "${fallback}" is not registered.`);
115
+ }
116
+ }
117
+
118
+ const state = new Map<string, "visiting" | "visited">();
119
+ const path: string[] = [];
120
+ const visit = (name: string): void => {
121
+ if (state.get(name) === "visited") {
122
+ return;
123
+ }
124
+ if (state.get(name) === "visiting") {
125
+ const start = path.indexOf(name);
126
+ const cycle = [...path.slice(start), name];
127
+ throw new InfraError(`llmRouter fallback cycle detected: ${cycle.join(" -> ")}.`);
128
+ }
129
+ state.set(name, "visiting");
130
+ path.push(name);
131
+ const fallback = entries.find(([entryName]) => entryName === name)?.[1].options.fallback;
132
+ if (fallback !== undefined) {
133
+ visit(fallback);
134
+ }
135
+ path.pop();
136
+ state.set(name, "visited");
137
+ };
138
+ for (const [name] of entries) {
139
+ visit(name);
140
+ }
141
+ }
142
+
143
+ function errorMessageOf(error: unknown): string {
144
+ return redactSensitiveText(error instanceof Error ? error.message : String(error));
145
+ }
146
+
147
+ function positiveInteger(value: number | undefined, field: string): number | undefined {
148
+ if (value !== undefined && (!Number.isSafeInteger(value) || value <= 0)) {
149
+ throw new InfraError(`${field} must be a positive integer when provided.`);
150
+ }
151
+ return value;
152
+ }
153
+
154
+ function nonNegativeInteger(value: number | undefined, field: string): number | undefined {
155
+ if (value !== undefined && (!Number.isSafeInteger(value) || value < 0)) {
156
+ throw new InfraError(`${field} must be a non-negative safe integer when provided.`);
157
+ }
158
+ return value;
159
+ }
160
+
161
+ function finiteNumber(value: number | undefined, field: string): number | undefined {
162
+ if (value !== undefined && !Number.isFinite(value)) {
163
+ throw new InfraError(`${field} must be finite when provided.`);
164
+ }
165
+ return value;
166
+ }
167
+
168
+ function normalizeProfileOptions(options: LlmModelProfileOptions, field: string): LlmModelProfileOptions {
169
+ const model = nonEmptyText(options.model, `${field}.model`);
170
+ const fallback = nonEmptyText(options.fallback, `${field}.fallback`);
171
+ nonNegativeInteger(options.timeoutMs, `${field}.timeoutMs`);
172
+ positiveInteger(options.maxOutputTokens, `${field}.maxOutputTokens`);
173
+ finiteNumber(options.temperature, `${field}.temperature`);
174
+ return Object.freeze({
175
+ ...options,
176
+ ...(model === undefined ? {} : { model }),
177
+ ...(fallback === undefined ? {} : { fallback }),
178
+ });
179
+ }
180
+
181
+ export function llmProfile<T extends LlmConfigShape>(
182
+ config: AppConfig<T>,
183
+ adapter: LlmProviderAdapter,
184
+ options: LlmModelProfileOptions = {},
185
+ ): LlmModelProfile<T> {
186
+ return Object.freeze({ config, adapter, options: normalizeProfileOptions(options, "llmProfile") });
187
+ }
188
+
189
+ export class LlmModelRouter implements AgentModelProvider {
190
+ private readonly profiles = new Map<string, RuntimeProfile>();
191
+ private connectPromise?: Promise<void>;
192
+ private initializePromise?: Promise<void>;
193
+ private disposePromise?: Promise<void>;
194
+ private disposed = false;
195
+
196
+ public constructor(
197
+ profiles: readonly RuntimeProfile[],
198
+ private readonly defaultProfile: string,
199
+ private readonly factories: readonly (() => RuntimeProfile)[] = [],
200
+ ) {
201
+ for (let index = 0; index < profiles.length; index += 1) {
202
+ const profile = profiles[index] as RuntimeProfile;
203
+ this.profiles.set(profile.name, profile);
204
+ }
205
+ }
206
+
207
+ public async complete(request: AgentModelRequest, context: AgentModelProviderContext): Promise<AgentModelResponse> {
208
+ context.signal.throwIfAborted();
209
+ await this.initialize();
210
+ const requested = request.modelProfile ?? context.modelProfile ?? this.defaultProfile;
211
+ return this.completeWithProfile(request, context, requested, new Set<string>());
212
+ }
213
+
214
+ public connect(signal?: AbortSignal): Promise<void> {
215
+ if (this.disposed) {
216
+ return Promise.reject(new InfraError("LLM model router is already disposed."));
217
+ }
218
+ this.connectPromise ??= this.connectProfiles(signal);
219
+ return this.connectPromise;
220
+ }
221
+
222
+ private async connectProfiles(signal?: AbortSignal): Promise<void> {
223
+ signal?.throwIfAborted();
224
+ await this.initialize();
225
+ for (const profile of this.profiles.values()) {
226
+ try {
227
+ if (this.disposed) throw new InfraError("LLM model router is already disposed.");
228
+ signal?.throwIfAborted();
229
+ await awaitAbortable(Promise.resolve(profile.adapter.connect?.(profile.provider, signal)), signal);
230
+ } catch (error) {
231
+ const primary = new InfraError(
232
+ `LLM model profile "${profile.name}" failed to connect: ${errorMessageOf(error)}`,
233
+ );
234
+ try {
235
+ await this.dispose();
236
+ } catch (cleanupError) {
237
+ const cleanupErrors =
238
+ cleanupError instanceof AggregateError ? cleanupError.errors : [cleanupError];
239
+ throw new AggregateError(
240
+ [primary, ...cleanupErrors],
241
+ `LLM model router failed to connect and rollback finished with errors.`,
242
+ );
243
+ }
244
+ throw primary;
245
+ }
246
+ }
247
+ }
248
+
249
+ private initialize(): Promise<void> {
250
+ if (this.disposed) return Promise.reject(new InfraError("LLM model router is already disposed."));
251
+ this.initializePromise ??= Promise.resolve().then(async () => {
252
+ try {
253
+ if (this.disposed) throw new InfraError("LLM model router is already disposed.");
254
+ for (const create of this.factories) {
255
+ const profile = create();
256
+ this.profiles.set(profile.name, profile);
257
+ }
258
+ } catch (error) {
259
+ const primary = new InfraError(`LLM model router failed to create profiles: ${errorMessageOf(error)}`);
260
+ try {
261
+ await this.dispose();
262
+ } catch (cleanupError) {
263
+ throw new AggregateError([primary, cleanupError], "LLM model router creation and rollback failed.");
264
+ }
265
+ throw primary;
266
+ }
267
+ });
268
+ return this.initializePromise;
269
+ }
270
+
271
+ public dispose(): Promise<void> {
272
+ if (this.disposePromise !== undefined) {
273
+ return this.disposePromise;
274
+ }
275
+ if (this.disposed) {
276
+ return Promise.resolve();
277
+ }
278
+ this.disposed = true;
279
+ const work = Promise.resolve().then(() => this.disposeProfiles());
280
+ this.disposePromise = work;
281
+ const clear = (): void => {
282
+ this.disposePromise = undefined;
283
+ };
284
+ void work.then(clear, clear);
285
+ return work;
286
+ }
287
+
288
+ private async disposeProfiles(): Promise<void> {
289
+ const errors: unknown[] = [];
290
+ const profiles = Array.from(this.profiles.values()).reverse();
291
+ for (let index = 0; index < profiles.length; index += 1) {
292
+ const profile = profiles[index] as RuntimeProfile;
293
+ try {
294
+ await profile.adapter.dispose?.(profile.provider);
295
+ } catch (error) {
296
+ errors.push(new InfraError(
297
+ `LLM model profile "${profile.name}" failed to dispose: ${errorMessageOf(error)}`,
298
+ ));
299
+ }
300
+ }
301
+ if (errors.length === 1) {
302
+ throw errors[0];
303
+ }
304
+ if (errors.length > 1) {
305
+ throw new AggregateError(errors, "LLM model router disposal finished with errors.");
306
+ }
307
+ }
308
+
309
+ public async healthCheck(signal?: AbortSignal): Promise<boolean> {
310
+ if (this.disposed) {
311
+ return false;
312
+ }
313
+ await this.initialize();
314
+ let healthy = true;
315
+ for (const profile of this.profiles.values()) {
316
+ if (profile.adapter.healthCheck) {
317
+ try {
318
+ signal?.throwIfAborted();
319
+ if (!(await awaitAbortable(Promise.resolve(profile.adapter.healthCheck(profile.provider, signal)), signal))) {
320
+ healthy = false;
321
+ }
322
+ } catch {
323
+ healthy = false;
324
+ if (signal?.aborted) return false;
325
+ }
326
+ }
327
+ }
328
+ return healthy;
329
+ }
330
+
331
+ private async completeWithProfile(
332
+ request: AgentModelRequest,
333
+ context: AgentModelProviderContext,
334
+ profileName: string,
335
+ visited: Set<string>,
336
+ ): Promise<AgentModelResponse> {
337
+ if (visited.has(profileName)) {
338
+ throw new LlmModelRouterError(`LLM model profile fallback cycle detected at "${profileName}".`);
339
+ }
340
+ visited.add(profileName);
341
+
342
+ const profile = this.profiles.get(profileName);
343
+ if (!profile) {
344
+ throw new LlmModelRouterError(`Unknown LLM model profile "${profileName}".`);
345
+ }
346
+ if (context.signal.aborted) {
347
+ throw new LlmModelRouterError("LLM model request was cancelled before provider dispatch.");
348
+ }
349
+
350
+ let emittedText = false, acceptingText = true;
351
+ const streamingContext = context.onTextDelta ? { ...context, onTextDelta: (text: string) => {
352
+ if (!acceptingText || context.signal.aborted) return;
353
+ if (text) emittedText = true;
354
+ context.onTextDelta!(text);
355
+ } } : context;
356
+ try {
357
+ return await profile.provider.complete(this.requestForProfile(request, profile), this.contextForProfile(streamingContext, profileName));
358
+ } catch (error) {
359
+ acceptingText = false;
360
+ const fallback = profile.options.fallback;
361
+ // A second model must not silently append a new answer to already visible text.
362
+ if (fallback !== undefined && !emittedText) {
363
+ if (context.signal.aborted) throw new LlmModelRouterError("LLM model request was cancelled before provider dispatch.");
364
+ return this.completeWithProfile(request, context, fallback, visited);
365
+ }
366
+ throw new LlmModelRouterError(
367
+ `LLM model profile "${profileName}" failed: ${errorMessageOf(error)}`,
368
+ );
369
+ } finally {
370
+ acceptingText = false;
371
+ }
372
+ }
373
+
374
+ private requestForProfile(request: AgentModelRequest, profile: RuntimeProfile): AgentModelRequest {
375
+ return agentModelRequest({
376
+ invocationId: request.invocationId,
377
+ messages: request.messages,
378
+ tools: request.tools,
379
+ output: request.output,
380
+ capabilities: request.capabilities,
381
+ modelProfile: profile.name,
382
+ // Model identity belongs to infra/profile policy. Invocation input may
383
+ // tune sampling/limits but cannot bypass the selected profile's model.
384
+ model: profile.options.model ?? profile.connection.model,
385
+ maxOutputTokens: request.maxOutputTokens ?? profile.options.maxOutputTokens,
386
+ temperature: request.temperature ?? profile.options.temperature,
387
+ metadata: { ...request.metadata, modelProfile: profile.name },
388
+ });
389
+ }
390
+
391
+ private contextForProfile(context: AgentModelProviderContext, profileName: string): AgentModelProviderContext {
392
+ return Object.freeze({
393
+ ...context,
394
+ modelProfile: profileName,
395
+ });
396
+ }
397
+ }
398
+
399
+ export function llmRouter(
400
+ profiles: Readonly<Record<string, LlmModelProfile>>,
401
+ options: LlmRouterOptions = {},
402
+ ): InfraConnector<AgentModelProvider> {
403
+ const entries = profileEntries(profiles);
404
+ const defaultProfile = defaultProfileName(entries, options);
405
+ ensureFallbacksValid(entries);
406
+ const configs = Object.freeze(Array.from(new Set(entries.map(([, profile]) => profile.config))));
407
+
408
+ return {
409
+ token: AGENT_MODEL_PROVIDER,
410
+ config: configs,
411
+ create(configs) {
412
+ // The router must have an owner before adapters allocate resources.
413
+ // Initialization happens inside an awaited operation, so rollback can
414
+ // await asynchronous adapter disposal and preserve cleanup errors.
415
+ const factories = entries.map(([name, profile]) => () => {
416
+ const connection = resolveLlmConnectionOptions(profile.config, profile.options, configs);
417
+ // A profile-owned model is part of the concrete Infra connection. This
418
+ // keeps direct providers strict while the router remains the authority
419
+ // that selects the active profile/model pair.
420
+ const profileConnection = profile.options.model === undefined
421
+ ? connection
422
+ : Object.freeze({ ...connection, model: profile.options.model });
423
+ return Object.freeze({
424
+ name,
425
+ adapter: profile.adapter,
426
+ provider: profile.adapter.create(profileConnection),
427
+ connection: profileConnection,
428
+ options: profile.options,
429
+ });
430
+ });
431
+ return new LlmModelRouter([], defaultProfile, factories);
432
+ },
433
+ connect(client, signal) {
434
+ return client instanceof LlmModelRouter ? client.connect(signal) : undefined;
435
+ },
436
+ dispose(client) {
437
+ return client instanceof LlmModelRouter ? client.dispose() : undefined;
438
+ },
439
+ healthCheck(client, signal) {
440
+ return client instanceof LlmModelRouter ? client.healthCheck(signal) : false;
441
+ },
442
+ };
443
+ }