FlowEngine API
The FlowEngine class orchestrates conversation execution.
Basic Usage
typescript
import { FlowEngine, MemoryStorage, OllamaAdapter } from "@andresaya/flowkit";
const engine = new FlowEngine(flow, {
llm: new OllamaAdapter({ model: "qwen3:4b" }),
storage: new MemoryStorage(),
});
// Start a conversation
const result = await engine.start("session-123");
console.log(result.message);
// Handle user input
const response = await engine.handle("session-123", "Hello!");
console.log(response.message);Constructor
typescript
new FlowEngine(flow: FlowConfig, config: EngineConfig)EngineConfig
typescript
interface EngineConfig {
/** LLM adapter (required) */
llm: LLMAdapter;
/** Storage adapter (required) */
storage: StorageAdapter;
/** Tools registry (optional) */
tools?: ToolsRegistry | ToolDefinition[];
/** Event handler (optional) */
onEvent?: (event: EngineEvent) => void;
/** Max extraction retries (default: 3) */
maxRetries?: number;
/** Handoff configuration (optional) */
handoff?: boolean | Partial<HandoffConfig>;
/** Timeout configuration (optional) */
timeout?: TimeoutConfig;
/** Knowledge base for RAG (optional) */
knowledgeBase?: KnowledgeBase;
/** Plugins (optional) */
plugins?: Plugin[];
/** Logger for debugging (optional) */
logger?: Logger;
}Methods
start(conversationId, initialSlots?)
Starts a new conversation.
typescript
const result = await engine.start("session-123");
// With pre-filled slots
const result = await engine.start("session-123", {
user_name: "John",
is_premium: true
});Returns: EngineOutput
handle(conversationId, message)
Processes a user message.
typescript
const result = await engine.handle("session-123", "My name is John");Returns: EngineOutput
getState(conversationId)
Gets the current conversation state.
typescript
const state = await engine.getState("session-123");
console.log(state.slots);
console.log(state.currentStep);getSlots(conversationId)
Gets all slot values.
typescript
const slots = await engine.getSlots("session-123");
// { user_name: "John", user_email: "john@example.com" }getSlot(conversationId, slotName)
Gets a specific slot value.
typescript
const name = await engine.getSlot("session-123", "user_name");setSlot(conversationId, slotName, value)
Sets a slot value.
typescript
await engine.setSlot("session-123", "verified", true);isEnded(conversationId)
Checks if conversation has ended.
typescript
const ended = await engine.isEnded("session-123");delete(conversationId)
Deletes a conversation's state.
typescript
await engine.delete("session-123");EngineOutput
The result returned by start() and handle():
typescript
interface EngineOutput {
/** The bot's response message */
message: string;
/** Whether the conversation has ended */
done: boolean;
/** Current step and slots */
state: {
step: string;
slots: Slots;
};
}Events
Use onEvent to track conversation events:
typescript
const engine = new FlowEngine(flow, {
llm,
storage,
onEvent: (event) => {
switch (event.type) {
case "flow:start":
console.log("Started:", event.conversationId);
break;
case "flow:end":
console.log("Ended:", event.slots);
break;
case "step:enter":
console.log("Step:", event.step);
break;
case "extract:success":
console.log("Extracted:", event.extractType, "=", event.value);
break;
case "error":
console.error("Error:", event.error);
break;
}
}
});Event Types
| Event | Description |
|---|---|
flow:start | Conversation started |
flow:end | Conversation ended |
step:enter | Entered a step |
step:exit | Left a step |
extract:success | Data extracted |
extract:fail | Extraction failed |
user:message | User sent message |
agent:message | Agent sent message |
tool:call | Tool being called |
tool:result | Tool returned |
handoff:detected | Handoff detected |
error | Error occurred |
Handoff Configuration
Enable handoff detection:
typescript
const engine = new FlowEngine(flow, {
llm,
storage,
handoff: {
enabled: true,
keywords: ["human", "agent", "person"],
phrases: ["speak to someone", "talk to a human"],
},
onEvent: (event) => {
if (event.type === "handoff:detected") {
// Transfer to human agent
transferToHuman(event.conversationId, event.reason);
}
}
});Timeout Configuration
typescript
const engine = new FlowEngine(flow, {
llm,
storage,
timeout: {
messageTimeout: 30000, // 30 seconds
sessionTimeout: 600000, // 10 minutes
},
onEvent: (event) => {
if (event.type === "timeout") {
console.log("Timeout:", event.timeoutType);
}
}
});Example: Complete Integration
typescript
import {
agent, flow, FlowEngine,
MemoryStorage, OllamaAdapter, Tools,
name, email
} from "@andresaya/flowkit";
// Agent
const bot = agent("Assistant").build();
// Flow
const myFlow = flow("onboarding", bot)
.ask("name", "What's your name?", name(), "name")
.then("email")
.ask("email", "What's your email?", email(), "email")
.then("save")
.say("save", "Saving...")
.do("save_user")
.then("done")
.say("done", "All set!")
.done()
.build();
// Tools
const tools = new Tools();
tools.register("save_user", async (payload) => {
await db.users.create(payload);
return { success: true };
});
// Engine
const engine = new FlowEngine(myFlow, {
llm: new OllamaAdapter({ model: "qwen3:4b" }),
storage: new MemoryStorage(),
tools,
maxRetries: 3,
handoff: { enabled: true },
timeout: { sessionTimeout: 300000 },
onEvent: (event) => {
analytics.track(event);
}
});
// Use
const session = "user-123";
let result = await engine.start(session);
while (!result.done) {
const userInput = await getUserInput();
result = await engine.handle(session, userInput);
}