ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Electric Agents RuntimeHandler 深度指南:Webhook 唤醒路由、类型注册与部署配置

Electric Agents RuntimeHandler 深度指南:Webhook 唤醒路由、类型注册与部署配置 Electric Agents RuntimeHandler 深度指南Webhook 唤醒路由、类型注册与部署配置【免费下载链接】electricThe agent platform built on sync.项目地址: https://gitcode.com/GitHub_Trending/el/electricRuntimeHandler是electric-ax/agents-runtime包面向宿主应用暴露的运行时入口工厂它创建一个负责接收 Electric Agents runtime server 发来的 webhook 唤醒请求的路由器并在启动时自动注册所有实体类型。本文结合该包的 API 参考文档与仓库源码完整讲解RuntimeRouter/RuntimeHandler的接口契约、RuntimeRouterConfig全部配置项、webhook 签名校验、唤醒生命周期管理以及如何接入 Node HTTP 服务。读完本文你将掌握如何用createRuntimeHandler搭建一个可被 Electric Agents 平台唤醒的实体运行时、如何理解并配置每个关键参数serveEndpoint、webhookSignature、idleTimeout、sandboxProfiles等、以及如何正确地进行优雅关闭与错误处理。本文对应的官方 API 参考文档位于 website/docs/agents/reference/runtime-handler.md源码实现位于 packages/agents-runtime/src/create-handler.ts。一、RuntimeHandler 在 Electric Agents 架构中的角色在 Electric Agents 的运行时模型中每个实体entity拥有一条 append-only 事件流。当服务端决定唤醒一个实体时它通过 webhook 将唤醒通知投递给实体所在的宿主进程宿主进程中的RuntimeHandler就是这个 webhook 的接收与分发入口。根据源码注释create-handler.ts的定位说明create-handler.ts提供Runtime router factory—— 创建一个 fetch 原生的请求路由器负责 webhook 唤醒投递兼容的 Node HTTP 适配器—— 将 Node 的IncomingMessage/ServerResponse桥接为 fetchRequest/Response。工厂函数返回的对象承担两类职责webhook 唤醒投递接收 Electric Agents runtime server 发来的唤醒通知WakeNotification/WebhookNotification解码、验签、查找到对应实体类型后在后台异步执行该实体的 handler启动时类型注册将defineEntity注册的所有实体类型以 upsert 语义批量注册到服务端/_electric/entity-types使平台知晓该宿主进程可承载哪些实体。在electric-ax/agents-runtime的 README 中createRuntimeHandler()被描述为Electric Agents 在实体被唤醒时调用的 webhook 入口README.md足见其在运行时中的枢纽地位。二、RuntimeRouter核心接口契约RuntimeRouter是运行时路由器的抽象接口RuntimeHandler在其基础上扩展了 Node HTTP 适配能力。两者均由 create-handler.ts 定义并从包入口导出index.ts。interface RuntimeRouter { handleRequest(request: Request): PromiseResponse | null handleWebhookRequest(request: Request): PromiseResponse dispatchWake( notification: WakeNotification, options?: PickProcessWakeConfig, claimHeaders | claimTokenHeader ): void dispatchWebhookWake(notification: WebhookNotification): void drainWakes(): Promisevoid waitForSettled(): Promisevoid abortWakes(): void debugState(): RuntimeDebugState readonly typeNames: string[] readonly sandboxProfileDescriptors: Array{ name: string label: string description?: string remote?: boolean } registerTypes(): Promisevoid }各方法的职责与调用链如下方法返回类型说明handleRequest(request)PromiseResponse \| null路由 fetchRequest。若请求路径与webhookPath不匹配则返回null否则委托给handleWebhookRequesthandleWebhookRequest(request)PromiseResponse直接处理 webhook 请求不做路径匹配dispatchWake(notification, opts?)void从任意传输通道分发一个已解析的唤醒通知dispatchWebhookWake(notification)void分发已解析的 webhook 通知在后台运行唤醒 handlerdrainWakes()Promisevoid等待所有在途唤醒 handler 收敛若任一唤醒出错则抛出异常waitForSettled()Promisevoid等待所有在途唤醒 handler 收敛drainWakes的友好别名abortWakes()void中止在途唤醒使宿主进程可以快速关闭debugState()RuntimeDebugState返回运行时本地快照用于测试与关闭诊断typeNamesstring[]所有已注册实体类型的名称只读sandboxProfileDescriptorsArray{name, label, description?, remote?}本运行时对外发布的 sandbox 沙箱配置档的线格式描述只读registerTypes()Promisevoid将所有实体类型注册到 Electric Agents runtime server采用 upsert 语义每次启动均可安全调用注意源码中的RuntimeRouter接口还包含一个文档未列出的isWakeActive(streamPath): boolean方法用于判断某个流路径的唤醒是否已在途create-handler.ts可视为内部诊断能力。2.1 请求处理流程handleWebhookRequest 内部逻辑从 create-handler.ts 可以看到handleWebhookRequest的完整处理管线方法校验非POST请求直接返回405 Method not allowed签名校验若启用了webhookSignature读取请求头webhook-signature用verifyWebhookSignature校验签名失败时返回相应错误与状态码JSON 解析将请求体解码为WebhookNotification解析失败返回400 Invalid JSON实体类型查找从通知中取entity.type通过注册表或模块级注册表查找实体类型未找到返回503 Unknown entity type分发执行dispatchWebhookWake(notification)在后台执行唤醒立即返回200 { ok: true }。2.2 路径路由handleRequestconst handleRequest async (request: Request): PromiseResponse | null { const pathname new URL(request.url).pathname if (pathname ! webhookPath) return null return handleWebhookRequest(request) }handleRequest仅做 URL pathname 比对命中webhookPath才继续处理否则返回null交给上层框架继续路由create-handler.ts。2.3 唤醒生命周期管理dispatchWake的实现create-handler.ts揭示了唤醒后台执行的关键细节每次唤醒创建一个AbortController作为关闭信号调用processWake(notification, {...wakeConfig, shutdownSignal})唤醒 Promise 被登记到pendingWakes集合同时以streamPath作为 label 记录用于isWakeActive与诊断唤醒失败时优先调用config.onWakeError?.(error)观察器只有返回true表示已处理才不会把错误收集进wakeErrors数组未处理错误会记录日志并在drainWakes时重新抛出唤醒结束无论成败都会从三个登记结构中移除。drainWakescreate-handler.ts循环等待pendingWakes全部清空之后若wakeErrors非空则抛出一个错误或AggregateErrorabortWakes遍历所有AbortController触发中止debugState返回RuntimeDebugState快照。三、RuntimeHandlerNode HTTP 适配器interface RuntimeHandler extends RuntimeRouter { onEnter(req: IncomingMessage, res: ServerResponse): Promisevoid }onEnter是 Node HTTP 兼容适配器用于将传统 Nodehttp.createServer回调桥接到 fetch 世界方法参数说明onEnter(req, res)NodeIncomingMessage、ServerResponse将请求转换为 fetchRequest并委托给handleWebhookRequest从源码实现看create-handler.tscreateRuntimeHandler内部先创建createRuntimeRouter(config)再包装出onEntertoFetchRequest(req)读取请求体、合并 headers、构造Request若读取失败返回400 Request body read failed调用router.handleWebhookRequest(request)sendNodeResponse(res, response)将 fetchResponse的 status/headers/body 写回ServerResponse。const onEnter async (req, res) { let request: Request try { request await toFetchRequest(req) } catch (err) { await sendNodeResponse(res, json({ error: Request body read failed, details: ... }, 400)) return } const response await router.handleWebhookRequest(request) await sendNodeResponse(res, response) }toFetchRequest将 Node 的多个同名 header 追加为 fetch Headers 的多个值URL 基于req.headers.host与req.url构造body 非空时以Buffer传入create-handler.ts。3.1 实战接线接入 Node HTTP 服务器结合仓库示例 examples/agents-playground/server.ts 与 examples/agents-chat-starter/src/server/index.ts一个典型的宿主接线如下import http from node:http import { createRuntimeHandler } from electric-ax/agents-runtime const runtime createRuntimeHandler({ baseUrl: http://localhost:4437, // Electric Agents runtime server serveEndpoint: http://localhost:3000/webhook, // 对外可访问的回调地址 }) const server http.createServer(async (req, res) { if (req.url /webhook req.method POST) { await runtime.onEnter(req, res) return } res.writeHead(404) res.end() }) server.listen(3000, async () { await runtime.registerTypes() // 启动时注册所有实体类型 console.log(App server ready on port 3000) })onEnter适合传统 Node HTTP 服务如果宿主框架本身基于 fetch如 Bun、Deno、Hono 适配层则应优先使用handleRequest(request)源码注释明确建议新集成优先使用 fetch 原生入口见 create-handler.ts。四、RuntimeDebugState关闭与测试诊断快照interface RuntimeDebugState { pendingWakeCount: number pendingWakeLabels: string[] wakeErrorCount: number typeNames: string[] }字段类型说明pendingWakeCountnumber在途唤醒 handler 数量pendingWakeLabelsstring[]标识每个待处理唤醒的标签用于诊断wakeErrorCountnumber已出错的唤醒 handler 数量typeNamesstring[]所有已注册实体类型的名称debugState()由源码中的内部状态直接映射而来pendingWakeCount即pendingWakes.sizependingWakeLabels即标签 Map 的值集合wakeErrorCount即wakeErrors.lengthtypeNames来自getRegisteredTypes()create-handler.ts。该快照是判断宿主是否可以安全退出的重要依据。五、工厂函数function createRuntimeRouter(config: RuntimeRouterConfig): RuntimeRouter function createRuntimeHandler(config: RuntimeHandlerConfig): RuntimeHandlercreateRuntimeRouter创建纯 fetch 路由器含请求处理、唤醒分发、类型注册createRuntimeHandler在其之上叠加 Node HTTP 适配器onEnterRuntimeHandlerConfig与RuntimeRouterConfig是同一类型export type RuntimeHandlerConfig RuntimeRouterConfig见 create-handler.ts两个工厂接受完全相同的配置对象。六、RuntimeRouterConfig 全部配置项详解配置接口完整定义见 create-handler.ts与文档 API 参考一致。以下为全部字段的默认值与语义字段类型默认值说明baseUrlstring-必填Electric Agents runtime server 的基地址如http://localhost:4437serveEndpointstring-你的应用对外暴露的完整 webhook 回调 URL用于类型注册webhookPathstringserveEndpoint/handlerUrl的 pathname兜底/electric-agentshandleRequest()匹配的路径handlerUrlstring-serveEndpoint的向后兼容别名新代码请优先用serveEndpointregistryEntityRegistry模块级默认注册表本 handler 使用的实体注册表subscriptionPathForType(typeName: string) string-覆盖每个实体类型注册时的 webhook 订阅路径defaultDispatchPolicyForType(typeName: string) DispatchPolicy \| undefined-覆盖每个实体类型注册的默认分发策略serverHeadersHeadersProvider-发送给 agents server 控制面请求类型注册、唤醒认领的附加请求头webhookSignaturefalse \| PartialWebhookSignatureVerifierConfig默认启用JWKS 地址为${baseUrl}/__ds/jwks.jsonwebhook 签名校验配置仅在可信进程内测试时设为falseidleTimeoutnumber20000关闭一次唤醒前的空闲超时毫秒heartbeatIntervalnumber10000心跳间隔毫秒createElectricTools(context) AgentTool[] \| Promise...-可选工具工厂在每次唤醒执行 handler 前调用为 agent 注入额外工具onWakeError(error: Error) boolean \| void-后台唤醒失败的观察器返回true表示错误已处理不会在 drain 时重新抛出registrationConcurrencynumber8实体类型注册的最大并发数sandboxProfilesReadonlyArraySandboxProfile-本运行时发布的命名沙箱配置档spawn 请求可按 profile 名称选择publicUrlstring-本运行时的公网 URL转发给 agents server 用于GET /api/runtimesnamestringdefault运行时可读名称用于运行时元数据去重6.1 baseUrl 与 serveEndpoint必填的两个端点baseUrl指向Electric Agents runtime serverDurable Streams 服务端控制面调用类型注册/_electric/entity-types、JWKS 拉取、唤醒认领都基于它拼接 URL参见appendPathToUrl(baseUrl, /_electric/entity-types)create-handler.ts。serveEndpoint是你自己的宿主应用对外可达的 webhook 回调地址。类型注册时它被写入注册体的serve_endpoint字段并在未显式提供default_dispatch_policy时自动生成指向该地址的 webhook 分发策略create-handler.ts。webhookPath的推导逻辑位于normalizeConfigcreate-handler.tsconst serveEndpoint config.serveEndpoint ?? config.handlerUrl const webhookPath config.webhookPath ?? getPathname(serveEndpoint) ?? /electric-agents即优先取显式webhookPath其次取serveEndpoint或handlerUrl的 pathname最后兜底/electric-agents。6.2 webhookSignature默认启用的签名校验webhookSignature在normalizeConfig中被归一化create-handler.tsconst webhookSignature config.webhookSignature false ? false : { jwksUrl: config.webhookSignature?.jwksUrl ?? appendPathToUrl(config.baseUrl, /__ds/jwks.json), toleranceSeconds: config.webhookSignature?.toleranceSeconds, cacheTtlMs: config.webhookSignature?.cacheTtlMs, fetchClient: config.webhookSignature?.fetchClient, }要点默认从${baseUrl}/__ds/jwks.json拉取 JWKS 公钥集无需手动配置即可启用签名校验校验发生在请求头webhook-signature格式为ttimestamp,kidkid,ed25519signature可从测试用例 create-handler.test.ts 看到构造方式可覆盖jwksUrl、toleranceSeconds时间容差秒、cacheTtlMsJWKS 缓存 TTL、fetchClient仅当运行可信的进程内测试时才设为false生产环境务必保持默认启用。仓库测试 create-handler.test.ts 会先clearRegistry()再 mockprocessWake并构造带 Ed25519 签名的 webhook 请求验证验签与分发链路是理解该配置行为的可执行范例。6.3 idleTimeout 与 heartbeatInterval唤醒生命周期控制idleTimeout默认20_000ms在关闭一次唤醒wake前允许的空闲时间上限heartbeatInterval默认10_000ms向服务端发送心跳的间隔。两者通过wakeConfig传入processWakecreate-handler.ts共同决定一次实体唤醒的执行时限与保活节奏。6.4 createElectricTools为每次唤醒注入额外工具createElectricTools是一个可选工具工厂签名接收每次唤醒的上下文返回AgentTool[]createElectricTools?: (context: { entityUrl: string entityType: string args: ReadonlyRecordstring, unknown db: EntityStreamDBWithActions events: ArrayChangeEvent upsertCronSchedule(opts: { id: string; expression: string; timezone?: string payload?: unknown; debounceMs?: number; timeoutMs?: number }): Promise{ txid: string } upsertFutureSendSchedule(opts: { id: string; payload: unknown; targetUrl?: string fireAt: string; messageType?: string }): Promise{ txid: string } deleteSchedule(opts: { id: string }): Promise{ txid: string } listWebhookSources(): PromiseArrayWebhookSourceContract subscribeToWebhookSource(opts: WebhookSourceSubscriptionInput) : Promise{ txid: string; subscription: WebhookSourceSubscription } unsubscribeFromWebhookSource(opts: { id: string }): Promise{ txid: string } }) AgentTool[] | PromiseAgentTool[]上下文提供了实体 URL/类型、spawn 参数、实体 StreamDB含操作、本次唤醒触发的事件列表以及定时任务cron/future send和 webhook source 订阅管理能力。在 examples/agents-playground/server.ts 中可以看到通过createElectricTools注入自定义工具集合的用法。6.5 onWakeError后台唤醒错误观察器onWakeError?: (error: Error) boolean | void调用时机在dispatchWake的 catch 分支若返回true表示该错误已被上层处理不会进入wakeErrors收集列表因此drainWakes()不会因它抛错否则错误会记录日志并被drainWakes重新抛出。这为宿主提供了吞掉已知可恢复错误 vs 让关闭流程感知错误的精确控制create-handler.ts。6.6 registrationConcurrency类型注册并发控制默认8。registerTypes()使用一个简单的 worker 池实现并发注册forEachWithConcurrency见 create-handler.ts并发度取Math.max(1, Math.min(concurrency, items.length))。宿主进程拥有大量实体类型时可通过此参数控制注册请求对服务端的瞬时压力。6.7 sandboxProfiles、publicUrl 与 name运行时元数据sandboxProfiles注册到本运行时的命名沙箱配置档。每个 profile 是(name, label, description?, factory)元组——factory 闭包只保存在运行时本地仅有描述性字段通过sandboxProfileDescriptors广告给 agents server 并呈现在 UI 选择器中spawn 负载通过sandbox.profile指定服务端会按目标 runner 广告的集合校验。重复的 profile 名称会在createRuntimeRouter时直接抛错fail-fast见 create-handler.tspublicUrl运行时公网 URL转发给 agents server 后可出现在GET /api/runtimes的公共运行时列表中省略则该运行时被排除在公共列表之外name默认default作为/api/runtimes去重键last-write-wins同名多实例注册时后者覆盖前者。七、registerTypes 的类型注册机制registerTypes()是启动流程的关键一步。从源码create-handler.ts看通过注册表registry ?? 模块级默认注册表枚举所有实体类型以registrationConcurrency并发向${baseUrl}/_electric/entity-types发送POST每个注册体由buildEntityTypeRegistrationBody构造create-handler.ts包含name、description、可选的creation_schema/inbox_schemas/slash_commands、合并了DEFAULT_STATE_SCHEMAS的state_schemas、externally_writable_collections、permission_grants以及serve_endpoint与default_dispatch_policyserveEndpoint存在时写入serve_endpointdefaultDispatchPolicyForType有返回则优先使用否则自动生成指向serveEndpoint的 webhook 分发策略subscription_id为webhook:typeName特殊字符会被替换为_见runtimeWebhookSubscriptionIdcreate-handler.ts任一类型注册失败网络错误或非 2xx最终抛出汇总错误registered.length/total registered (n failed: ...)由于采用 upsert 语义每次启动重复调用是安全的——文档与 README 都强调这是推荐的启动惯例。Schema 序列化方面toJsonSchemacreate-handler.ts依次尝试 Standard Schema 的~standard.jsonSchema.input()、自定义toJSONSchema()、JSON Schema 关键字检测最后兜底用zod-to-json-schema转换确保 Zod 等 schema 库都能被转成注册所需的 JSON Schema。八、部署配置与优雅关闭实践综合以上配置项一个面向生产的最小配置示例const runtime createRuntimeHandler({ baseUrl: http://electric-agents:4437, serveEndpoint: https://agent-host.example.com/webhook, // webhookSignature: 默认启用自动使用 ${baseUrl}/__ds/jwks.json idleTimeout: 20_000, heartbeatInterval: 10_000, registrationConcurrency: 8, serverHeaders: async () ({ authorization: Bearer ${process.env.AGENTS_SERVER_TOKEN}, }), onWakeError: (err) { // 记录并吞掉预期内的可恢复错误避免 drainWakes 抛错 return true }, name: web-1, // 多实例部署时用于 /api/runtimes 去重 publicUrl: https://agent-host.example.com, }) await runtime.registerTypes()优雅关闭建议按以下顺序执行停止接收新请求从负载均衡器摘除、server.close()await runtime.drainWakes()等待所有在途唤醒收敛——若某个唤醒失败且未被onWakeError标记为已处理这里会抛出Error/AggregateError应记录为关闭诊断信息若需要在有限时间内强制退出可调用runtime.abortWakes()中止在途唤醒通过runtime.debugState()输出pendingWakeCount/wakeErrorCount等快照便于排查为何关不掉。注意区分三个等待/中止方法drainWakes()会因错误抛异常waitForSettled()是其友好别名同样会抛错源码实现即await drainWakes()见 create-handler.tsabortWakes()则主动触发 AbortController 中断在途唤醒以加速关闭。九、测试验证与进一步探索仓库为createRuntimeHandler/createRuntimeRouter提供了完整测试套件packages/agents-runtime/test/create-handler.test.ts覆盖 webhook 签名构造与验签、onEnter请求桥接、错误请求如连接重置导致的400、注册与唤醒分发等场景packages/agents-runtime/test/runtime-dsl.ts集成测试 DSL可运行完整的运行时流程packages/agents-runtime/test/sandbox-profiles.test.ts验证 sandbox profile 的重复名检测与描述符发布。可运行的完整宿主示例examples/agents-playground/server.tscreateEntityRegistrycreateRuntimeHandlercreateElectricTools的组合范例examples/agents-chat-starter/src/server/index.ts聊天类实体宿主的完整接线examples/agents-walkthrough/src/index.ts从零到一的渐进式运行时搭建。若需绕过 webhook 而使用拉取式唤醒pull-based wake可查看包内导出的 createPullWakeRunnerwebhook 验签的底层实现位于packages/agents-runtime/src/webhook-signature.ts。两者与RuntimeHandler共同构成了electric-ax/agents-runtime的完整唤醒接收体系。【免费下载链接】electricThe agent platform built on sync.项目地址: https://gitcode.com/GitHub_Trending/el/electric创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表