Context & Events
Access request context and communicate between agents via events.
Overview
The SDK provides rich context objects for every request and a Pub/Sub-based event system for agent-to-agent communication. Context includes request metadata, session state, and buyer information. Events enable loose coupling between agents.
Request Context
Every ACP event handler receives a RequestContext object with metadata about the current request:
import { HyperfoldAgent, OnACPEvent, RequestContext } from '@hyperfold/actions-sdk';
@HyperfoldAgent({ name: 'context-aware-agent', type: 'negotiator' })
export class ContextAwareAgent {
@OnACPEvent('quote')
async handleQuote(
productId: string,
offer: number,
context: RequestContext // Automatically injected
) {
console.log('Request ID:', context.requestId);
console.log('Timestamp:', context.timestamp);
console.log('Source IP:', context.sourceIp);
console.log('Buyer Agent:', context.buyer.agent_id);
console.log('Buyer Provider:', context.buyer.provider);
console.log('Session ID:', context.session.id);
console.log('Session Start:', context.session.started_at);
console.log('Trace ID:', context.trace.traceId);
console.log('Span ID:', context.trace.spanId);
const pricing = await this.calculatePrice(productId, {
buyerTier: context.buyer.loyalty_tier,
sessionHistory: context.session.interaction_count,
});
return { price: pricing.suggested };
}
}
Context Properties
| Property | Type | Description |
|---|---|---|
requestId | string | Unique request identifier |
timestamp | Date | Request timestamp |
buyer | BuyerContext | Buyer agent information |
session | SessionContext | Current session state |
trace | TraceContext | Distributed tracing IDs |
Session Context
Session context provides state management across multiple interactions within a single buyer session:
import { SessionContext } from '@hyperfold/actions-sdk';
@HyperfoldAgent({ name: 'session-agent', type: 'negotiator' })
export class SessionAgent {
@OnACPEvent('search')
async handleSearch(query: string, filters: any, context: RequestContext) {
const session = context.session as SessionContext;
const previousSearches = await session.get('searches') || [];
await session.set('searches', [...previousSearches, query]);
const cart = await session.get('cart') || [];
console.log('Interactions:', session.interaction_count);
console.log('Duration:', session.duration_ms);
return await this.search(query, filters);
}
async onSessionStart(session: SessionContext) {
await session.set('started_at', new Date().toISOString());
await session.set('cart', []);
await session.set('viewed_products', []);
if (session.customer_id) {
const customer = await this.crm.getCustomer(session.customer_id);
await session.set('customer', customer);
}
}
async onSessionEnd(session: SessionContext, outcome: SessionOutcome) {
await this.analytics.logSession({
session_id: session.id,
duration: session.duration_ms,
interactions: session.interaction_count,
outcome: outcome.status,
revenue: outcome.revenue,
});
await session.clear();
}
}
Session state is automatically persisted to Firestore. Default TTL is 24 hours but can be configured per-agent.
Event Publishing
Publish events to notify other agents of important actions:
import { HyperfoldAgent, Events } from '@hyperfold/actions-sdk';
@HyperfoldAgent({ name: 'event-publisher', type: 'negotiator' })
export class EventPublisher {
constructor(private events: Events) {}
@OnACPEvent('finalize')
async handleFinalize(checkoutId: string, paymentToken: string) {
const order = await this.createOrder(checkoutId, paymentToken);
await this.events.publish('order.created', {
order_id: order.id,
customer_id: order.customer_id,
items: order.items,
total: order.total,
timestamp: new Date().toISOString(),
});
await this.events.publish('fulfillment.required', {
order_id: order.id,
shipping_address: order.shipping_address,
items: order.items,
}, { topic: 'fulfillment-events' });
await this.events.publish('reminder.send', {
customer_id: order.customer_id,
order_id: order.id,
type: 'review_request',
}, { delay: '7d' });
return { order_id: order.id };
}
}
Publish Options
| Option | Type | Description |
|---|---|---|
topic | string | Pub/Sub topic (default: agent-events) |
delay | string | Delay before delivery (e.g., '5m', '1h', '7d') |
attributes | object | Custom Pub/Sub attributes |
Event Subscription
Subscribe to events from other agents using @OnEvent:
import { HyperfoldAgent, OnEvent } from '@hyperfold/actions-sdk';
@HyperfoldAgent({ name: 'event-subscriber', type: 'fulfillment' })
export class EventSubscriber {
@OnEvent('order.created')
async handleOrderCreated(event: OrderCreatedEvent) {
await this.startFulfillment(event.order_id, event.items);
}
@OnEvent('order.cancelled')
async handleOrderCancelled(event: OrderCancelledEvent) {
await this.cancelFulfillment(event.order_id);
}
@OnEvent('inventory.low', { topic: 'inventory-events' })
async handleLowInventory(event: LowInventoryEvent) {
await this.notifications.sendAlert({
type: 'low_inventory',
product_id: event.product_id,
current_quantity: event.quantity,
reorder_threshold: event.threshold,
});
}
@OnEvent('order.created', {
filter: (event) => event.total > 1000,
})
async handleHighValueOrder(event: OrderCreatedEvent) {
await this.notifications.sendSlack({
channel: '#high-value-orders',
message: `High-value order: $${event.total} from ${event.customer_id}`,
});
}
@OnEvent('payment.failed', {
maxRetries: 3,
retryDelay: '5m',
deadLetterTopic: 'failed-payment-events',
})
async handlePaymentFailed(event: PaymentFailedEvent) {
await this.payments.retryPayment(event.payment_id);
}
}
Event handlers should be idempotent. Pub/Sub guarantees at-least-once delivery, so the same event may be delivered multiple times.
Learn about built-in tools in Tools Reference.