@agent-assistant/core
v0.4.35
Published
Assistant definition, lifecycle, and runtime composition for Agent Assistant SDK
Readme
@agent-assistant/core
@agent-assistant/core is the root composition package for Agent Assistant SDK. It defines the assistant contract, creates the runtime, dispatches normalized inbound messages to capability handlers, and emits outbound events through injected adapters.
The package is TypeScript-first, has no cloud assumptions, and does not implement sessions, surfaces, memory, routing, or product logic. Those concerns stay in later packages and integrate through abstract contracts defined here.
What It Owns
AssistantDefinitionfor assistant identity, capabilities, hooks, runtime constraints, and traitscreateAssistant()for constructing the runtime with injected inbound and outbound adaptersAssistantRuntimelifecycle methods:start(),stop(),dispatch(),emit(),register(),get(), andstatus()- capability dispatch with hook support, timeout handling, and concurrency limiting
- outbound targeting by
surfaceIdor session fanout through an abstract sessions subsystem - storing, freezing, and exposing
TraitsProvideron the runtime definition (store and expose — never interpret)
What It Does Not Own
- relay transport, HTTP servers, sockets, or surface normalization
- session creation or session lifecycle rules
- memory persistence or retrieval
- model routing, policy enforcement, or coordination logic
- product-specific prompts, workflows, or adapters
Installation
npm installFrom the package directory:
cd packages/core
npm install
npm test
npm run buildPublic API
import {
AssistantDefinitionError,
OutboundEventError,
createAssistant,
type AssistantDefinition,
type InboundMessage,
type OutboundEvent,
} from "@agent-assistant/core";createAssistant(definition, adapters)
Creates an AssistantRuntime from a validated assistant definition and two injected adapters:
inbound.onMessage(handler)andinbound.offMessage(handler)connect normalized inbound messages into coreoutbound.send(event)delivers targeted outbound messagesoutbound.fanout(event, surfaceIds)is optional and used for session fanout when available
The runtime is created in the created state. Call start() before dispatching messages.
Runtime Behavior
Lifecycle
start()is idempotent while startedstop()is idempotent after stop- a stopped runtime cannot be restarted
status()returns readiness, startup time, registered subsystems, registered capabilities, and current in-flight handler count
Dispatch
dispatch(message)runs the pre-dispatchonMessagehook when defined- returning
falsefromonMessagedrops the message without invoking a capability - missing capabilities do not throw from
dispatch(); they report throughonError - capability failures and timeouts report through
onError - concurrency is limited by
constraints.maxConcurrentHandlersand extra dispatches queue in FIFO order
Emit
emit({ surfaceId, text })performs a targeted sendemit({ sessionId, text })resolves the registeredsessionssubsystem and fans out to itsattachedSurfacesemit()throwsOutboundEventErrorwhen neithersurfaceIdnorsessionIdis present
Core keeps the sessions contract abstract. The runtime expects a subsystem registered under the string key sessions with either:
runtime.register("sessions", {
async getSession(sessionId: string) {
return {
attachedSurfaces: ["surface-a", "surface-b"],
};
},
});or:
runtime.register("sessions", {
async get(sessionId: string) {
return {
attachedSurfaces: ["surface-a", "surface-b"],
};
},
});Example
import { createAssistant, type InboundMessage } from "@agent-assistant/core";
const runtime = createAssistant(
{
id: "assistant-1",
name: "Example Assistant",
capabilities: {
reply: async (message: InboundMessage, context) => {
context.log.info("handling inbound message");
await context.runtime.emit({
surfaceId: message.surfaceId,
text: `Echo: ${message.text}`,
});
},
},
},
{
inbound: {
onMessage(handler) {
void handler;
},
offMessage(handler) {
void handler;
},
},
outbound: {
async send(event) {
console.log("send", event);
},
},
},
);
await runtime.start();Traits
AssistantDefinition accepts an optional traits field of type TraitsProvider from @agent-assistant/traits. Core stores and freezes the provider during assembly. It does not read, branch on, or interpret any trait values.
import { createTraitsProvider } from "@agent-assistant/traits";
import { createAssistant } from "@agent-assistant/core";
const runtime = createAssistant(
{
id: "sage-assistant",
name: "Sage",
traits: createTraitsProvider(
{ voice: "concise", formality: "professional", proactivity: "medium", riskPosture: "moderate" },
{ preferMarkdown: true, preferredResponseLength: 800 },
),
capabilities: {
reply: async (message, context) => {
// Capability handlers access traits as read-only data
const voice = context.runtime.definition.traits?.traits.voice;
const preferMarkdown = context.runtime.definition.traits?.surfaceFormatting?.preferMarkdown;
// Surface formatting decisions live here — not in core
void voice; void preferMarkdown;
},
},
},
adapters,
);traits is optional. Existing definitions without traits work without modification.
@agent-assistant/traits is a peer dependency. Consumers that do not use traits do not need to install it.
Development
npm testruns the isolated Vitest suite for WF-1, WF-2, WF-4, and WF-5 core workflowsnpm run buildemitsdist/declarations and JavaScript viatsc
CORE_PACKAGE_IMPLEMENTED
