@agentium/transport

中文文档
4.11.0发布于 2026/10/24MITTypeScriptESM + CJS零依赖近 30 天下载 1854

HTTP and WebSocket transport layer for Agentium agents

原始使用文档
文档目录12 节
  1. Install
  2. Quick Start
  3. Features
  4. Documentation
  5. Community
  6. License
  7. Authenticated HTTP hosting
  8. Text gateway security and connection ownership
  9. Voice gateway acknowledgement migration
  10. A2A 1.0 and legacy migration
  11. Durable task control and event replay
  12. Durable A2A and MCP Tasks bridges

@agentium/transport

HTTP and WebSocket transport layer for deploying Agentium agents as APIs.

Install

npm install @agentium/transport

Quick Start

import express from "express";
import { Agent, openai } from "@agentium/core";
import { createAgentRouter } from "@agentium/transport";

const app = express();
app.use(express.json());

const agent = new Agent({
  name: "assistant",
  model: openai("gpt-4o"),
});

app.use("/api", createAgentRouter({ security: { mode: "local" }, agents: { assistant: agent } }));
app.listen(3000);

Features

  • Auto-Discovery — Reads from the global Registry at request time; agents created after server start are immediately available
  • Express Router — REST API with streaming support and list endpoints (GET /agents, /teams, /workflows, /tools)
  • Socket.IO Gateway — Real-time WebSocket communication with dynamic agent/team lookup and tool discovery
  • A2A Server — Agent-to-Agent protocol support
  • CORS & Rate Limiting — Built-in security middleware
  • Swagger — Auto-generated API documentation
  • File Upload — Multipart form data support

Documentation

Full docs at docs.agentium.in

Community

Join the conversation on Discord.

License

MIT

Authenticated HTTP hosting

createAgentRouter now requires an explicit identity resolver and resource authorizer whenever JWT or RBAC is configured. Scope checks alone do not establish session, checkpoint, or approval ownership. Authenticated configuration missing either hook throws during router creation.

app.use("/api", createAgentRouter({
  agents: { assistant: agent },
  registry: false,
  jwt: { secret: process.env.JWT_SECRET! },
  rbac: {},
  security: {
    mode: "authenticated",
    resolveIdentity: (claims) => {
      const verified = claims as { sub?: string; tenant?: string };
      return verified.sub
        ? { userId: verified.sub, tenantId: verified.tenant }
        : null;
    },
    authorizeResource: async ({ identity, operation, resource }) => {
      // Application-owned implementation; use authoritative records and default-deny.
      // session:create must atomically bind this new ID before resolving true.
      return ownership.authorizeAndBind({ identity, operation, resource });
    },
  },
}));

The ownership service above is an application dependency, not a provided in-memory store. It must return false for unknown or unmigrated ownerless records. Do not infer ownership from a request body, checkpoint contents, or possession of an ID. Store session IDs globally uniquely and check both the intended actor and tenant according to your application's policy. For new executions, the router generates a UUID and waits for session:create to persist its owner binding; failure prevents Agent/Team/Workflow execution. A supplied session ID requires session:use and cannot implicitly claim an existing or unknown session. The selected ID is returned in X-Agentium-Session-Id, including for streaming requests.

Host authentication middleware in middleware runs before JWT/RBAC and may populate req.user from credentials it verifies itself. resolveIdentity receives only that verified value. Authenticated body userId/tenantId values must match the resolved identity if supplied; execution and correction handlers use the resolved values. Multipart run requests perform identity and ownership checks after parsing their fields and before Agent execution. Do not configure middleware that copies unverified request claims into req.user.

The resource authorizer receives these operations:

OperationResource and required host decision
session:create, session:useSession ID and agent/team/workflow name; atomically bind a new ID or verify existing ownership.
run:use, checkpoints:listRun ID and agent name; verify ownership before correction association or checkpoint listing.
checkpoint:restoreCheckpoint ID and agent name; verify authoritative ownership before rollback.
approval:read, approval:approve, approval:denyRequest ID; verify ownership. Pending lists and SSE events are filtered individually.
correction:createAgent name and requested scope; authorize correction visibility. Referenced run/session IDs are checked separately.
schedules:listEntire schedule collection; allow only callers entitled to see all returned schedules.
schedule:create, schedule:deleteSchedule ID; authorize creation or deletion. Creation grants management authority for that ID, including replacement and all configured scheduler targets.
admin:get, admin:post, admin:put, admin:patch, admin:deleteFull admin path; authorize administration at that path.

Do not grant collection/admin/scheduler management operations to users needing only per-item or restricted-target access; use a dedicated host endpoint until those APIs offer narrower contracts. Successful scope checks, including admin:*, never bypass resource authorization. This hook does not migrate the underlying storage to a multi-tenant schema.

RBAC now explicitly covers approvals, corrections, checkpoints/rollback, schedules, metrics, tool listings, discovery and nested admin routes. Unknown routes return 403, including for administrators, until registered in rbac.defaultScopes. An explicit empty scope array means "any authenticated identity". rbac.agentScopes applies before Express route parameters are populated. Optional rbac.publicRoutes, such as ["GET /agents"], permits intentionally public listings or documentation. Resource control routes still require verified identity/ownership. Swagger paths need an explicit public route or a defaultScopes entry when RBAC is enabled.

Every router now requires an explicit security option. For a trusted local application, use security: { mode: "local" }. For hosted use, select mode: "authenticated" and provide both identity and resource authorization hooks. Omitting security or choosing an unknown mode fails before discovery, middleware setup, or optional dependency loading. Local mode cannot be combined with JWT/RBAC; configuration never silently downgrades authentication. The text Socket.IO gateway has the explicit contract below. Standalone admin routers and A2A servers retain their own deployment authorization.

Team and Workflow HTTP routes enforce session ownership before calling their runtime. Their internal Agent delegation now carries tenant/user/run lineage, cancellation and execution policy. Custom workflow callbacks remain trusted host code; route authorization does not sandbox them.

Text gateway security and connection ownership

createAgentGateway also requires security: { mode: "local" } for trusted local usage. authMiddleware requires authenticated mode; it cannot silently select a local gateway. For hosted Socket.IO, middleware verifies credentials and stores trusted state in socket.data. Middleware must call next; synchronous throws and returned promise rejections deny access with a generic error. Admission waits for any returned promise to settle, and duplicate next calls cannot admit twice. The gateway re-resolves identity and calls the host authorizer for every run, cancellation, discovery or tool lookup:

createAgentGateway({
  io,
  registry: false,
  agents: { assistant: agent },
  authMiddleware: verifySocketCredentials, // host function populating socket.data
  security: {
    mode: "authenticated",
    resolveIdentity: (verifiedState) => identityFromVerifiedState(verifiedState),
    authorizeResource: ({ identity, operation, resource }) =>
      authorizeSocketResource(identity, operation, resource),
  },
  maxConcurrentRuns: 4,
  maxOutputBytes: 256 * 1024,
  textStream: { maxFrameBytes: 256 * 1024, maxBufferedBytes: 256 * 1024, writeTimeoutMs: 10_000 },
});

authorizeResource must return exactly true to allow a resource. execute checks the named Agent, Team or Workflow. session:create must atomically bind the server-generated opaque session ID to the verified actor/tenant before returning; session:use must reject unknown, ownerless or other-tenant IDs. ID possession conveys no authority. Discovery calls discover separately for each named Agent, Team, Workflow or tool and omits denied entries. run:cancel applies after the gateway checks that the run belongs to this socket and its current verified actor. Never derive this policy from a client room or client identity claim.

Authenticated run payloads reject userId, tenantId, runId, room and apiKey. Handshake keys are not forwarded to providers in authenticated mode. Credentials come from host-configured runtime/provider objects. Client sessionId is only an ownership-checked reference. Local mode retains per-run API keys; new sessions are generated rather than using socket IDs.

Existing agent.run, team.run, agent.chunk, agent.tool.call, agent.tool.done, agent.done and agent.error names remain. workflow.run is available for workflows supplied through serve or the registry. Every admitted execution receives a generated runId; run events include runId and, after ownership binding, sessionId. The additive agent.started event supplies both IDs before runtime work starts. Concurrent clients must correlate events by runId. Send run.cancel with { runId }; its acknowledgement is cancellation_requested, and an error terminal is emitted only after runtime/iterator cleanup settles.

Ordinary text HTTP and socket runs are connection-owned. Disconnect aborts their signal, initiates iterator return, and prevents late results. Agent/Team SSE uses one shared writer, waits for Node drain before pulling the next chunk, bounds individual encoded frames and queued bytes (256 KiB each by default), and applies a 10-second drain deadline. Socket output is serialized per connection, with the same configurable bounds and Engine.IO transport readiness; final collected Agent text has its own byte cap. Slow or oversized output cancels production; if a bounded terminal cannot be delivered, the connection closes. Configure the Socket.IO server's maxHttpBufferSize, HTTP body limits and deployment connection/time limits separately.

Cancellation is cooperative: arbitrary host callbacks cannot be force-killed, and disconnect does not undo effects. Cleanup promises are observed; no terminal success is published while owned work is unresolved. Durable task watchers retain their separate persisted lifetime. The in-memory SSEEventLog only provides process-local replay and does not persist execution; multiline strings are encoded as separate SSE data lines and event names reject line injection.

Multipart uploads bound file count/size plus text field count/size (maxFields: 32, maxFieldSize: 64 KiB defaults). The selected patched Multer peer is required even when only local fixtures are used; transport limits do not repair a vulnerable installed parser. Aborted and malformed upload tests use small local requests and assert completion, bounded limits and released file buffers.

Voice gateway acknowledgement migration

Voice gateways now reserve pending connections, cancel disconnected setup, and bound queued output. Auth middleware establishes identity in socket.data.auth; client user/session/key overrides are ignored when authentication is enabled. The client must acknowledge voice.audio sequence numbers through voice.playback.ack, clear playback on voice.clear, and send voice.playback.complete only after a generation has actually played. Defaults are 256 KiB per frame, 1 MiB pending output, and a 10-second acknowledgement deadline. Missing acknowledgements terminate the session rather than growing buffers. See the voice guide for the event contract, format negotiation and playback-confirmed history.

A2A 1.0 and legacy migration

Install the optional @a2a-js/sdk peer (tested with 1.3.0). createA2AV1Server uses A2A1.0 JSON-RPC and /.well-known/agent-card.json; A2AV1Client is exported by core. The older createA2AServer / A2ARemoteAgent implementation remains available. Use createA2AServer for its server export; the redundant server alias has been removed. The client also has the explicit A2ALegacyRemoteAgent name. Mount the legacy endpoint separately during migration.

import { createA2AV1Server } from "@agentium/transport";

await createA2AV1Server(app, {
  agents: { assistant },
  url: "https://agents.example/rpc",
  audience: "agentium-service",
  authenticate: async (request, audience) => {
    // Host verifier validates signature, issuer, expiry and this audience.
    const claims = await verifyAccessToken(request.headers.authorization, audience);
    return claims ? { tenantId: claims.tenantId, userId: claims.subject } : null;
  },
  maxTasks: 10_000,
  maxHistoryMessages: 128,
});

Verified tenant and actor own tasks. Body tenant overrides cannot change that identity. Text, structured JSON and PNG/JPEG/WebP raw bytes or HTTP(S) image references are accepted. Inline image URLs should use the raw-byte part instead; local paths and other URL schemes are rejected. The host remains responsible for remote media access policy in its model adapter. A structured Agent result becomes a typed artifact. completionState maps domain-specific results to input-required or authentication-required interruptions.

Cancellation waits for owned Agent work to settle before reporting canceled; late success cannot overwrite it. A non-cooperative callback may delay acknowledgment. Capacity is enforced before task admission and in the backing store, with bounded history and one active writer per identity/session. Exhaustion rejects new work; retention is process-local and is reset on restart, with no durable recovery claim.

The client restricts credential-bearing discovery/requests to the configured origin, rejects redirects and supports per-call abort while sharing discovery. Paid providers are not required for the protocol conformance tests. Legacy clients propagate cancellation and close SSE readers on early exit; legacy streaming servers abort work on disconnect, bound outgoing buffering, and cap process-local tasks with maxTasks. Failed Agent outputs stay failed. Legacy authentication and task-owner isolation remain host middleware responsibilities; use the 1.0 adapter for built-in verified ownership.

Durable task control and event replay

createDurableTaskRouter({supervisor, records, authenticate, authorize, wake}) serves already-admitted durable tasks. Mount it under an application-owned prefix. The supervisor and record service must share the same JournaledDurableTaskStore instance. Host authentication supplies tenant/actor identity, and authorization rechecks current grants on every request. These routes return 404 for inaccessible tasks and keep inputs, action arguments, internal failure text and blob keys private.

  • GET /:taskId returns task ID, state, revision and update timestamp.
  • POST /:taskId/cancel persists cancellation, then invokes the host wake callback. Its 202 response reports the current state and deliveryPending if delivery failed. Retry wake through host recovery; cancellation is acknowledged only after reconciliation/settlement.
  • GET /:taskId/events returns one bounded SSE replay batch and closes. Reconnect with Last-Event-ID; malformed cursors return 400, retention/future-cursor gaps return 409 with retained bounds. Authentication and policy are checked again on reconnect. Event data is intended for the owning actor; apply any required content redaction before appending it.

The router is an Agentium control API, separate from the named A2A/MCP wire adapters. It does not claim that an existing process-local protocol server becomes restart-safe when mounted beside it.

Durable A2A and MCP Tasks bridges

createDurableA2AV1Server and createDurableMCPTaskHandler are opt-in adapters over the same durable supervisor. They do not use the ordinary A2A server's process-local task store. Install the optional peers @a2a-js/sdk (tested at 1.3.0) and/or @modelcontextprotocol/server (tested at 2.3.0). Construction dynamically loads only the selected SDK; importing the package does not connect to a database or protocol server.

Both adapters require a DurableProtocolHost: supervisor, admit, authorize, and wake. Authentication additionally verifies credentials for an explicit audience and returns {tenantId, actorId}. Every task lookup checks both fields and current host policy. authorize receives read, cancel, input, or wake; missing callbacks fail construction. Protocol metadata never supplies identity, policy revisions, grants, manifests, or driver registrations.

import { DurableActionLedger } from "@agentium/core";
import {
  createDurableA2AV1Server,
  createDurableMCPTaskHandler,
  type DurableProtocolHost,
} from "@agentium/transport";

const host: DurableProtocolHost = {
  supervisor,
  async admit(identity, payload) {
    // Application service: validate current policy, select registered driver,
    // bind identity/manifest/input/budget/grant refs, and persist atomically.
    // For retries, deduplicate A2A messageId and any application idempotency key.
    return admission.persist(identity, payload);
  },
  authorize: (identity, task, operation) => policy.authorize(identity, task, operation),
  wake: (key) => durableQueue.wake(key),
  async respond(identity, task, response) {
    // Your human-consent service must reject automated/model-originated approval.
    await consent.verify(identity, task, response);
    await DurableActionLedger.decide(supervisor.store,
      { tenantId: identity.tenantId, taskId: task.id },
      { ...response, actorId: identity.actorId });
  },
  // Only public text/JSON leaves the host. Resolve artifact references with
  // DurableRunRecords and the same verified identity before projecting output.
  output: (identity, task) => publicResults.read(identity, task),
};

app.use(await createDurableA2AV1Server({
  ...host,
  name: "assistant",
  url: "https://agents.example/rpc",
  audience: "agentium-service",
  authenticate: (request, audience) => auth.verify(request.headers.authorization, audience),
}));

const mcp = await createDurableMCPTaskHandler({
  ...host,
  name: "assistant",
  audience: "agentium-service",
  authenticate: (request, audience) => auth.verify(request.headers.get("authorization"), audience),
  tools: [{ name: "research", inputSchema: {
    type: "object", properties: { query: { type: "string" } },
    required: ["query"], additionalProperties: false,
  } }],
});
// Mount mcp.fetch(request) using your runtime's web-standard Request/Response adapter.
// On shutdown: await mcp.close().

admission, policy, consent, auth, publicResults, and durableQueue above are host services, not implicit Agentium globals. Admission must complete persistence before returning {tenantId, taskId}. The bridge verifies that record's owner before responding and separately authorizes wake delivery. A failed queue delivery does not erase the admitted task, approval decision, or cancellation intent; the host must retry delivery. For a Mongo-backed deployment use the durable store's majority/CAS adapter, not a generic StorageDriver. In-memory stores keep their non-durable capability flag.

A2A supports 1.0 JSON-RPC SendMessage, GetTask, and CancelTask with text/JSON input and projected text/JSON artifacts. The card advertises streaming: false and pushNotifications: false; streaming, subscriptions, task listing, extended cards, and push configuration are rejected. New context IDs come from admission. Existing-task input is one JSON part {approvalId, preparedHash, approved}; it must match an outstanding durable approval. Default blocking SendMessage waits for a terminal/interrupted state. configuration.returnImmediately: true returns the admitted task immediately; the default 30-second wait limit raises a protocol error containing the task ID, leaving the task available through GetTask. CancelTask reports canceled only after supervisor acknowledgement; a timeout reports pending cancellation as an error, and GetTask remains working with metadata.cancellationRequested until acknowledged.

MCP supports 2026-07-28 HTTP framing and the io.modelcontextprotocol/tasks extension. The official SDK handles discovery/tool listing and schema validation; this adapter implements tools/call, tasks/get, tasks/update, and tasks/cancel. Each modern request must have the validated protocol envelope, matching protocol/method/name headers, and the Tasks capability. A missing capability, unsupported revision, unsupported method, or invalid argument is rejected before admission. Polling is supported; task notifications/subscriptions, task listing, legacy task shapes, and legacy HTTP sessions are not. Named ordinary/legacy adapters remain separate and unchanged.

A pending human decision maps to input_required with a stable approval ID and prepared digest. MCP input responses use {[approvalId]: {action: "accept", content: {approved, preparedHash}}}; decline/cancel deny the approval. Already answered or unknown keys are ignored, and respond must be installed explicitly. Approved/denied input awaiting worker pickup returns working. MCP cancellation acknowledges persisted intent with resultType: "complete"; polling remains working until cancellation is acknowledged. Completed projections may set isError: true for a domain/tool error while remaining protocol-completed. Internal execution failures expose only a generic protocol error; stored failure text stays private.

Request and projected task payloads are bounded to 64 KiB, with depth/node limits. A2A messages accept at most 32 parts; MCP exposes at most 128 distinct tools. Files, raw media, arbitrary artifact URLs, internal inputs/action arguments, and blob keys are never automatically serialized. Larger results require a host-owned retrieval API. The host supplies request rate/concurrency limits and task retention; MCP returns ttlMs: null because this bridge does not own expiration. Durable SSE event replay is provided by createDurableTaskRouter, separately from these polling protocol endpoints.

For MCP client recovery, MCPV2ToolProvider.exportTaskReference(handle, ctx) produces a credential-free reference for host-owned storage. After client restart, resumeTask(reference, ctx) verifies the provider/endpoint and tenant/user/session identity, fetches the remote task under current credentials, and returns a fresh local handle for the new run. HTTP Tasks and explicit tenant/user identity are required. Do not expose references or approval controls as ordinary model tools.

Local HTTP fixtures exercise the actual pinned SDKs, ownership, negotiation, approval digest binding, cancellation, projected artifacts, and compatibility with the existing adapters. The opt-in AGENTIUM_DURABLE_MONGO_TEST=1 fixture creates a random isolated database, closes the original store, recreates protocol servers over a new store client, and verifies approval/completion/cancellation reads. These are scoped interoperability checks for the implemented methods, not full protocol certification, external deployment approval, or exactly-once execution guarantees.

版本与发布记录

@agentium/transport 共发布 40 个版本,首次发布于 2026/05/22;过去 12 个月发布了 40 个版本。

版本发布日期距今
4.11.0latest2026/10/2415 天前
4.10.02026/10/2415 天前
4.9.02026/10/1326 天前
4.8.32026/10/1227 天前
4.8.22026/10/1029 天前
4.8.12026/10/1029 天前

关于 @agentium/transport 的常见问题

@agentium/transport 是什么?

HTTP and WebSocket transport layer for Agentium agents

如何安装 @agentium/transport?

在项目目录运行 npm install @agentium/transport,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:@agentium/core(^4.11.0)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@agentium/transport 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@agentium/transport 支持 ESM 还是 CommonJS?

同时提供 ES Module 与 CommonJS 入口,import 和 require() 都可以使用,打包工具会自动选择合适的版本。

@agentium/transport 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js ^22.18.0 || ^24.11.0。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@agentium/transport 可以商用吗?

@agentium/transport 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@agentium/transport 的下载量有多少?

根据 npm 官方下载统计,@agentium/transport 在 2026/10/05 – 2026/11/03 这 30 天内被下载 1,854 次,日均约 62 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@agentium/transport 还在维护吗?

最新版本 4.11.0 发布于 2026/10/24(15 天前);至今共发布 40 个版本,其中过去 12 个月发布了 40 个;首次发布于 2026/05/22。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。