@tisyn/agent
v0.8.0
Published
`@tisyn/agent` defines the typed capability boundary between Tisyn workflows and the work that actually gets performed. It turns effectful calls into explicit contracts: named agent boundaries, typed operation payloads, and handlers the runtime can dispat
Downloads
1,093
Readme
@tisyn/agent
@tisyn/agent defines the typed capability boundary between Tisyn workflows and the work that actually gets performed. It turns effectful calls into explicit contracts: named agent boundaries, typed operation payloads, and handlers the runtime can dispatch locally or across a transport boundary.
If @tisyn/ir describes what work should happen, @tisyn/agent describes who can do it and how it is called.
Where It Fits
This package sits between authored workflow logic and concrete side effects.
- The compiler lowers authored calls like
yield* Service().method(...)into effectful IR. - The runtime resolves those effects through installed agent handlers.
- The transport layer can expose the same declarations across process, worker, or network boundaries.
@tisyn/agent is the capability layer that gives effect IDs stable names, payload shapes, and implementations.
Core Concepts
agent(id, operations)declares a named capability boundary.operation<Spec>()declares one typed operation on that boundary.implementAgent()binds handlers to a declaration.Effects.around()installs Effection middleware layers that intercept or route effect invocations.dispatch()performs an effect call through the currentEffectsmiddleware boundary.invoke()executes a declared operation against the current dispatch stack.useAgent()retrieves a typed handle for an agent bound in the current scope viauseTransport().
Agent declarations are typed metadata plus call helpers. They describe invocations, but do not execute anything by themselves.
Public API
The public surface exported from src/index.ts includes:
agent— declare a named agent boundary and its available operationsoperation— declare the typed input/output contract for one operationimplementAgent— bind handlers to a declaration so the runtime can dispatch themEffects— the Effection middleware context for invocation routing; useEffects.around()to install intercept layersdispatch— perform an effect call through the currentEffectsmiddleware boundaryinvoke— execute a declared operation against the current dispatch stackuseAgent— retrieve a typed handle for an agent previously bound viauseTransport()installEnforcement— install a non-bypassable enforcement wrapper that runs before theEffectsmiddleware chaininstallCrossBoundaryMiddleware— install an IR function node as the cross-boundary middleware carrier for further remote delegationgetCrossBoundaryMiddleware— read the current cross-boundary middleware carrier from scope (returnsnullif not set)evaluateMiddlewareFn— drive an IR function node as a middleware function with scope-local dispatch semantics
Important exported types:
OperationSpec— describe the typed input and result shape of an operationDeclaredAgent— represent the callable declaration returned byagent()AgentDeclaration— structural type for a declared agent contractAgentImplementation— declaration paired with handlers and install logicImplementationHandlers— type the handler map expected byimplementAgent()Invocation— represent one concrete operation call ready for dispatchArgsOf— extract the input shape from an operation declarationResultOf— extract the result type from an operation declarationWorkflow— represent the authored workflow return type used in ambient declarationsAgentHandle— typed operation handle returned byuseAgent()EnforcementFn— function type for enforcement wrappers installed viainstallEnforcement()
Declare an Agent
import { agent, operation } from "@tisyn/agent";
const orders = agent("orders", {
fetch: operation<{ input: { orderId: string } }, { id: string; total: number }>(),
cancel: operation<{ input: { orderId: string } }, void>(),
});Calling a declared operation produces an invocation description. It is a typed effect request, not a direct function call.
const request = orders.fetch({ input: { orderId: "ord-1" } });Implement Handlers
import { implementAgent } from "@tisyn/agent";
const ordersImpl = implementAgent(orders, {
*fetch({ input }) {
return { id: input.orderId, total: 42 };
},
*cancel() {},
});
The implementation exposes call(opName, payload) for use by protocol servers. To make the handlers reachable at the dispatch layer, pass the implementation to a transport (see @tisyn/transport).
Invoke an Operation
import { invoke } from "@tisyn/agent";
const order = yield* invoke(
orders.fetch({ input: { orderId: "ord-1" } }),
);This is useful when:
- application code wants to call an installed agent directly
- one agent implementation delegates work to another
const checkoutImpl = implementAgent(checkout, {
*complete({ input }) {
const order = yield* invoke(
orders.fetch({ input: { orderId: input.orderId } }),
);
return { ok: order.total > 0 };
},
});Mental Model
An agent declaration gives Tisyn a typed, named capability boundary.
- Declarations define what operations exist and what they accept or return.
- Invocations describe one requested operation call.
- Implementations attach concrete handlers to those declarations.
- Effects middleware decides how invocations are routed.
That routing can stay local, or it can be forwarded through another layer such as a worker or network transport. @tisyn/agent stays focused on the contract and dispatch shape rather than the transport itself.
Relationship to the Rest of Tisyn
- Use
@tisyn/agentwith@tisyn/runtimewhen executing IR against real effect handlers. - Use it with
@tisyn/transportwhen those handlers must be reached across process, worker, or network boundaries. @tisyn/compilerdiscovers effect usage from authored workflow source, but does not execute effects.@tisyn/protocoldefines wire messages for remote execution, but@tisyn/agentitself remains protocol-agnostic.
What This Package Does Not Define
@tisyn/agent does not define:
- the IR language
- durable execution
- replay semantics
- transport or protocol messages
It defines the typed capability layer that those systems rely on.
Summary
Use @tisyn/agent when you want effectful workflow calls to become explicit, typed capability contracts.
It gives Tisyn a stable boundary between workflow intent and concrete execution: declarations name the capability, operations define the payload shape, implementations provide handlers, and dispatch makes invocation routable wherever the work actually happens.
