feat(server): io/agent worker groups, invoke limits for external IO capabilities, loop lag probe
- WORKER_CONCURRENCY / WORKER_AGENT_CONCURRENCY; --role worker (io), worker:agent, all (both) - HTTP invoke of release.search/inspect, identity.resolve, catalog.lookup(remote): 15s timeout + per-upstream semaphore (site 2, TMDB 4) - worker event-loop lag probe: warn + count when drift > 5s Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
fe9693d4ca
commit
473c5e94a5
7 files changed
+399
-19
No files matched your search
@@ -14,6 +14,7 @@ import type { ModuleApp, ServerContext } from "../types.ts";
|
||||
import { planBinding } from "./authorize.ts";
|
||||
import { cancelTask, retryTask, taskToApi } from "./capabilities.ts";
|
||||
import { route } from "./http.ts";
|
||||
import { createInvokeLimiter, type InvokeLimiter, UpstreamBusyError, UpstreamTimeoutError } from "./invoke-limits.ts";
|
||||
import { AgentRunError, abortRun, appendMessage, startRun } from "./service.ts";
|
||||
|
||||
// Agent 会话 API、持续授权 / 单次审批、能力目录与调用、业务任务。
|
||||
@@ -85,7 +86,11 @@ const decode = (c?: string) => {
|
||||
return at && id ? { at, id } : null;
|
||||
};
|
||||
|
||||
export function registerAgentRoutes(app: ModuleApp, ctx: ServerContext) {
|
||||
export function registerAgentRoutes(
|
||||
app: ModuleApp,
|
||||
ctx: ServerContext,
|
||||
limiter: InvokeLimiter = createInvokeLimiter(),
|
||||
) {
|
||||
const db = () => ctx.db;
|
||||
|
||||
// ── Agent 会话 ──
|
||||
@@ -328,13 +333,16 @@ export function registerAgentRoutes(app: ModuleApp, ctx: ServerContext) {
|
||||
if (body.preview && !entry.descriptor.supportsPreview)
|
||||
throw new ApiException("bad_request", `${entry.descriptor.id} 不支持预览`);
|
||||
try {
|
||||
const output = await ctx.capabilities.invoke(params.capabilityId, body.input, {
|
||||
actorId,
|
||||
taskId: `http:${c.get("requestId") ?? "req"}`,
|
||||
scopeIds: [],
|
||||
signal: c.req.raw.signal,
|
||||
source: "web",
|
||||
});
|
||||
// 外部 IO 型能力(站点实时搜索/详情刷新、TMDB):15s 超时 + 按上游限并发
|
||||
const output = await limiter.run(params.capabilityId, body.input, c.req.raw.signal, (signal) =>
|
||||
ctx.capabilities.invoke(params.capabilityId, body.input, {
|
||||
actorId,
|
||||
taskId: `http:${c.get("requestId") ?? "req"}`,
|
||||
scopeIds: [],
|
||||
signal: signal ?? c.req.raw.signal,
|
||||
source: "web",
|
||||
}),
|
||||
);
|
||||
const o = (output ?? {}) as { taskId?: unknown; planId?: unknown; plan?: { id?: unknown } | null };
|
||||
return {
|
||||
output,
|
||||
@@ -499,6 +507,8 @@ export function registerAgentRoutes(app: ModuleApp, ctx: ServerContext) {
|
||||
|
||||
/** 能力错误 → HTTP 错误码 */
|
||||
function capabilityHttpError(err: unknown): never {
|
||||
if (err instanceof UpstreamBusyError) throw new ApiException("rate_limited", err.message);
|
||||
if (err instanceof UpstreamTimeoutError) throw new ApiException("upstream_unavailable", err.message);
|
||||
if (!isCapabilityError(err)) throw err;
|
||||
const code =
|
||||
err.code === "unauthorized"
|
||||
|
||||
Reference in new issue
Block a user