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,1497 @@
1
+ import { inlineGeneratedSchema } from "./Schema.contract";
2
+ import { describeTool } from "../Tool.contract";
3
+ import type { Class, ServiceProvider } from "../../di";
4
+ import { getGeneratedOpenApiMetadata, getGeneratedOpenApiSchemaName } from "../../http/OpenApi/generatedOpenApiRegistry";
5
+ import { redactSensitive, redactSensitiveText } from "../../../library/redaction";
6
+ import { AgentRuntimeError } from "../errors";
7
+ import { agentModelJson, bindAgentModel } from "./AgentModelBinding";
8
+ import { validateAgentJsonSchema } from "./AgentJsonSchema";
9
+ import type { AgentDefinition, AgentRegistry, AgentTaskDefinition, ToolDefinition } from "../AgentRegistry";
10
+ import {
11
+ DefaultAgentContextBuilder,
12
+ mergeAgentContextLimits,
13
+ normalizeAgentContextLimits,
14
+ type AgentContextBuilder,
15
+ type AgentContextLimits,
16
+ } from "../AgentContextBuilder";
17
+ import {
18
+ AgentToolExecutor,
19
+ type AgentToolExecutionOptions,
20
+ type AgentToolExecutorOptions,
21
+ type AgentToolSchemaValidator,
22
+ } from "../AgentToolExecutor";
23
+ import type { AgentModelProvider, AgentModelProviderContext } from "../ModelProvider";
24
+ import {
25
+ agentExecutionCheckpointV1,
26
+ evolveAgentExecutionCheckpointV1,
27
+ requireIssuedAgentExecutionCheckpointV1,
28
+ type AgentExecutionBoundary,
29
+ type AgentExecutionCheckpointV1,
30
+ } from "./AgentExecutionState";
31
+ import {
32
+ agentClassSchema,
33
+ agentData,
34
+ agentJsonSchema,
35
+ agentMessage,
36
+ agentModelRequest,
37
+ agentModelResponse,
38
+ agentOutputContract,
39
+ agentToolCall,
40
+ agentToolContract,
41
+ agentToolCallPart,
42
+ agentToolResultPart,
43
+ normalizeJsonValue,
44
+ type AgentMessage,
45
+ type AgentModelRequest,
46
+ type AgentModelResponse,
47
+ type AgentOutputContract,
48
+ type AgentToolError,
49
+ type AgentToolContract,
50
+ type AgentToolResult,
51
+ type JsonObject,
52
+ type JsonValue,
53
+ } from "../semantic";
54
+
55
+ const DEFAULT_MAX_STEPS = 8;
56
+ const DEFAULT_MAX_TOOL_CALLS_PER_STEP = 16;
57
+ const DEFAULT_MODEL_TIMEOUT_MS = 60_000;
58
+
59
+ export type AgentRuntimeStatus = "completed" | "failed";
60
+
61
+ export interface AgentRuntimeToolCallContext {
62
+ readonly invocationId: string;
63
+ readonly agentName: string;
64
+ readonly call: AgentModelResponse["toolCalls"][number];
65
+ }
66
+
67
+ export interface AgentRuntimeToolExecutionOptions extends Omit<
68
+ AgentToolExecutionOptions,
69
+ "agentName" | "invocationId" | "metadata" | "idempotencyKey"
70
+ > {
71
+ /** Optional prefix; the runtime appends the unique model call id. */
72
+ readonly idempotencyKey?: string;
73
+ /** Per-call override for domain-specific stable idempotency keys. */
74
+ readonly idempotencyKeyForCall?: (context: AgentRuntimeToolCallContext) => string | undefined;
75
+ }
76
+
77
+ export interface AgentRuntimeOptions {
78
+ readonly maxSteps?: number;
79
+ readonly maxToolCallsPerStep?: number;
80
+ readonly modelProfile?: string;
81
+ readonly model?: string;
82
+ /** Provider-call timeout. Defaults to 60 seconds; 0 explicitly disables it. */
83
+ readonly timeoutMs?: number;
84
+ readonly contextBuilder?: AgentContextBuilder;
85
+ readonly contextLimits?: AgentContextLimits;
86
+ readonly toolExecutorOptions?: AgentToolExecutorOptions;
87
+ readonly taskSchemaValidator?: AgentToolSchemaValidator;
88
+ }
89
+
90
+ export interface AgentRuntimeInvokeOptions {
91
+ readonly id?: string;
92
+ readonly input?: unknown;
93
+ readonly messages?: readonly AgentMessage[];
94
+ readonly output?: AgentOutputContract;
95
+ readonly metadata?: unknown;
96
+ readonly modelProfile?: string;
97
+ readonly model?: string;
98
+ readonly maxSteps?: number;
99
+ readonly maxToolCallsPerStep?: number;
100
+ readonly maxOutputTokens?: number;
101
+ readonly temperature?: number;
102
+ /** Per-provider-call timeout override; 0 explicitly disables it. */
103
+ readonly timeoutMs?: number;
104
+ readonly contextLimits?: AgentContextLimits;
105
+ readonly signal?: AbortSignal;
106
+ readonly toolExecution?: AgentRuntimeToolExecutionOptions;
107
+ /** Ephemeral, provisional text; never persisted/replayed as a checkpoint or accepted output. */
108
+ readonly onTextDelta?: (event: { readonly step: number; readonly text: string }) => void;
109
+ }
110
+
111
+ export interface AgentRuntimeTaskInvokeOptions extends Omit<AgentRuntimeInvokeOptions, "input"> {}
112
+
113
+ export interface AgentRuntimeResult {
114
+ readonly invocationId: string;
115
+ readonly agentName: string;
116
+ readonly status: AgentRuntimeStatus;
117
+ readonly steps: number;
118
+ readonly messages: readonly AgentMessage[];
119
+ readonly responses: readonly AgentModelResponse[];
120
+ readonly toolResults: readonly AgentToolResult[];
121
+ readonly finalMessage?: AgentMessage;
122
+ /** Validated structured value for declared or explicitly requested JSON output. */
123
+ readonly output?: JsonValue;
124
+ readonly error?: AgentToolError;
125
+ readonly metadata: JsonObject;
126
+ }
127
+
128
+ type PreparedTaskContract =
129
+ | { readonly ok: true; readonly instance: object; readonly value: JsonValue }
130
+ | { readonly ok: false; readonly error: AgentToolError };
131
+
132
+ type PreparedAgentPlan = {
133
+ readonly agent: AgentDefinition;
134
+ readonly invocationId: string;
135
+ readonly metadata: JsonObject;
136
+ readonly maxSteps: number;
137
+ readonly maxToolCallsPerStep: number;
138
+ readonly timeoutMs: number | undefined;
139
+ readonly modelProfile: string | undefined;
140
+ readonly contextLimits: AgentContextLimits | undefined;
141
+ readonly messages: AgentMessage[];
142
+ readonly seenToolCallIds: Set<string>;
143
+ readonly tools: readonly AgentToolContract[];
144
+ readonly executorToolOptions: AgentToolExecutionOptions;
145
+ readonly sessionToolTimeouts?: ReadonlyMap<string, number>;
146
+ readonly options: AgentRuntimeInvokeOptions;
147
+ readonly taskFinalization?: TaskFinalizationPlan;
148
+ };
149
+
150
+ type TaskFinalizationPlan = {
151
+ readonly task: AgentTaskDefinition;
152
+ readonly timeoutMs: number | undefined;
153
+ readonly signal: AbortSignal | undefined;
154
+ };
155
+
156
+ type AgentPreparation =
157
+ | { readonly ok: true; readonly plan: PreparedAgentPlan }
158
+ | { readonly ok: false; readonly result: AgentRuntimeResult };
159
+
160
+ type PreparedTaskPlan = {
161
+ readonly task: AgentTaskDefinition;
162
+ readonly timeoutMs: number | undefined;
163
+ readonly plan: PreparedAgentPlan;
164
+ };
165
+
166
+ type TaskPreparation =
167
+ | { readonly ok: true; readonly prepared: PreparedTaskPlan }
168
+ | { readonly ok: false; readonly result: AgentRuntimeResult };
169
+
170
+ type EngineProgress = Pick<AgentExecutionCheckpointV1, "phase" | "steps" | "messages" | "responses" | "toolResults" | "seenToolCallIds" | "pendingToolBatch" | "terminal">;
171
+
172
+ /** Progress of a run kept only in memory (no checkpoint store). */
173
+ type InMemoryExecutionState = EngineProgress;
174
+
175
+ type PhaseBridge<TState extends EngineProgress> = {
176
+ evolve(
177
+ previous: TState,
178
+ progress: EngineProgress,
179
+ ): TState;
180
+ boundaryError(state: TState): Error;
181
+ };
182
+
183
+ type EngineBoundary<TState extends EngineProgress> = {
184
+ checkControl(current: TState, next: TState): Promise<import("./AgentExecutionState").AgentExecutionControlDecision>;
185
+ beforeModelDispatch(checkpoint: TState, step: number, request: AgentModelRequest): Promise<void>;
186
+ afterModelSettlement(previous: TState, candidate: TState, step: number, outcome: { readonly response: AgentModelResponse } | { readonly error: AgentToolError }): Promise<void>;
187
+ beforeToolDispatch(checkpoint: TState, step: number, toolIndex: number, call: AgentModelResponse["toolCalls"][number], idempotencyKey: string): Promise<void>;
188
+ afterToolSettlement(previous: TState, candidate: TState, step: number, toolIndex: number, call: AgentModelResponse["toolCalls"][number], idempotencyKey: string, result: AgentToolResult): Promise<void>;
189
+ };
190
+
191
+ type EngineOutcome<TState extends EngineProgress> =
192
+ | { readonly kind: "terminal"; readonly state: TState; readonly result: AgentRuntimeResult }
193
+ | { readonly kind: "suspended"; readonly state: TState; readonly reason: string };
194
+
195
+ export type AgentExecutionDriveOutcome =
196
+ | { readonly kind: "terminal"; readonly checkpoint: AgentExecutionCheckpointV1; readonly result: AgentRuntimeResult }
197
+ | { readonly kind: "suspended"; readonly checkpoint: AgentExecutionCheckpointV1; readonly reason: string };
198
+
199
+ /** Owner-private Session creation carrier; it is never re-exported by AgentRuntime. */
200
+ export interface AgentSessionPreparationV1 {
201
+ readonly invocationId: string;
202
+ readonly agentName: string;
203
+ readonly taskName: string | null;
204
+ readonly input: JsonValue;
205
+ readonly requested: {
206
+ readonly maxSteps: number | null;
207
+ readonly maxToolCallsPerStep: number | null;
208
+ readonly runTimeoutMs: number | null;
209
+ readonly modelProfile: string | null;
210
+ };
211
+ readonly module: {
212
+ readonly maxSessionSteps: number;
213
+ readonly maxToolCallsPerStep: number;
214
+ readonly runTimeoutMs: number;
215
+ readonly providerCallTimeoutMs: number;
216
+ readonly toolDefaultTimeoutMs: number;
217
+ readonly scopeDisposeTimeoutMs: number;
218
+ };
219
+ readonly signal?: AbortSignal;
220
+ }
221
+
222
+ export type AgentSessionPreparationOutcomeV1 =
223
+ | { readonly kind: "prepared"; readonly checkpoint: AgentExecutionCheckpointV1 }
224
+ | { readonly kind: "rejected"; readonly result: AgentRuntimeResult };
225
+
226
+ export interface AgentExecutionDriveRequestV1 {
227
+ readonly checkpoint: AgentExecutionCheckpointV1;
228
+ readonly boundary: AgentExecutionBoundary;
229
+ readonly signal: AbortSignal;
230
+ }
231
+
232
+ export class AgentExecutionBoundaryError extends Error {
233
+ constructor(readonly checkpoint: AgentExecutionCheckpointV1) {
234
+ super("Agent execution durable boundary rejected a checkpoint transition.");
235
+ this.name = "AgentExecutionBoundaryError";
236
+ }
237
+ }
238
+
239
+ class AgentRuntimeTimeoutError extends Error {
240
+ constructor() {
241
+ super("Agent runtime provider call timed out.");
242
+ this.name = "AgentRuntimeTimeoutError";
243
+ }
244
+ }
245
+
246
+ class AgentRuntimeAbortError extends Error {
247
+ constructor() {
248
+ super("Agent runtime invocation was aborted.");
249
+ this.name = "AgentRuntimeAbortError";
250
+ }
251
+ }
252
+
253
+ function isPlainJsonObject(value: JsonValue): value is JsonObject {
254
+ return typeof value === "object" && value !== null && !Array.isArray(value);
255
+ }
256
+
257
+ function normalizeMetadata(value: unknown, field: string): JsonObject {
258
+ const normalized = normalizeJsonValue(value ?? {}, field);
259
+ if (!isPlainJsonObject(normalized)) {
260
+ throw new AgentRuntimeError(`${field} must be a JSON object.`);
261
+ }
262
+ return normalized;
263
+ }
264
+
265
+ function errorMessageOf(error: unknown): string {
266
+ try {
267
+ return error instanceof Error && typeof error.message === "string" ? error.message : String(error);
268
+ } catch {
269
+ return "Unknown error.";
270
+ }
271
+ }
272
+
273
+ function assertPositiveInteger(value: number | undefined, field: string): void {
274
+ if (value === undefined) {
275
+ return;
276
+ }
277
+ if (!Number.isInteger(value) || value <= 0) {
278
+ throw new AgentRuntimeError(`${field} must be a positive integer.`);
279
+ }
280
+ }
281
+
282
+ function assertNonNegativeInteger(value: number | undefined, field: string): void {
283
+ if (value === undefined) return;
284
+ if (!Number.isInteger(value) || value < 0) {
285
+ throw new AgentRuntimeError(`${field} must be a non-negative integer.`);
286
+ }
287
+ }
288
+
289
+ function optionalText(value: string | undefined, field: string): string | undefined {
290
+ if (value === undefined) {
291
+ return undefined;
292
+ }
293
+ const trimmed = value.trim();
294
+ if (trimmed.length === 0) {
295
+ throw new AgentRuntimeError(`${field} must be a non-empty string when provided.`);
296
+ }
297
+ return trimmed;
298
+ }
299
+
300
+ function optionPositiveInteger(value: JsonValue | undefined, field: string): number {
301
+ if (typeof value !== "number" || !Number.isSafeInteger(value) || value <= 0) {
302
+ throw new AgentRuntimeError(`${field} must be a positive integer.`);
303
+ }
304
+ return value;
305
+ }
306
+
307
+ function optionText(value: JsonValue | undefined, field: string): string | undefined {
308
+ if (value === null) return undefined;
309
+ if (typeof value !== "string" || value.trim().length === 0) {
310
+ throw new AgentRuntimeError(`${field} must be a non-empty string or null.`);
311
+ }
312
+ return value;
313
+ }
314
+
315
+ function checkpointOptionObject(value: JsonValue | undefined, field: string): JsonObject {
316
+ if (value === undefined || !isPlainJsonObject(value)) throw new AgentRuntimeError(`${field} must be an object.`);
317
+ return value;
318
+ }
319
+
320
+ function optionNullablePositiveInteger(value: JsonValue | undefined, field: string): number | undefined {
321
+ if (value === null) return undefined;
322
+ return optionPositiveInteger(value, field);
323
+ }
324
+
325
+ function optionNullableFiniteNonNegative(value: JsonValue | undefined, field: string): number | undefined {
326
+ if (value === null) return undefined;
327
+ if (typeof value !== "number" || !Number.isFinite(value) || value < 0) {
328
+ throw new AgentRuntimeError(`${field} must be a finite non-negative number or null.`);
329
+ }
330
+ return value;
331
+ }
332
+
333
+ function checkpointContextLimits(value: JsonObject): AgentContextLimits | undefined {
334
+ const maxMessages = optionNullablePositiveInteger(value.maxMessages, "checkpoint.options.context.maxMessages");
335
+ const maxChars = optionNullablePositiveInteger(value.maxChars, "checkpoint.options.context.maxChars");
336
+ const maxTokens = optionNullablePositiveInteger(value.maxTokens, "checkpoint.options.context.maxTokens");
337
+ return maxMessages === undefined && maxChars === undefined && maxTokens === undefined
338
+ ? undefined
339
+ : Object.freeze({ maxMessages, maxChars, maxTokens });
340
+ }
341
+
342
+ function checkpointToolExecutionOptions(
343
+ value: JsonObject,
344
+ agent: AgentDefinition,
345
+ invocationId: string,
346
+ ): AgentToolExecutionOptions {
347
+ const maxAttempts = value.maxAttempts;
348
+ if (maxAttempts !== 1) throw new AgentRuntimeError("checkpoint.options.tool.maxAttempts must be 1.");
349
+ const scopeDisposeTimeoutMs = optionPositiveInteger(value.scopeDisposeTimeoutMs, "checkpoint.options.tool.scopeDisposeTimeoutMs");
350
+ const timeouts = value.timeouts;
351
+ if (!Array.isArray(timeouts)) throw new AgentRuntimeError("checkpoint.options.tool.timeouts must be an array.");
352
+ const expected = agent.tools.map((tool) => tool.metadata.name).sort();
353
+ const actual = timeouts.map((entry) => {
354
+ if (!isPlainJsonObject(entry)) throw new AgentRuntimeError("checkpoint.options.tool.timeouts entry must be an object.");
355
+ const name = optionText(entry.name, "checkpoint.options.tool.timeouts.name");
356
+ if (name === undefined) throw new AgentRuntimeError("checkpoint.options.tool.timeouts.name is required.");
357
+ optionPositiveInteger(entry.timeoutMs, "checkpoint.options.tool.timeouts.timeoutMs");
358
+ return name;
359
+ });
360
+ if (expected.length !== actual.length || expected.some((name, index) => name !== actual[index])) {
361
+ throw new AgentRuntimeError(`checkpoint for invocation "${invocationId}" does not match the bound Agent tools.`);
362
+ }
363
+ return Object.freeze({ retryPolicy: Object.freeze({ maxAttempts: 1 }), scopeDisposeTimeoutMs });
364
+ }
365
+
366
+ function checkpointToolTimeouts(value: JsonObject): ReadonlyMap<string, number> {
367
+ const entries = value.timeouts;
368
+ if (!Array.isArray(entries)) throw new AgentRuntimeError("checkpoint.options.tool.timeouts must be an array.");
369
+ const timeouts = new Map<string, number>();
370
+ for (const entry of entries) {
371
+ if (!isPlainJsonObject(entry)) throw new AgentRuntimeError("checkpoint.options.tool.timeouts entry must be an object.");
372
+ const name = optionText(entry.name, "checkpoint.options.tool.timeouts.name");
373
+ if (name === undefined || timeouts.has(name)) throw new AgentRuntimeError("checkpoint.options.tool.timeouts must contain unique names.");
374
+ timeouts.set(name, optionPositiveInteger(entry.timeoutMs, "checkpoint.options.tool.timeouts.timeoutMs"));
375
+ }
376
+ return timeouts;
377
+ }
378
+
379
+ function generatedInvocationId(): string {
380
+ return `inv-${crypto.randomUUID()}`;
381
+ }
382
+
383
+ function classDebugName(value: unknown): string {
384
+ const name = (value as { readonly name?: unknown }).name;
385
+ return typeof name === "string" && name.trim().length > 0 ? name : "<anonymous class>";
386
+ }
387
+
388
+
389
+ function isObjectRecord(value: unknown): value is Record<string, unknown> {
390
+ return typeof value === "object" && value !== null && !Array.isArray(value);
391
+ }
392
+
393
+ function responseMessage(response: AgentModelResponse): AgentMessage | undefined {
394
+ return response.message;
395
+ }
396
+
397
+ function normalizeProviderResponse(value: unknown): AgentModelResponse {
398
+ if (!isObjectRecord(value) || !Array.isArray(value.toolCalls)) {
399
+ throw new AgentRuntimeError("Model provider response must be an object with a toolCalls array.");
400
+ }
401
+ const rawMessage = value.message;
402
+ const message = rawMessage === undefined
403
+ ? undefined
404
+ : (() => {
405
+ if (!isObjectRecord(rawMessage)) {
406
+ throw new AgentRuntimeError("Model provider response message must be an object.");
407
+ }
408
+ return agentMessage(
409
+ rawMessage.role as AgentMessage["role"],
410
+ rawMessage.content as AgentMessage["content"],
411
+ {
412
+ id: rawMessage.id as string | undefined,
413
+ name: rawMessage.name as string | undefined,
414
+ toolCallId: rawMessage.toolCallId as string | undefined,
415
+ createdAtUnixMs: rawMessage.createdAtUnixMs as number | undefined,
416
+ metadata: rawMessage.metadata,
417
+ },
418
+ );
419
+ })();
420
+ const toolCalls = value.toolCalls.map((call, index) => {
421
+ if (!isObjectRecord(call)) {
422
+ throw new AgentRuntimeError(`Model provider toolCalls[${index}] must be an object.`);
423
+ }
424
+ return agentToolCall({
425
+ id: call.id as string,
426
+ name: call.name as string,
427
+ input: call.input,
428
+ metadata: call.metadata,
429
+ });
430
+ });
431
+ return agentModelResponse({
432
+ invocationId: value.invocationId as string,
433
+ finishReason: value.finishReason as AgentModelResponse["finishReason"],
434
+ message,
435
+ toolCalls,
436
+ usage: value.usage as AgentModelResponse["usage"],
437
+ metadata: value.metadata,
438
+ });
439
+ }
440
+
441
+ function runtimeError(code: string, message: string, details?: JsonValue): AgentToolError {
442
+ return Object.freeze({
443
+ code,
444
+ message: redactSensitiveText(message),
445
+ ...(details !== undefined ? { details: redactSensitive(details) } : {}),
446
+ });
447
+ }
448
+
449
+ function runtimeResult(options: {
450
+ readonly invocationId: string;
451
+ readonly agentName: string;
452
+ readonly status: AgentRuntimeStatus;
453
+ readonly steps: number;
454
+ readonly messages: readonly AgentMessage[];
455
+ readonly responses: readonly AgentModelResponse[];
456
+ readonly toolResults: readonly AgentToolResult[];
457
+ readonly finalMessage?: AgentMessage;
458
+ readonly output?: JsonValue;
459
+ readonly error?: AgentToolError;
460
+ readonly metadata: JsonObject;
461
+ }): AgentRuntimeResult {
462
+ return Object.freeze({
463
+ invocationId: options.invocationId,
464
+ agentName: options.agentName,
465
+ status: options.status,
466
+ steps: options.steps,
467
+ messages: Object.freeze([...options.messages]),
468
+ responses: Object.freeze([...options.responses]),
469
+ toolResults: Object.freeze([...options.toolResults]),
470
+ ...(options.finalMessage !== undefined ? { finalMessage: options.finalMessage } : {}),
471
+ ...(options.output !== undefined ? { output: options.output } : {}),
472
+ ...(options.error !== undefined ? { error: options.error } : {}),
473
+ metadata: options.metadata,
474
+ });
475
+ }
476
+
477
+ function timed<T>(
478
+ operation: Promise<T>,
479
+ timeoutMs: number | undefined,
480
+ abort: () => void,
481
+ signal?: AbortSignal,
482
+ ): Promise<T> {
483
+ // `operation` may already be running. Observe rejection before a pre-abort
484
+ // fast path so hostile/late validators cannot escape as unhandled.
485
+ void operation.catch(() => undefined);
486
+ if (signal?.aborted) {
487
+ return Promise.reject(new AgentRuntimeAbortError());
488
+ }
489
+
490
+ return new Promise<T>((resolve, reject) => {
491
+ let settled = false;
492
+ let timer: ReturnType<typeof setTimeout> | undefined;
493
+ const finish = (callback: () => void): void => {
494
+ if (settled) return;
495
+ settled = true;
496
+ if (timer !== undefined) clearTimeout(timer);
497
+ signal?.removeEventListener("abort", onAbort);
498
+ callback();
499
+ };
500
+ const onAbort = () => finish(() => reject(new AgentRuntimeAbortError()));
501
+ signal?.addEventListener("abort", onAbort, { once: true });
502
+ timer = timeoutMs === undefined
503
+ ? undefined
504
+ : setTimeout(() => finish(() => {
505
+ reject(new AgentRuntimeTimeoutError());
506
+ abort();
507
+ }), timeoutMs);
508
+
509
+ operation.then(
510
+ (value) => {
511
+ finish(() => resolve(value));
512
+ },
513
+ (error: unknown) => {
514
+ finish(() => reject(error));
515
+ },
516
+ );
517
+ });
518
+ }
519
+
520
+ function attachAbortForwarding(source: AbortSignal | undefined, target: AbortController): (() => void) | undefined {
521
+ if (source === undefined) {
522
+ return undefined;
523
+ }
524
+ if (source.aborted) {
525
+ target.abort(source.reason);
526
+ return undefined;
527
+ }
528
+ const abort = () => target.abort(source.reason);
529
+ source.addEventListener("abort", abort, { once: true });
530
+ return () => source.removeEventListener("abort", abort);
531
+ }
532
+
533
+ export class AgentExecutionDriver {
534
+ private readonly toolExecutor: AgentToolExecutor;
535
+ private readonly defaultMaxSteps: number;
536
+ private readonly defaultMaxToolCallsPerStep: number;
537
+ private readonly defaultModelProfile?: string;
538
+ private readonly hasConcreteModelOption: boolean;
539
+ readonly defaultTimeoutMs?: number;
540
+ private readonly defaultContextLimits?: AgentContextLimits;
541
+ private readonly contextBuilder: AgentContextBuilder;
542
+ private readonly taskSchemaValidator?: AgentToolSchemaValidator;
543
+
544
+ constructor(
545
+ services: ServiceProvider,
546
+ private readonly registry: AgentRegistry,
547
+ private readonly modelProvider: AgentModelProvider,
548
+ options: AgentRuntimeOptions = {},
549
+ ) {
550
+ assertPositiveInteger(options.maxSteps, "AgentRuntime.maxSteps");
551
+ assertPositiveInteger(options.maxToolCallsPerStep, "AgentRuntime.maxToolCallsPerStep");
552
+ assertNonNegativeInteger(options.timeoutMs, "AgentRuntime.timeoutMs");
553
+ this.defaultMaxSteps = options.maxSteps ?? DEFAULT_MAX_STEPS;
554
+ this.defaultMaxToolCallsPerStep = options.maxToolCallsPerStep ?? DEFAULT_MAX_TOOL_CALLS_PER_STEP;
555
+ this.defaultModelProfile = optionalText(options.modelProfile, "AgentRuntime.modelProfile");
556
+ this.hasConcreteModelOption = options.model !== undefined;
557
+ this.defaultTimeoutMs = options.timeoutMs === 0
558
+ ? undefined
559
+ : options.timeoutMs ?? DEFAULT_MODEL_TIMEOUT_MS;
560
+ this.defaultContextLimits = normalizeAgentContextLimits(options.contextLimits, "AgentRuntime.contextLimits");
561
+ this.contextBuilder = options.contextBuilder ?? new DefaultAgentContextBuilder();
562
+ this.taskSchemaValidator = options.taskSchemaValidator ?? options.toolExecutorOptions?.schemaValidator;
563
+ this.toolExecutor = new AgentToolExecutor(services, registry, options.toolExecutorOptions);
564
+ }
565
+
566
+ async invoke(agentName: string, options: AgentRuntimeInvokeOptions = {}): Promise<AgentRuntimeResult> {
567
+ const prepared = await this.prepareAgent(agentName, options);
568
+ return prepared.ok ? this.drive(prepared.plan) : prepared.result;
569
+ }
570
+
571
+ async prepareSessionCheckpoint(request: AgentSessionPreparationV1): Promise<AgentSessionPreparationOutcomeV1> {
572
+ try {
573
+ this.assertSessionPreparation(request);
574
+ const options: AgentRuntimeInvokeOptions = {
575
+ id: request.invocationId,
576
+ input: request.input,
577
+ maxSteps: request.requested.maxSteps ?? undefined,
578
+ maxToolCallsPerStep: request.requested.maxToolCallsPerStep ?? undefined,
579
+ modelProfile: request.requested.modelProfile ?? undefined,
580
+ timeoutMs: request.module.providerCallTimeoutMs,
581
+ contextLimits: undefined,
582
+ signal: request.signal,
583
+ };
584
+ const prepared = request.taskName === null
585
+ ? await this.prepareAgent(request.agentName, options)
586
+ : await this.prepareTask(request.agentName, request.taskName, request.input, options);
587
+ if (!prepared.ok) return { kind: "rejected", result: prepared.result };
588
+ const plan = "plan" in prepared ? prepared.plan : prepared.prepared.plan;
589
+ const task = "plan" in prepared ? undefined : prepared.prepared.task;
590
+ const maxSteps = request.requested.maxSteps ?? Math.min(task?.metadata.maxSteps ?? plan.agent.metadata.maxSteps ?? request.module.maxSessionSteps, request.module.maxSessionSteps);
591
+ const maxToolCallsPerStep = request.requested.maxToolCallsPerStep ?? request.module.maxToolCallsPerStep;
592
+ const runTimeoutMs = request.requested.runTimeoutMs ?? request.module.runTimeoutMs;
593
+ const modelProfile = request.requested.modelProfile ?? task?.metadata.modelProfile ?? plan.agent.metadata.modelProfile ?? null;
594
+ if (maxSteps > request.module.maxSessionSteps || maxToolCallsPerStep > request.module.maxToolCallsPerStep || runTimeoutMs > request.module.runTimeoutMs) {
595
+ throw new AgentRuntimeError("AgentSession requested limits must not exceed module limits.");
596
+ }
597
+ return { kind: "prepared", checkpoint: this.initialCheckpoint({ ...plan, contextLimits: undefined }, {
598
+ maxSteps, maxToolCallsPerStep, runTimeoutMs, modelProfile,
599
+ providerTimeoutMs: request.module.providerCallTimeoutMs,
600
+ toolDefaultTimeoutMs: request.module.toolDefaultTimeoutMs,
601
+ scopeDisposeTimeoutMs: request.module.scopeDisposeTimeoutMs,
602
+ }) };
603
+ } catch (error) {
604
+ return { kind: "rejected", result: runtimeResult({
605
+ invocationId: request.invocationId, agentName: request.agentName, status: "failed", steps: 0,
606
+ messages: [], responses: [], toolResults: [], metadata: Object.freeze({}),
607
+ error: runtimeError("AGENT_RUNTIME_OPTIONS_INVALID", errorMessageOf(error)),
608
+ }) };
609
+ }
610
+ }
611
+
612
+ private assertSessionPreparation(request: AgentSessionPreparationV1): void {
613
+ for (const [value, field] of [
614
+ [request.module.maxSessionSteps, "AgentSession.maxSessionSteps"], [request.module.maxToolCallsPerStep, "AgentSession.maxToolCallsPerStep"],
615
+ [request.module.runTimeoutMs, "AgentSession.runTimeoutMs"], [request.module.providerCallTimeoutMs, "AgentSession.providerCallTimeoutMs"],
616
+ [request.module.toolDefaultTimeoutMs, "AgentSession.toolDefaultTimeoutMs"], [request.module.scopeDisposeTimeoutMs, "AgentSession.scopeDisposeTimeoutMs"],
617
+ ] as const) assertPositiveInteger(value, field);
618
+ for (const [value, field] of [[request.requested.maxSteps, "AgentSession.maxSteps"], [request.requested.maxToolCallsPerStep, "AgentSession.maxToolCallsPerStep"], [request.requested.runTimeoutMs, "AgentSession.runTimeoutMs"]] as const) assertPositiveInteger(value ?? undefined, field);
619
+ if (request.taskName !== null && request.taskName.trim().length === 0) throw new AgentRuntimeError("AgentSession.taskName must be non-empty.");
620
+ }
621
+
622
+ private initialCheckpoint(plan: PreparedAgentPlan, resolved: {
623
+ readonly maxSteps: number; readonly maxToolCallsPerStep: number; readonly runTimeoutMs: number; readonly modelProfile: string | null;
624
+ readonly providerTimeoutMs: number; readonly toolDefaultTimeoutMs: number; readonly scopeDisposeTimeoutMs: number;
625
+ }): AgentExecutionCheckpointV1 {
626
+ const input = normalizeJsonValue(plan.options.input, "agentSession.input");
627
+ const task = plan.taskFinalization?.task.metadata.name;
628
+ return agentExecutionCheckpointV1({
629
+ version: "bazis.agent-execution-state/v1",
630
+ invocation: {
631
+ kind: task === undefined ? "agent" : "task",
632
+ invocationId: plan.invocationId,
633
+ agentName: plan.agent.metadata.name,
634
+ taskName: task ?? null,
635
+ input,
636
+ metadata: plan.metadata,
637
+ options: {
638
+ maxSteps: resolved.maxSteps,
639
+ maxToolCallsPerStep: resolved.maxToolCallsPerStep,
640
+ runTimeoutMs: resolved.runTimeoutMs,
641
+ modelProfile: resolved.modelProfile,
642
+ provider: { timeoutMs: resolved.providerTimeoutMs },
643
+ context: {
644
+ maxMessages: plan.contextLimits?.maxMessages ?? null,
645
+ maxChars: plan.contextLimits?.maxChars ?? null,
646
+ maxTokens: plan.contextLimits?.maxTokens ?? null,
647
+ },
648
+ output: { maxOutputTokens: null, temperature: null },
649
+ tool: {
650
+ defaultTimeoutMs: resolved.toolDefaultTimeoutMs,
651
+ scopeDisposeTimeoutMs: resolved.scopeDisposeTimeoutMs,
652
+ maxAttempts: 1,
653
+ timeouts: plan.agent.tools
654
+ .map((tool) => ({ name: tool.metadata.name, timeoutMs: tool.metadata.timeoutMs ?? resolved.toolDefaultTimeoutMs }))
655
+ .sort((left, right) => left.name < right.name ? -1 : left.name > right.name ? 1 : 0),
656
+ },
657
+ },
658
+ },
659
+ phase: "ready-model",
660
+ steps: 0,
661
+ messages: plan.messages.map((message) => ({
662
+ role: message.role,
663
+ content: message.content,
664
+ id: message.id ?? null,
665
+ name: message.name ?? null,
666
+ toolCallId: message.toolCallId ?? null,
667
+ createdAtUnixMs: message.createdAtUnixMs ?? null,
668
+ metadata: message.metadata,
669
+ })),
670
+ responses: [],
671
+ toolResults: [],
672
+ seenToolCallIds: [...plan.seenToolCallIds],
673
+ pendingToolBatch: null,
674
+ terminal: null,
675
+ });
676
+ }
677
+
678
+ /** Rebuilds only ephemeral definitions/options after Session binding qualification. */
679
+ private rehydratePlan(checkpoint: AgentExecutionCheckpointV1): PreparedAgentPlan {
680
+ const agent = this.registry.getAgent(checkpoint.invocation.agentName);
681
+ if (!agent) throw new AgentRuntimeError(`Agent "${checkpoint.invocation.agentName}" is not registered.`);
682
+ const options = checkpoint.invocation.options;
683
+ const maxSteps = optionPositiveInteger(options.maxSteps, "checkpoint.options.maxSteps");
684
+ const maxToolCallsPerStep = optionPositiveInteger(options.maxToolCallsPerStep, "checkpoint.options.maxToolCallsPerStep");
685
+ const modelProfile = optionText(options.modelProfile, "checkpoint.options.modelProfile");
686
+ const provider = checkpointOptionObject(options.provider, "checkpoint.options.provider");
687
+ const context = checkpointOptionObject(options.context, "checkpoint.options.context");
688
+ const output = checkpointOptionObject(options.output, "checkpoint.options.output");
689
+ const tool = checkpointOptionObject(options.tool, "checkpoint.options.tool");
690
+ const providerTimeoutMs = optionPositiveInteger(provider.timeoutMs, "checkpoint.options.provider.timeoutMs");
691
+ const contextLimits = checkpointContextLimits(context);
692
+ const toolOptions = checkpointToolExecutionOptions(tool, agent, checkpoint.invocation.invocationId);
693
+ const sessionToolTimeouts = checkpointToolTimeouts(tool);
694
+ let taskFinalization: TaskFinalizationPlan | undefined;
695
+ if (checkpoint.invocation.kind === "task") {
696
+ const task = this.registry.getTask(agent.metadata.name, checkpoint.invocation.taskName!);
697
+ if (!task) throw new AgentRuntimeError(`Task "${checkpoint.invocation.taskName}" is not registered on Agent "${agent.metadata.name}".`);
698
+ taskFinalization = { task, timeoutMs: providerTimeoutMs, signal: undefined };
699
+ }
700
+ return {
701
+ agent,
702
+ invocationId: checkpoint.invocation.invocationId,
703
+ metadata: checkpoint.invocation.metadata,
704
+ maxSteps,
705
+ maxToolCallsPerStep,
706
+ timeoutMs: providerTimeoutMs,
707
+ modelProfile,
708
+ contextLimits,
709
+ messages: [...checkpoint.messages],
710
+ seenToolCallIds: new Set(checkpoint.seenToolCallIds),
711
+ tools: this.toolContracts(agent),
712
+ executorToolOptions: toolOptions,
713
+ sessionToolTimeouts,
714
+ options: {
715
+ id: checkpoint.invocation.invocationId,
716
+ input: checkpoint.invocation.input,
717
+ metadata: checkpoint.invocation.metadata,
718
+ modelProfile,
719
+ maxOutputTokens: optionNullablePositiveInteger(output.maxOutputTokens, "checkpoint.options.output.maxOutputTokens"),
720
+ temperature: optionNullableFiniteNonNegative(output.temperature, "checkpoint.options.output.temperature"),
721
+ ...(taskFinalization === undefined ? {} : { output: this.taskOutputContract(taskFinalization.task) }),
722
+ },
723
+ taskFinalization,
724
+ };
725
+ }
726
+
727
+ private async prepareAgent(agentName: string, options: AgentRuntimeInvokeOptions): Promise<AgentPreparation> {
728
+ const invocationId = options.id ?? generatedInvocationId();
729
+ let metadata: JsonObject;
730
+ let maxSteps: number;
731
+ let maxToolCallsPerStep: number;
732
+ let timeoutMs: number | undefined;
733
+ let modelProfile: string | undefined;
734
+ let contextLimits: AgentContextLimits | undefined;
735
+ try {
736
+ metadata = normalizeMetadata(options.metadata, "agentRuntime.metadata");
737
+ assertPositiveInteger(options.maxSteps, "agentRuntime.maxSteps");
738
+ assertPositiveInteger(options.maxToolCallsPerStep, "agentRuntime.maxToolCallsPerStep");
739
+ assertNonNegativeInteger(options.timeoutMs, "agentRuntime.timeoutMs");
740
+ maxSteps = options.maxSteps ?? this.registry.getAgent(agentName)?.metadata.maxSteps ?? this.defaultMaxSteps;
741
+ maxToolCallsPerStep = options.maxToolCallsPerStep ?? this.defaultMaxToolCallsPerStep;
742
+ timeoutMs = options.timeoutMs === 0 ? undefined : options.timeoutMs ?? this.defaultTimeoutMs;
743
+ modelProfile = optionalText(options.modelProfile, "agentRuntime.modelProfile");
744
+ contextLimits = mergeAgentContextLimits(
745
+ this.defaultContextLimits,
746
+ normalizeAgentContextLimits(options.contextLimits, "agentRuntime.contextLimits"),
747
+ );
748
+ if (this.hasConcreteModelOption || options.model !== undefined) {
749
+ throw new AgentRuntimeError("Concrete model selection is owned by Infra; use modelProfile instead.");
750
+ }
751
+ } catch (error) {
752
+ return { ok: false, result: runtimeResult({ invocationId, agentName, status: "failed", steps: 0, messages: [], responses: [], toolResults: [], error: runtimeError("AGENT_RUNTIME_OPTIONS_INVALID", errorMessageOf(error)), metadata: Object.freeze({}) }) };
753
+ }
754
+
755
+ const agent = this.registry.getAgent(agentName);
756
+ if (!agent) {
757
+ return { ok: false, result: runtimeResult({ invocationId, agentName, status: "failed", steps: 0, messages: [], responses: [], toolResults: [], error: runtimeError("AGENT_NOT_REGISTERED", `Agent "${agentName}" is not registered.`), metadata }) };
758
+ }
759
+
760
+ let declaredInput: unknown = options.input;
761
+ if (agent.metadata.input !== undefined) {
762
+ const prepared = await this.prepareTaskContract(agent.metadata.input, options.input, "input", timeoutMs, options.signal, "agent");
763
+ if (!prepared.ok) {
764
+ return { ok: false, result: runtimeResult({ invocationId, agentName: agent.metadata.name, status: "failed", steps: 0, messages: [], responses: [], toolResults: [], error: this.agentContractError(prepared.error, "input"), metadata }) };
765
+ }
766
+ declaredInput = prepared.value;
767
+ }
768
+
769
+ let messages: AgentMessage[];
770
+ let seenToolCallIds: Set<string>;
771
+ try {
772
+ messages = this.initialMessages({ ...options, input: declaredInput });
773
+ seenToolCallIds = this.initialToolCallIds(messages);
774
+ } catch (error) {
775
+ return { ok: false, result: runtimeResult({ invocationId, agentName: agent.metadata.name, status: "failed", steps: 0, messages: [], responses: [], toolResults: [], error: runtimeError("AGENT_INPUT_INVALID", errorMessageOf(error)), metadata }) };
776
+ }
777
+
778
+ return {
779
+ ok: true,
780
+ plan: {
781
+ agent,
782
+ invocationId,
783
+ metadata,
784
+ maxSteps,
785
+ maxToolCallsPerStep,
786
+ timeoutMs,
787
+ modelProfile,
788
+ contextLimits,
789
+ messages,
790
+ seenToolCallIds,
791
+ tools: this.toolContracts(agent),
792
+ executorToolOptions: this.executorToolOptions(options.toolExecution),
793
+ options: { ...options, id: invocationId, input: declaredInput },
794
+ },
795
+ };
796
+ }
797
+
798
+ private async prepareTask(
799
+ agentName: string,
800
+ taskName: string,
801
+ input: unknown,
802
+ options: AgentRuntimeTaskInvokeOptions,
803
+ ): Promise<TaskPreparation> {
804
+ const invocationId = options.id ?? generatedInvocationId();
805
+ const task = this.registry.getTask(agentName, taskName);
806
+ if (!task) {
807
+ return { ok: false, result: runtimeResult({ invocationId, agentName, status: "failed", steps: 0, messages: [], responses: [], toolResults: [], error: runtimeError("AGENT_TASK_NOT_REGISTERED", `Task "${taskName}" is not registered on Agent "${agentName}".`), metadata: Object.freeze({ taskName }) }) };
808
+ }
809
+
810
+ let timeoutMs: number | undefined;
811
+ try {
812
+ assertNonNegativeInteger(options.timeoutMs, "agentRuntime.timeoutMs");
813
+ timeoutMs = options.timeoutMs === 0 ? undefined : options.timeoutMs ?? this.defaultTimeoutMs;
814
+ } catch (error) {
815
+ return { ok: false, result: runtimeResult({ invocationId, agentName, status: "failed", steps: 0, messages: [], responses: [], toolResults: [], error: runtimeError("AGENT_RUNTIME_OPTIONS_INVALID", errorMessageOf(error)), metadata: Object.freeze({ taskName }) }) };
816
+ }
817
+
818
+ let preparedInput: unknown = input;
819
+ if (task.metadata.input !== undefined) {
820
+ const prepared = await this.prepareTaskContract(task.metadata.input, input, "input", timeoutMs, options.signal, "task");
821
+ if (!prepared.ok) {
822
+ return { ok: false, result: runtimeResult({ invocationId, agentName: task.agent.metadata.name, status: "failed", steps: 0, messages: [], responses: [], toolResults: [], error: prepared.error, metadata: Object.freeze({ taskName: task.metadata.name }) }) };
823
+ }
824
+ preparedInput = prepared.value;
825
+ }
826
+
827
+ const agent = await this.prepareAgent(task.agent.metadata.name, {
828
+ ...options,
829
+ id: invocationId,
830
+ input: preparedInput,
831
+ output: this.taskOutputContract(task) ?? options.output,
832
+ modelProfile: options.modelProfile ?? task.metadata.modelProfile,
833
+ maxSteps: options.maxSteps ?? task.metadata.maxSteps,
834
+ metadata: this.taskInvocationMetadata(options.metadata, task),
835
+ });
836
+ if (!agent.ok) return agent;
837
+ return {
838
+ ok: true,
839
+ prepared: {
840
+ task,
841
+ timeoutMs,
842
+ plan: {
843
+ ...agent.plan,
844
+ taskFinalization: { task, timeoutMs, signal: options.signal },
845
+ },
846
+ },
847
+ };
848
+ }
849
+
850
+ /**
851
+ * Private durable continuation. The Session coordinator parses persisted
852
+ * text first and performs binding authorization before reaching this method.
853
+ */
854
+ async driveCheckpoint(request: AgentExecutionDriveRequestV1): Promise<AgentExecutionDriveOutcome> {
855
+ const checkpoint = requireIssuedAgentExecutionCheckpointV1(request.checkpoint);
856
+ if (checkpoint.phase === "terminal") throw new AgentRuntimeError("terminal Agent Session checkpoints cannot be resumed.");
857
+ const plan = this.rehydratePlan(checkpoint);
858
+ const outcome = await this.drivePhaseEngine(plan, checkpoint, request.boundary, request.signal, {
859
+ evolve: evolveAgentExecutionCheckpointV1,
860
+ boundaryError: (state) => new AgentExecutionBoundaryError(state),
861
+ }, true);
862
+ return outcome.kind === "terminal"
863
+ ? { kind: "terminal", checkpoint: outcome.state, result: outcome.result }
864
+ : { kind: "suspended", checkpoint: outcome.state, reason: outcome.reason };
865
+ }
866
+
867
+ private async drivePhaseEngine<TState extends EngineProgress>(
868
+ plan: PreparedAgentPlan,
869
+ initial: TState,
870
+ boundary: EngineBoundary<TState>,
871
+ signal: AbortSignal | undefined,
872
+ bridge: PhaseBridge<TState>,
873
+ session: boolean,
874
+ ): Promise<EngineOutcome<TState>> {
875
+ let checkpoint = initial;
876
+ const suspend = (reason: string): EngineOutcome<TState> => ({ kind: "suspended", state: checkpoint, reason });
877
+ const control = async (candidate: TState): Promise<EngineOutcome<TState> | undefined> => {
878
+ try {
879
+ const decision = await boundary.checkControl(checkpoint, candidate);
880
+ if (decision.kind === "suspend") return suspend(decision.reason);
881
+ checkpoint = candidate;
882
+ return undefined;
883
+ } catch {
884
+ throw bridge.boundaryError(checkpoint);
885
+ }
886
+ };
887
+ const committedControl = async (candidate: TState): Promise<EngineOutcome<TState> | undefined> => {
888
+ checkpoint = candidate;
889
+ try {
890
+ const decision = await boundary.checkControl(checkpoint, checkpoint);
891
+ return decision.kind === "suspend" ? suspend(decision.reason) : undefined;
892
+ } catch {
893
+ throw bridge.boundaryError(checkpoint);
894
+ }
895
+ };
896
+ const terminal = (state: TState, result: AgentRuntimeResult): EngineOutcome<TState> => ({ kind: "terminal", state, result });
897
+
898
+ for (;;) {
899
+ if (session && signal?.aborted) return suspend("aborted");
900
+ if (checkpoint.phase === "pending-tools") {
901
+ const pendingControl = await control(checkpoint);
902
+ if (pendingControl !== undefined) return pendingControl;
903
+ const pending = checkpoint.pendingToolBatch!;
904
+ const response = checkpoint.responses[pending.responseIndex]!;
905
+ const call = response.toolCalls[pending.nextToolIndex]!;
906
+ let idempotencyKey: string;
907
+ try {
908
+ idempotencyKey = !session
909
+ ? this.toolIdempotencyKey(plan.options.toolExecution, { invocationId: plan.invocationId, agentName: plan.agent.metadata.name, call })
910
+ : this.sessionIdempotencyKey(plan.invocationId, call.id);
911
+ } catch (error) {
912
+ if (session) throw bridge.boundaryError(checkpoint);
913
+ const failed = bridge.evolve(checkpoint, { phase: "terminal", steps: checkpoint.steps, messages: checkpoint.messages, responses: checkpoint.responses, toolResults: checkpoint.toolResults, seenToolCallIds: checkpoint.seenToolCallIds, pendingToolBatch: undefined, terminal: { status: "failed", error: runtimeError("AGENT_TOOL_OPTIONS_INVALID", errorMessageOf(error)) } });
914
+ return terminal(failed, this.resultFromCheckpoint(plan, failed));
915
+ }
916
+ try {
917
+ await boundary.beforeToolDispatch(checkpoint, pending.step, pending.nextToolIndex, call, idempotencyKey);
918
+ } catch {
919
+ return suspend("before-tool-rejected");
920
+ }
921
+ const toolTimeoutMs = plan.sessionToolTimeouts?.get(call.name);
922
+ const result = await this.toolExecutor.execute(call, {
923
+ ...plan.executorToolOptions,
924
+ ...(toolTimeoutMs === undefined ? {} : { timeoutMs: toolTimeoutMs }),
925
+ agentName: plan.agent.metadata.name,
926
+ invocationId: plan.invocationId,
927
+ metadata: plan.metadata,
928
+ signal,
929
+ idempotencyKey,
930
+ });
931
+ const messages = [...checkpoint.messages, agentMessage("tool", agentToolResultPart(result), {
932
+ toolCallId: call.id, metadata: { toolName: call.name },
933
+ })];
934
+ const toolResults = [...checkpoint.toolResults, result];
935
+ const isUnknown = result.error?.code?.endsWith("_OUTCOME_UNKNOWN") === true;
936
+ const nextToolIndex = pending.nextToolIndex + 1;
937
+ const candidate = bridge.evolve(checkpoint, {
938
+ phase: isUnknown ? "terminal" : nextToolIndex === response.toolCalls.length ? "ready-model" : "pending-tools",
939
+ steps: checkpoint.steps,
940
+ messages,
941
+ responses: checkpoint.responses,
942
+ toolResults,
943
+ seenToolCallIds: checkpoint.seenToolCallIds,
944
+ pendingToolBatch: isUnknown && nextToolIndex < response.toolCalls.length
945
+ ? { ...pending, nextToolIndex }
946
+ : nextToolIndex === response.toolCalls.length ? undefined : { ...pending, nextToolIndex },
947
+ terminal: isUnknown ? {
948
+ status: "failed",
949
+ error: runtimeError("AGENT_TOOL_OUTCOME_UNKNOWN", `Tool "${call.name}" finished with an unknown retry-safe side-effect outcome; automatic model continuation is blocked.`, {
950
+ callId: call.id, toolName: call.name, idempotencyKey, toolErrorCode: result.error?.code,
951
+ }),
952
+ } : undefined,
953
+ });
954
+ try {
955
+ await boundary.afterToolSettlement(checkpoint, candidate, pending.step, pending.nextToolIndex, call, idempotencyKey, result);
956
+ } catch {
957
+ throw bridge.boundaryError(checkpoint);
958
+ }
959
+ const stopped = await committedControl(candidate);
960
+ if (stopped !== undefined) return stopped;
961
+ if (candidate.phase === "terminal") return terminal(candidate, this.resultFromCheckpoint(plan, candidate));
962
+ continue;
963
+ }
964
+
965
+ if (checkpoint.steps >= plan.maxSteps) {
966
+ const candidate = bridge.evolve(checkpoint, {
967
+ phase: "terminal", steps: checkpoint.steps, messages: checkpoint.messages, responses: checkpoint.responses,
968
+ toolResults: checkpoint.toolResults, seenToolCallIds: checkpoint.seenToolCallIds, pendingToolBatch: undefined,
969
+ terminal: { status: "failed", error: runtimeError("AGENT_MAX_STEPS_EXCEEDED", `Agent "${plan.agent.metadata.name}" exceeded maxSteps (${plan.maxSteps}).`, { maxSteps: plan.maxSteps }) },
970
+ });
971
+ const stopped = await control(candidate);
972
+ return stopped ?? terminal(candidate, this.resultFromCheckpoint(plan, candidate));
973
+ }
974
+
975
+ const step = checkpoint.steps + 1;
976
+ const readyControl = await control(checkpoint);
977
+ if (readyControl !== undefined) return readyControl;
978
+ let modelRequest: AgentModelRequest;
979
+ try {
980
+ const context = this.contextBuilder.build({ invocationId: plan.invocationId, agent: plan.agent, messages: checkpoint.messages, metadata: plan.metadata, limits: plan.contextLimits });
981
+ modelRequest = agentModelRequest({
982
+ invocationId: plan.invocationId, messages: context.messages, tools: plan.tools,
983
+ output: this.providerOutputContract(plan.agent.metadata.output === undefined ? plan.options.output : this.agentOutputContract(plan.agent)),
984
+ modelProfile: plan.modelProfile,
985
+ maxOutputTokens: plan.options.maxOutputTokens, temperature: plan.options.temperature,
986
+ metadata: { ...plan.metadata, agentName: plan.agent.metadata.name, step, modelProfile: plan.modelProfile ?? null, agentContext: context.metadata },
987
+ });
988
+ } catch (error) {
989
+ const candidate = bridge.evolve(checkpoint, {
990
+ phase: "terminal", steps: step, messages: checkpoint.messages, responses: checkpoint.responses, toolResults: checkpoint.toolResults,
991
+ seenToolCallIds: checkpoint.seenToolCallIds, pendingToolBatch: undefined,
992
+ terminal: { status: "failed", error: runtimeError("AGENT_CONTEXT_INVALID", errorMessageOf(error)) },
993
+ });
994
+ const stopped = await control(candidate);
995
+ return stopped ?? terminal(candidate, this.resultFromCheckpoint(plan, candidate));
996
+ }
997
+ try {
998
+ await boundary.beforeModelDispatch(checkpoint, step, modelRequest);
999
+ } catch {
1000
+ return suspend("before-model-rejected");
1001
+ }
1002
+ const response = await this.completeModel(modelRequest, plan.agent.metadata.name, plan.modelProfile, plan.metadata, signal, plan.timeoutMs,
1003
+ plan.options.onTextDelta ? text => plan.options.onTextDelta!(Object.freeze({ step, text })) : undefined);
1004
+ if (!response.ok) {
1005
+ const candidate = bridge.evolve(checkpoint, {
1006
+ phase: "terminal", steps: step, messages: checkpoint.messages, responses: checkpoint.responses, toolResults: checkpoint.toolResults,
1007
+ seenToolCallIds: checkpoint.seenToolCallIds, pendingToolBatch: undefined, terminal: { status: "failed", error: response.error },
1008
+ });
1009
+ try { await boundary.afterModelSettlement(checkpoint, candidate, step, { error: response.error }); } catch { throw bridge.boundaryError(checkpoint); }
1010
+ const stopped = await committedControl(candidate);
1011
+ return stopped ?? terminal(candidate, this.resultFromCheckpoint(plan, candidate));
1012
+ }
1013
+ const candidate = await this.modelCandidate(plan, checkpoint, step, response.value, signal, bridge);
1014
+ try { await boundary.afterModelSettlement(checkpoint, candidate.state, step, { response: response.value }); } catch { throw bridge.boundaryError(checkpoint); }
1015
+ const stopped = await committedControl(candidate.state);
1016
+ if (stopped !== undefined) return stopped;
1017
+ if (candidate.state.phase === "terminal") return terminal(candidate.state, candidate.result ?? this.resultFromCheckpoint(plan, candidate.state));
1018
+ }
1019
+ }
1020
+
1021
+ private sessionIdempotencyKey(invocationId: string, callId: string): string {
1022
+ return `agent:${invocationId.length}:${invocationId}:${callId.length}:${callId}`;
1023
+ }
1024
+
1025
+ private resultFromCheckpoint(plan: PreparedAgentPlan, checkpoint: EngineProgress): AgentRuntimeResult {
1026
+ const terminal = checkpoint.terminal;
1027
+ if (terminal === undefined) throw new AgentRuntimeError("terminal checkpoint is required.");
1028
+ return runtimeResult({ invocationId: plan.invocationId, agentName: plan.agent.metadata.name, status: terminal.status,
1029
+ steps: checkpoint.steps, messages: checkpoint.messages, responses: checkpoint.responses, toolResults: checkpoint.toolResults,
1030
+ finalMessage: terminal.finalMessage, output: terminal.output, error: terminal.error, metadata: plan.metadata });
1031
+ }
1032
+
1033
+ private async modelCandidate<TState extends EngineProgress>(
1034
+ plan: PreparedAgentPlan, checkpoint: TState, step: number, response: AgentModelResponse, signal: AbortSignal | undefined, bridge: PhaseBridge<TState>,
1035
+ ): Promise<{ readonly state: TState; readonly result?: AgentRuntimeResult }> {
1036
+ const rejected = (code: string, message: string, retainResponse = true): { readonly state: TState; readonly result: AgentRuntimeResult } => {
1037
+ const state = bridge.evolve(checkpoint, { phase: "terminal", steps: step, messages: checkpoint.messages,
1038
+ responses: retainResponse ? [...checkpoint.responses, response] : checkpoint.responses, toolResults: checkpoint.toolResults, seenToolCallIds: checkpoint.seenToolCallIds,
1039
+ pendingToolBatch: undefined, terminal: { status: "failed", error: runtimeError(code, message) } });
1040
+ return { state, result: this.resultFromCheckpoint(plan, state) };
1041
+ };
1042
+ if (response.invocationId !== plan.invocationId) return rejected("AGENT_PROVIDER_RESPONSE_INVALID", "Model provider returned a response for another invocation.", false);
1043
+ if (response.toolCalls.length > plan.maxToolCallsPerStep) return rejected("AGENT_TOOL_CALL_LIMIT_EXCEEDED", `Model requested ${response.toolCalls.length} tool calls; the per-step limit is ${plan.maxToolCallsPerStep}.`);
1044
+ const seen = new Set(checkpoint.seenToolCallIds);
1045
+ for (const call of response.toolCalls) { if (seen.has(call.id)) return rejected("AGENT_PROVIDER_RESPONSE_INVALID", `Model provider reused tool call id "${call.id}" within one invocation.`); seen.add(call.id); }
1046
+ const message = responseMessage(response);
1047
+ if (response.toolCalls.length > 0 && message !== undefined && message.role !== "assistant") return rejected("AGENT_PROVIDER_RESPONSE_INVALID", "A response with tool calls must use an assistant message.");
1048
+ if (response.toolCalls.length > 0) {
1049
+ const assistant = agentMessage("assistant", [...(message?.content ?? []), ...response.toolCalls.map(agentToolCallPart)], message === undefined ? {} : { id: message.id, name: message.name, createdAtUnixMs: message.createdAtUnixMs, metadata: message.metadata });
1050
+ const state = bridge.evolve(checkpoint, { phase: "pending-tools", steps: step, messages: [...checkpoint.messages, assistant], responses: [...checkpoint.responses, response], toolResults: checkpoint.toolResults, seenToolCallIds: [...seen], pendingToolBatch: { step, responseIndex: checkpoint.responses.length, assistantMessageIndex: checkpoint.messages.length, nextToolIndex: 0 }, terminal: undefined });
1051
+ return { state };
1052
+ }
1053
+ const messages = message === undefined ? checkpoint.messages : [...checkpoint.messages, message];
1054
+ let result: AgentRuntimeResult;
1055
+ if (response.finishReason !== "stop" || message === undefined) {
1056
+ result = runtimeResult({ invocationId: plan.invocationId, agentName: plan.agent.metadata.name, status: "failed", steps: step, messages, responses: [...checkpoint.responses, response], toolResults: checkpoint.toolResults, finalMessage: message, metadata: plan.metadata,
1057
+ error: runtimeError("AGENT_PROVIDER_STOPPED", `Model provider stopped with finishReason "${response.finishReason}".`) });
1058
+ } else {
1059
+ result = runtimeResult({ invocationId: plan.invocationId, agentName: plan.agent.metadata.name, status: "completed", steps: step, messages, responses: [...checkpoint.responses, response], toolResults: checkpoint.toolResults, finalMessage: message, metadata: plan.metadata });
1060
+ if (plan.agent.metadata.output !== undefined) {
1061
+ try {
1062
+ const output = this.parseTaskOutput(message);
1063
+ const prepared = await this.prepareTaskContract(plan.agent.metadata.output, output, "output", plan.timeoutMs, signal, "agent");
1064
+ result = prepared.ok
1065
+ ? runtimeResult({ ...result, output: prepared.value })
1066
+ : this.failedTaskResult(result, this.agentContractError(prepared.error, "output"));
1067
+ } catch (error) {
1068
+ result = this.failedTaskResult(result, runtimeError("AGENT_OUTPUT_INVALID", errorMessageOf(error)));
1069
+ }
1070
+ }
1071
+ if (plan.agent.metadata.output === undefined && plan.taskFinalization?.task.metadata.output === undefined && plan.options.output?.mode === "json") {
1072
+ result = this.validateExplicitOutput(result, plan.options.output);
1073
+ }
1074
+ if (result.status === "completed") result = await this.finalizeCompleted(plan, result, signal);
1075
+ }
1076
+ const state = bridge.evolve(checkpoint, { phase: "terminal", steps: step, messages: result.messages, responses: result.responses, toolResults: result.toolResults, seenToolCallIds: checkpoint.seenToolCallIds, pendingToolBatch: undefined,
1077
+ terminal: result.status === "completed" ? { status: "completed", finalMessage: result.finalMessage, output: result.output } : { status: "failed", finalMessage: result.finalMessage, error: result.error! } });
1078
+ return { state, result };
1079
+ }
1080
+
1081
+ private validateExplicitOutput(result: AgentRuntimeResult, contract: AgentOutputContract): AgentRuntimeResult {
1082
+ try {
1083
+ const output = normalizeJsonValue(this.parseTaskOutput(result.finalMessage), "agent.output");
1084
+ const declared = contract.schema;
1085
+ if (declared !== undefined) {
1086
+ const generated = declared.kind === "class" ? getGeneratedOpenApiMetadata().schemas[declared.name] : undefined;
1087
+ if (declared.kind === "class" && generated === undefined) {
1088
+ return this.failedTaskResult(result, runtimeError("AGENT_OUTPUT_SCHEMA_UNAVAILABLE", `Output class "${declared.name}" has no generated JSON schema.`));
1089
+ }
1090
+ const schema = declared.kind === "json-schema" ? declared.schema : inlineGeneratedSchema(generated, getGeneratedOpenApiMetadata().schemas);
1091
+ const issues = validateAgentJsonSchema(output, schema);
1092
+ if (issues.length > 0) return this.failedTaskResult(result, runtimeError("AGENT_OUTPUT_INVALID", "Agent output failed JSON Schema validation.", { schema: declared.name, issues }));
1093
+ }
1094
+ return runtimeResult({ ...result, output });
1095
+ } catch (error) {
1096
+ return this.failedTaskResult(result, runtimeError("AGENT_OUTPUT_INVALID", errorMessageOf(error)));
1097
+ }
1098
+ }
1099
+
1100
+ private async drive(plan: PreparedAgentPlan): Promise<AgentRuntimeResult> {
1101
+ const initial: InMemoryExecutionState = Object.freeze({
1102
+ phase: "ready-model", steps: 0, messages: Object.freeze([...plan.messages]), responses: Object.freeze([]), toolResults: Object.freeze([]), seenToolCallIds: Object.freeze([...plan.seenToolCallIds]),
1103
+ });
1104
+ const inMemoryBoundary: EngineBoundary<InMemoryExecutionState> = {
1105
+ async checkControl() { return { kind: "continue" }; }, async beforeModelDispatch() {}, async afterModelSettlement() {}, async beforeToolDispatch() {}, async afterToolSettlement() {},
1106
+ };
1107
+ const inMemoryBridge: PhaseBridge<InMemoryExecutionState> = {
1108
+ evolve(previous, progress) { return Object.freeze({ ...previous, ...progress }); },
1109
+ boundaryError() { return new AgentRuntimeError("in-memory execution boundary rejected a transition."); },
1110
+ };
1111
+ const resolvedPlan = { ...plan, modelProfile: plan.modelProfile ?? plan.agent.metadata.modelProfile ?? this.defaultModelProfile };
1112
+ const outcome = await this.drivePhaseEngine(resolvedPlan, initial, inMemoryBoundary, plan.options.signal, inMemoryBridge, false);
1113
+ if (outcome.kind === "terminal") return outcome.result;
1114
+ throw new AgentRuntimeError("in-memory execution cannot suspend.");
1115
+ }
1116
+ async invokeTask(
1117
+ agentName: string,
1118
+ taskName: string,
1119
+ input: unknown,
1120
+ options: AgentRuntimeTaskInvokeOptions = {},
1121
+ ): Promise<AgentRuntimeResult> {
1122
+ const preparation = await this.prepareTask(agentName, taskName, input, options);
1123
+ if (!preparation.ok) return preparation.result;
1124
+ return this.drive(preparation.prepared.plan);
1125
+ }
1126
+
1127
+ private async prepareTaskContract(
1128
+ contract: Class<object>,
1129
+ value: unknown,
1130
+ direction: "input" | "output",
1131
+ timeoutMs?: number,
1132
+ signal?: AbortSignal,
1133
+ contractKind: "agent" | "task" = "task",
1134
+ ): Promise<PreparedTaskContract> {
1135
+ if (signal?.aborted) {
1136
+ return { ok: false, error: runtimeError("AGENT_ABORTED", "Agent runtime invocation was aborted.") };
1137
+ }
1138
+ try {
1139
+ value = value instanceof contract
1140
+ ? agentModelJson(value, `task.${direction}`)
1141
+ : normalizeJsonValue(value, `task.${direction}`);
1142
+ } catch (error) {
1143
+ return { ok: false, error: runtimeError(direction === "input" ? "AGENT_TASK_INPUT_INVALID" : "AGENT_TASK_OUTPUT_INVALID", errorMessageOf(error)) };
1144
+ }
1145
+ const name = getGeneratedOpenApiSchemaName(contract) ?? classDebugName(contract);
1146
+ if (!isObjectRecord(value)) {
1147
+ return {
1148
+ ok: false,
1149
+ error: runtimeError(
1150
+ contractKind === "agent"
1151
+ ? direction === "input" ? "AGENT_INPUT_INVALID" : "AGENT_OUTPUT_INVALID"
1152
+ : direction === "input" ? "AGENT_TASK_INPUT_INVALID" : "AGENT_TASK_OUTPUT_INVALID",
1153
+ `${contractKind === "agent" ? "Agent" : "Task"} ${direction} schema "${name}" expects a JSON object.`,
1154
+ ),
1155
+ };
1156
+ }
1157
+
1158
+ const generated = getGeneratedOpenApiMetadata().schemas[name];
1159
+ if (generated === undefined && this.taskSchemaValidator === undefined) {
1160
+ return {
1161
+ ok: false,
1162
+ error: runtimeError(
1163
+ "AGENT_TASK_SCHEMA_VALIDATOR_MISSING",
1164
+ `Task ${direction} schema "${name}" has no generated JSON schema or configured validator.`,
1165
+ ),
1166
+ };
1167
+ }
1168
+ if (generated !== undefined) {
1169
+ const issues = validateAgentJsonSchema(value, inlineGeneratedSchema(generated, getGeneratedOpenApiMetadata().schemas));
1170
+ if (issues.length > 0) {
1171
+ return {
1172
+ ok: false,
1173
+ error: runtimeError(
1174
+ direction === "input" ? "AGENT_TASK_INPUT_VALIDATION_FAILED" : "AGENT_TASK_OUTPUT_VALIDATION_FAILED",
1175
+ `Task ${direction} failed generated schema validation.`,
1176
+ { schema: name, issues },
1177
+ ),
1178
+ };
1179
+ }
1180
+ }
1181
+
1182
+ let instance: object;
1183
+ try {
1184
+ instance = bindAgentModel(contract, value);
1185
+ } catch (error) {
1186
+ return {
1187
+ ok: false,
1188
+ error: runtimeError(
1189
+ direction === "input" ? "AGENT_TASK_INPUT_INVALID" : "AGENT_TASK_OUTPUT_INVALID",
1190
+ errorMessageOf(error),
1191
+ ),
1192
+ };
1193
+ }
1194
+
1195
+ if (this.taskSchemaValidator !== undefined) {
1196
+ try {
1197
+ const validation = await timed(
1198
+ Promise.resolve(this.taskSchemaValidator.validate(instance)),
1199
+ timeoutMs,
1200
+ () => undefined,
1201
+ signal,
1202
+ );
1203
+ if (!validation || typeof validation.isValid !== "boolean" || !Array.isArray(validation.errors)) {
1204
+ throw new AgentRuntimeError("task schema validator returned an invalid result.");
1205
+ }
1206
+ if (!validation.isValid) {
1207
+ return {
1208
+ ok: false,
1209
+ error: runtimeError(
1210
+ direction === "input" ? "AGENT_TASK_INPUT_VALIDATION_FAILED" : "AGENT_TASK_OUTPUT_VALIDATION_FAILED",
1211
+ `Task ${direction} failed model validation.`,
1212
+ {
1213
+ schema: name,
1214
+ issues: validation.errors.map((issue) => ({
1215
+ property: String(issue.property),
1216
+ message: String(issue.message),
1217
+ ...(issue.code !== undefined ? { code: String(issue.code) } : {}),
1218
+ })),
1219
+ },
1220
+ ),
1221
+ };
1222
+ }
1223
+ } catch (error) {
1224
+ if (error instanceof AgentRuntimeTimeoutError) {
1225
+ return {
1226
+ ok: false,
1227
+ error: runtimeError("AGENT_TASK_SCHEMA_VALIDATION_TIMEOUT", `Task ${direction} schema validation timed out.`, { schema: name }),
1228
+ };
1229
+ }
1230
+ if (error instanceof AgentRuntimeAbortError) {
1231
+ return { ok: false, error: runtimeError("AGENT_ABORTED", "Agent runtime invocation was aborted.") };
1232
+ }
1233
+ return {
1234
+ ok: false,
1235
+ error: runtimeError(
1236
+ "AGENT_TASK_SCHEMA_VALIDATION_FAILED",
1237
+ `Task ${direction} schema validation failed: ${errorMessageOf(error)}`,
1238
+ { schema: name },
1239
+ ),
1240
+ };
1241
+ }
1242
+ }
1243
+
1244
+ try {
1245
+ return { ok: true, instance, value: agentModelJson(instance, `task.${direction}`) };
1246
+ } catch (error) {
1247
+ return {
1248
+ ok: false,
1249
+ error: runtimeError(
1250
+ direction === "input" ? "AGENT_TASK_INPUT_INVALID" : "AGENT_TASK_OUTPUT_INVALID",
1251
+ errorMessageOf(error),
1252
+ ),
1253
+ };
1254
+ }
1255
+ }
1256
+
1257
+ private parseTaskOutput(message: AgentMessage | undefined): unknown {
1258
+ if (message === undefined) {
1259
+ throw new AgentRuntimeError("Task provider response does not contain a final message.");
1260
+ }
1261
+ if (message.content.length === 1 && message.content[0]?.kind === "data") {
1262
+ return message.content[0].value;
1263
+ }
1264
+ if (!message.content.every((part) => part.kind === "text")) {
1265
+ throw new AgentRuntimeError("Task JSON output must contain only text or one data part.");
1266
+ }
1267
+ const text = message.content.map((part) => part.kind === "text" ? part.text : "").join("\n").trim();
1268
+ if (text.length === 0) {
1269
+ throw new AgentRuntimeError("Task JSON output is empty.");
1270
+ }
1271
+ try {
1272
+ return JSON.parse(text) as unknown;
1273
+ } catch {
1274
+ throw new AgentRuntimeError("Task JSON output is malformed.");
1275
+ }
1276
+ }
1277
+
1278
+ private failedTaskResult(result: AgentRuntimeResult, error: AgentToolError): AgentRuntimeResult {
1279
+ return runtimeResult({
1280
+ invocationId: result.invocationId,
1281
+ agentName: result.agentName,
1282
+ status: "failed",
1283
+ steps: result.steps,
1284
+ messages: result.messages,
1285
+ responses: result.responses,
1286
+ toolResults: result.toolResults,
1287
+ finalMessage: result.finalMessage,
1288
+ error,
1289
+ metadata: result.metadata,
1290
+ });
1291
+ }
1292
+
1293
+ private async finalizeCompleted(plan: PreparedAgentPlan, result: AgentRuntimeResult, currentSignal?: AbortSignal): Promise<AgentRuntimeResult> {
1294
+ const finalization = plan.taskFinalization;
1295
+ if (finalization === undefined || finalization.task.metadata.output === undefined) {
1296
+ return result;
1297
+ }
1298
+ let outputValue: unknown;
1299
+ try {
1300
+ outputValue = this.parseTaskOutput(result.finalMessage);
1301
+ } catch (error) {
1302
+ return this.failedTaskResult(result, runtimeError("AGENT_TASK_OUTPUT_INVALID", errorMessageOf(error)));
1303
+ }
1304
+ const preparedOutput = await this.prepareTaskContract(
1305
+ finalization.task.metadata.output,
1306
+ outputValue,
1307
+ "output",
1308
+ finalization.timeoutMs,
1309
+ currentSignal,
1310
+ "task",
1311
+ );
1312
+ if (!preparedOutput.ok) {
1313
+ return this.failedTaskResult(result, preparedOutput.error);
1314
+ }
1315
+ return runtimeResult({
1316
+ invocationId: result.invocationId,
1317
+ agentName: result.agentName,
1318
+ status: "completed",
1319
+ steps: result.steps,
1320
+ messages: result.messages,
1321
+ responses: result.responses,
1322
+ toolResults: result.toolResults,
1323
+ finalMessage: result.finalMessage,
1324
+ output: preparedOutput.value,
1325
+ metadata: result.metadata,
1326
+ });
1327
+ }
1328
+
1329
+ private agentContractError(error: AgentToolError, direction: "input" | "output"): AgentToolError {
1330
+ if (error.code === "AGENT_TASK_SCHEMA_VALIDATION_TIMEOUT" || error.code === "AGENT_ABORTED") return error;
1331
+ return runtimeError(direction === "input" ? "AGENT_INPUT_INVALID" : "AGENT_OUTPUT_INVALID", error.message, error.details);
1332
+ }
1333
+
1334
+ private initialMessages(options: AgentRuntimeInvokeOptions): AgentMessage[] {
1335
+ const messages: AgentMessage[] = [];
1336
+ if (options.messages !== undefined) {
1337
+ messages.push(...options.messages);
1338
+ }
1339
+ if (options.input !== undefined) {
1340
+ messages.push(this.inputMessage(options.input));
1341
+ }
1342
+ if (messages.length === 0) {
1343
+ throw new AgentRuntimeError("agent invocation requires input or messages.");
1344
+ }
1345
+ return messages;
1346
+ }
1347
+
1348
+ private initialToolCallIds(messages: readonly AgentMessage[]): Set<string> {
1349
+ const ids = new Set<string>();
1350
+ for (const message of messages) {
1351
+ for (const part of message.content) {
1352
+ if (part.kind !== "tool-call") continue;
1353
+ if (ids.has(part.call.id)) {
1354
+ throw new AgentRuntimeError(`agent invocation messages contain duplicate tool call id "${part.call.id}".`);
1355
+ }
1356
+ ids.add(part.call.id);
1357
+ }
1358
+ }
1359
+ return ids;
1360
+ }
1361
+
1362
+ private toolIdempotencyKey(
1363
+ options: AgentRuntimeToolExecutionOptions | undefined,
1364
+ context: AgentRuntimeToolCallContext,
1365
+ ): string {
1366
+ const custom = options?.idempotencyKeyForCall?.(context);
1367
+ if (custom !== undefined) {
1368
+ const normalized = optionalText(custom, "agentRuntime.toolExecution.idempotencyKeyForCall");
1369
+ return normalized as string;
1370
+ }
1371
+ const prefix = optionalText(options?.idempotencyKey, "agentRuntime.toolExecution.idempotencyKey")
1372
+ ?? context.invocationId;
1373
+ return `agent:${prefix.length}:${prefix}:${context.call.id.length}:${context.call.id}`;
1374
+ }
1375
+
1376
+ private executorToolOptions(options: AgentRuntimeToolExecutionOptions | undefined): AgentToolExecutionOptions {
1377
+ if (options === undefined) return {};
1378
+ const { idempotencyKey: _prefix, idempotencyKeyForCall: _builder, ...executorOptions } = options;
1379
+ return executorOptions;
1380
+ }
1381
+
1382
+ private inputMessage(input: unknown): AgentMessage {
1383
+ if (typeof input === "string") {
1384
+ return agentMessage("user", input);
1385
+ }
1386
+ return agentMessage("user", agentData(input, { name: "input" }));
1387
+ }
1388
+
1389
+ private toolContracts(agent: AgentDefinition): readonly ReturnType<typeof agentToolContract>[] {
1390
+ return Object.freeze(agent.tools.map(describeTool));
1391
+ }
1392
+
1393
+ private providerOutputContract(output: AgentOutputContract | undefined): AgentOutputContract | undefined {
1394
+ if (output?.schema?.kind !== "class") return output;
1395
+ const schemas = getGeneratedOpenApiMetadata().schemas;
1396
+ const generated = schemas[output.schema.name];
1397
+ if (generated === undefined) return output;
1398
+ return agentOutputContract({ ...output, schema: agentJsonSchema(output.schema.name, inlineGeneratedSchema(generated, schemas), { strict: output.schema.strict }) });
1399
+ }
1400
+
1401
+ private taskOutputContract(task: AgentTaskDefinition): AgentOutputContract | undefined {
1402
+ if (task.metadata.output === undefined) {
1403
+ return undefined;
1404
+ }
1405
+ return agentOutputContract({
1406
+ mode: "json",
1407
+ schema: this.schemaContract(task.metadata.output),
1408
+ });
1409
+ }
1410
+
1411
+ private agentOutputContract(agent: AgentDefinition): AgentOutputContract | undefined {
1412
+ if (agent.metadata.output === undefined) {
1413
+ return undefined;
1414
+ }
1415
+ return agentOutputContract({ mode: "json", schema: this.schemaContract(agent.metadata.output) });
1416
+ }
1417
+
1418
+ private schemaContract(model: NonNullable<ToolDefinition["metadata"]["input"]>) {
1419
+ const name = getGeneratedOpenApiSchemaName(model) ?? classDebugName(model);
1420
+ const schemas = getGeneratedOpenApiMetadata().schemas;
1421
+ const generated = schemas[name];
1422
+ if (generated === undefined) {
1423
+ return agentClassSchema(name);
1424
+ }
1425
+ return agentJsonSchema(name, inlineGeneratedSchema(generated, schemas) as JsonObject);
1426
+ }
1427
+
1428
+ private taskInvocationMetadata(metadata: unknown, task: AgentTaskDefinition): unknown {
1429
+ const taskMetadata = {
1430
+ taskName: task.metadata.name,
1431
+ taskMethodName: task.metadata.methodName,
1432
+ };
1433
+ if (metadata === undefined) {
1434
+ return taskMetadata;
1435
+ }
1436
+ if (metadata !== null && typeof metadata === "object" && !Array.isArray(metadata)) {
1437
+ return { ...(metadata as Record<string, unknown>), ...taskMetadata };
1438
+ }
1439
+ return metadata;
1440
+ }
1441
+
1442
+ private async completeModel(
1443
+ request: AgentModelRequest,
1444
+ agentName: string,
1445
+ modelProfile: string | undefined,
1446
+ metadata: JsonObject,
1447
+ sourceSignal: AbortSignal | undefined,
1448
+ timeoutMs: number | undefined,
1449
+ onTextDelta?: (text: string) => void,
1450
+ ): Promise<{ readonly ok: true; readonly value: AgentModelResponse } | { readonly ok: false; readonly error: AgentToolError }> {
1451
+ const abortController = new AbortController();
1452
+ const detach = attachAbortForwarding(sourceSignal, abortController);
1453
+ let acceptingText = true;
1454
+ const context: AgentModelProviderContext = Object.freeze({
1455
+ invocationId: request.invocationId,
1456
+ agentName,
1457
+ ...(modelProfile !== undefined ? { modelProfile } : {}),
1458
+ metadata,
1459
+ signal: abortController.signal,
1460
+ ...(onTextDelta ? { onTextDelta: (text: string) => {
1461
+ if (!acceptingText || abortController.signal.aborted) return;
1462
+ if (typeof text !== "string") throw new AgentRuntimeError("Model text delta must be a string.");
1463
+ if (text) onTextDelta(text);
1464
+ } } : {}),
1465
+ });
1466
+
1467
+ try {
1468
+ if (abortController.signal.aborted) {
1469
+ throw new AgentRuntimeAbortError();
1470
+ }
1471
+ const rawResponse = await timed(
1472
+ Promise.resolve(this.modelProvider.complete(request, context)),
1473
+ timeoutMs,
1474
+ () => abortController.abort(),
1475
+ abortController.signal,
1476
+ );
1477
+ try {
1478
+ return { ok: true, value: normalizeProviderResponse(rawResponse) };
1479
+ } catch (error) {
1480
+ return {
1481
+ ok: false,
1482
+ error: runtimeError("AGENT_PROVIDER_RESPONSE_INVALID", `Model provider returned an invalid response: ${errorMessageOf(error)}`),
1483
+ };
1484
+ }
1485
+ } catch (error) {
1486
+ const code = error instanceof AgentRuntimeTimeoutError
1487
+ ? "AGENT_PROVIDER_TIMEOUT"
1488
+ : error instanceof AgentRuntimeAbortError
1489
+ ? "AGENT_ABORTED"
1490
+ : "AGENT_PROVIDER_FAILED";
1491
+ return { ok: false, error: runtimeError(code, errorMessageOf(error)) };
1492
+ } finally {
1493
+ acceptingText = false;
1494
+ detach?.();
1495
+ }
1496
+ }
1497
+ }