/** * The managed connector protocol. * * A connector is one integration with one external platform. It may contribute * tools, HTTP routes, sandbox provisioning, inbound events, and/or a named * messaging surface. Discovery is file-based: the CLI globs modules under * `connectors/` that export a `connector`, imports each one, and hands them to * {@link collectConnectors}, which stamps each with its file-stem `name`. */ import type { SandboxBackendProtocolV2 } from "deepagents"; import type { ChannelManifest } from "../channels/manifest.js"; import type { ChannelTransport } from "../channels/runtime.js"; import type { IdentityConfig, IdentityDefinition, RuntimeIdentity } from "../identity/index.js"; import type { ManagedRunConfig } from "./types.js"; /** * Realm-global brand marking a value as a managed connector. `Symbol.for` keeps * the identity stable across duplicate module instances (e.g. a connector built * against one copy of the package and collected by another). */ export declare const CONNECTOR_BRAND: unique symbol; /** * Build-time context handed to {@link Connector.tools} during agent-graph * construction. Intentionally minimal for v0: a connector's tools close over * their own configuration, and per-run identity flows through the existing * runtime seam into each tool's `invoke`, not through here. Reserved for future * deployment metadata. */ export type ToolContext = Record; /** * Request context handed to {@link Connector.http} when the managed HTTP app is * built. The connector receives its own namespaced sub-router (collision-safe), * the declared identity for its own authorization logic, and a * {@link HttpContext.requireIdentity} helper that fails closed. */ export interface HttpContext { /** * Router the connector mounts its routes on. Already namespaced under the * connector, so routes cannot collide with identity/API routes or with other * connectors. Routes registered here are **secure by default** — MDA resolves * and enforces caller identity before the handler runs (see * {@link HttpSubRouter}). */ readonly router: HttpSubRouter; /** The declared identity, for the connector's own authorization decisions. */ readonly identity?: IdentityConfig; /** * Resolve the caller identity from the raw request, reusing the same resolver * as the managed auth handler. Throws a 401-style error when identity is * absent or invalid. Secured routes already resolve identity for you; use this * only inside a {@link HttpSubRouter.public} route that wants optional or * conditional authentication. */ requireIdentity(request: Request): Promise; } /** * Context handed to {@link Connector.events} for the conventional public * inbound route at `/connectors/{name}/events`. */ export interface EventsContext { /** File-stem connector name (route segment). */ readonly name: string; /** The inbound request. */ readonly request: Request; /** * Pre-read raw body when the HTTP framework may have consumed `request` * (Hono mount passes `await c.req.text()`). */ readonly rawBody?: string | Uint8Array; /** The live connector instance (e.g. GitHub `prompt` callbacks). */ readonly connector: Connector; } /** * Deploy/runtime requirements a connector declares. * * Generalizes the former channel manifest: required env, permissions, and * opaque provider config. */ export type ConnectorRequirements = ChannelManifest; /** * Context handed to {@link Connector.sandbox} when a managed sandbox is created * or reused for a thread. Connectors close over their own config and use * {@link SandboxContext.backend} to provision checkout/CLI/credentials state. */ export interface SandboxContext { /** Sandbox backend surface (execute + optional file upload). */ readonly backend: ConnectorSandboxBackend; /** * `"create"` on first provision; `"reuse"` when a new thread joins an existing * sandbox; `"credentials"` on later messages in an already-synced thread * (refresh token / CLI wiring without re-cloning). */ readonly mode: "create" | "reuse" | "credentials"; /** Per-run LangGraph config (identity + thread scoping). */ readonly config?: ManagedRunConfig; /** Root identity declaration, when the project opts into managed identity. */ readonly identity?: IdentityDefinition; } /** Backend surface connectors may use during sandbox provisioning. */ export type ConnectorSandboxBackend = Pick & Partial>; /** * The router a connector uses to register routes. Structural so the managed app * can back it with Hono without leaking the framework type into the contract. * * Routes registered on this router are **secure by default**: MDA resolves the * caller's identity (401 on failure) before invoking the handler, and passes the * frozen {@link RuntimeIdentity} as the handler's second argument. Authorization * (scopes, constraints, ownership) remains the connector's job. * * A route that must be reachable without authentication (webhooks, health * checks, public callbacks) has to opt out **explicitly** via * {@link HttpSubRouter.public} — the unauthenticated surface is never the * accidental default. */ export interface HttpSubRouter { get(path: string, handler: SecuredRouteHandler): void; post(path: string, handler: SecuredRouteHandler): void; put(path: string, handler: SecuredRouteHandler): void; delete(path: string, handler: SecuredRouteHandler): void; /** Explicit opt-out: routes reachable without MDA identity enforcement. */ readonly public: PublicSubRouter; } /** The unauthenticated router surface, reached only via {@link HttpSubRouter.public}. */ export interface PublicSubRouter { get(path: string, handler: PublicRouteHandler): void; post(path: string, handler: PublicRouteHandler): void; put(path: string, handler: PublicRouteHandler): void; delete(path: string, handler: PublicRouteHandler): void; } /** * Handler for a secured route. MDA has already resolved and enforced the * caller's identity, which it passes as the second argument. */ export type SecuredRouteHandler = (request: Request, identity: RuntimeIdentity) => Response | Promise; /** Handler for an explicitly public route. No identity is resolved by MDA. */ export type PublicRouteHandler = (request: Request) => Response | Promise; /** Tools a connector contributes to the agent. Kept structural (`unknown[]`). */ export type ConnectorToolList = unknown[]; /** * A managed connector. Implement at least one of {@link Connector.tools}, * {@link Connector.http}, {@link Connector.sandbox}, {@link Connector.events}, * {@link Connector.messaging}, or {@link Connector.requirements}; a connector * implementing none does nothing and is rejected by {@link collectConnectors}. */ export interface Connector { readonly [CONNECTOR_BRAND]: true; /** * Diagnostic / provider label (e.g. `"mcp_servers"`, `"github"`, `"slack"`). * HTTP mounts use {@link name}, not kind. */ readonly kind: string; /** * File-stem instance name, stamped by {@link collectConnectors}. Mount * namespace and messaging address (`runtime.channel` / `deliverTo`). */ readonly name?: string; /** Contribute tools during agent-graph construction. MCP implements this. */ tools?(ctx: ToolContext): ConnectorToolList | Promise; /** Mount HTTP routes during managed-app construction. LangSmith implements this. */ http?(ctx: HttpContext): void | Promise; /** Provision/refresh sandbox state when a managed sandbox is created or reused. */ sandbox?(ctx: SandboxContext): void | Promise; /** * Handle `POST /connectors/{name}/events` (verify + normalize + ACK + work). * Public by construction; provider signature verification is the adapter's job. */ events?(ctx: EventsContext): Response | Promise; /** Build outbound messaging transport for `runtime.channel` / schedule delivery. */ messaging?(env: NodeJS.ProcessEnv): ChannelTransport | undefined; /** Deploy/runtime requirements (env, permissions, connection, provider config). */ requirements?(name: string): ConnectorRequirements; } /** * Run the `tools` hook of every connector that implements it and concatenate the * results, preserving connector order. Connectors without a `tools` hook (e.g. * HTTP-only connectors) contribute nothing. */ export declare function loadConnectorTools(connectors: readonly Connector[], ctx?: ToolContext): Promise; /** * Run the `sandbox` hook of every connector that implements it, preserving order. * Connectors without a `sandbox` hook contribute nothing. */ export declare function runConnectorSandboxHooks(connectors: readonly Connector[] | undefined, ctx: SandboxContext): Promise; /** True when at least one connector implements {@link Connector.sandbox}. */ export declare function hasSandboxConnectors(connectors: readonly Connector[] | undefined): boolean; /** True when any connector can start an ingress run via {@link Connector.events}. */ export declare function hasIngressConnectors(connectors: readonly Connector[] | undefined): boolean; /** * Build the requirements map (file-stem → manifest) from connectors that * implement {@link Connector.requirements}. */ export declare function requirementsFromConnectors(connectors: readonly Connector[]): Record; /** A discovered `connectors/` module paired with its source path for diagnostics. */ export interface DiscoveredConnectorModule { /** Project-relative path of the module, used in error messages. */ readonly source: string; /** The imported module namespace; its `connector` export is the connector. */ readonly module: { connector?: unknown; } & Record; } /** Narrow an arbitrary value to a {@link Connector} by its brand and hooks. */ export declare function isConnector(value: unknown): value is Connector; /** * Validate and collect the connectors discovered under `connectors/`. * * Each module should expose exactly one connector as `export const connector`. * The file stem becomes the instance {@link Connector.name} (mount namespace and * messaging address). Duplicate stems are a hard error. Modules with no such * export, or whose `connector` is not branded, are skipped. A branded connector * that implements no hooks is still a hard error. */ export declare function collectConnectors(modules: readonly DiscoveredConnectorModule[]): Connector[]; //# sourceMappingURL=connector.d.ts.map