Skip to content

Deployment

The most common deployment — an HTTP server that handles chat requests:

import express from 'express';
import { Agent, anthropic, defineTool } from 'agentfootprint';
import { agentObservability } from 'agentfootprint/observe';
import { SSEFormatter } from 'agentfootprint/stream';
const app = express();
app.use(express.json());
const provider = anthropic('claude-sonnet-4-20250514');
// Define tools once — shared across requests
const lookupOrder = defineTool({ /* ... */ });
app.post('/chat', async (req, res) => {
const { message, sessionId } = req.body;
// Create a NEW agent per request for isolation
const obs = agentObservability();
const agent = Agent.create({ provider })
.system('You are a support agent.')
.tool(lookupOrder)
.recorder(obs)
.streaming(true)
.build();
// SSE streaming response
res.setHeader('Content-Type', 'text/event-stream');
res.setHeader('Cache-Control', 'no-cache');
res.setHeader('Connection', 'keep-alive');
await agent.run(message, {
onEvent: (event) => {
res.write(SSEFormatter.format(event));
},
});
res.end();
});
app.listen(3000);

Create a new agent instance per request. The Agent.create().build() call is lightweight — it builds an internal flowchart but doesn’t allocate heavy resources. The provider (LLM adapter) can be shared across requests.

// GOOD: shared provider, per-request agent
const provider = anthropic('claude-sonnet-4-20250514');
app.post('/chat', async (req, res) => {
const agent = Agent.create({ provider }) // lightweight — new per request
.system('You are helpful.')
.build();
const result = await agent.run(req.body.message);
res.json({ content: result.content });
});
// BAD: shared agent across requests — narrative and state will bleed
const agent = Agent.create({ provider }).build(); // DON'T share this
app.post('/chat', async (req, res) => {
const result = await agent.run(req.body.message); // race conditions
});
FROM node:22-slim
WORKDIR /app
COPY package*.json ./
RUN npm ci --production
COPY . .
EXPOSE 3000
CMD ["node", "dist/server.js"]
Terminal window
docker build -t my-agent .
docker run -p 3000:3000 -e ANTHROPIC_API_KEY=sk-ant-... my-agent
VariableDescription
ANTHROPIC_API_KEYAnthropic API key (for AnthropicAdapter)
OPENAI_API_KEYOpenAI API key (for OpenAIAdapter)
AWS_REGIONAWS region (for BedrockAdapter)
AWS_ACCESS_KEY_IDAWS credentials (or use IAM roles)

Never hardcode API keys — use environment variables or a secrets manager.

import { Agent, bedrock } from 'agentfootprint';
const provider = bedrock('anthropic.claude-sonnet-4-20250514-v1:0');
export const handler = async (event: any) => {
const { message } = JSON.parse(event.body);
const agent = Agent.create({ provider })
.system('You are helpful.')
.build();
const result = await agent.run(message);
return {
statusCode: 200,
body: JSON.stringify({ content: result.content }),
};
};

For AWS AgentCore (managed serverless with VM isolation), see the AgentCore integration.

Add a health endpoint for Kubernetes, ECS, or load balancer probes:

app.get('/health', (_req, res) => {
res.json({ status: 'ok', uptime: process.uptime() });
});

Drain in-flight requests before stopping. Use AbortController to cancel running agents:

const activeControllers = new Set<AbortController>();
app.post('/chat', async (req, res) => {
const controller = new AbortController();
activeControllers.add(controller);
try {
const agent = Agent.create({ provider }).build();
const result = await agent.run(req.body.message, {
signal: controller.signal, // agent respects AbortSignal
});
res.json({ content: result.content });
} finally {
activeControllers.delete(controller);
}
});
// On SIGTERM: cancel all running agents, then exit
process.on('SIGTERM', () => {
for (const c of activeControllers) c.abort();
server.close(() => process.exit(0));
});
  • API keys in environment variables (not in code)
  • agentObservability() attached to every agent
  • Error handling with withRetry / withFallback
  • Per-request agent instances (not shared)
  • Token/cost monitoring via CloudWatch or your observability stack
  • maxIterations set to prevent runaway loops
  • Streaming enabled for user-facing agents
  • Tests with mock() in CI pipeline