Aimform

AWS Deployment

Use AWS Lambda for compute, API Gateway for WebSocket, and Step Functions for durable execution. Relational persistence must still be supplied through the authorized @aimform/db Database contract; this guide does not add an AWS provider driver or a second ORM.

Architecture

Browser ──WebSocket──▶ API Gateway (WebSocket API)
                            │
                            ▼
                      Lambda (connect/disconnect handler)
                            │
POST /messages ──▶ API Gateway (HTTP) ──▶ Lambda
                      │                       │
                      │                       ├─ Step Functions (durable execution)
                      │                       ├─ @aimform/db Database
                      │                       └─ S3 Storage
                      │
                      └──▶ Response: { runId }

Setup

import { AI } from "@aimform/ai";
import type { DatabaseAccess } from "@aimform/db";
 
// Construct this at the host composition boundary with an @aimform/db
// driver. Do not pass a provider pool or raw SQL client into @aimform/ai.
declare const database: DatabaseAccess;
 
// API Gateway WebSocket transport
const transport = new APIGatewayTransportAdapter(
  new ApiGatewayManagementApi({ endpoint: process.env.WS_ENDPOINT }),
);
 
const ai = new AI({
  model: "deepseek-v4-flash",
  apiKeys: { deepseekApiKey: process.env.DEEPSEEK_API_KEY! },
  db: database,
  transport,
  enableMemory: true,
  plugins: {
    files: new S3FilePlugin(s3Client, "aimform-files"),
    webSearch: new TavilySearchPlugin(process.env.TAVILY_API_KEY!),
  },
});

Lambda Handler

import { Handler } from "aws-lambda";
 
export const handler: Handler = async (event) => {
  const { runId, messages, toolContext } = JSON.parse(event.body);
 
  const result = await ai.chat({
    runId,
    conversationId: toolContext.conversationId,
    messages,
    toolContext: { ...toolContext, env: process.env },
  });
 
  return { statusCode: 200, body: JSON.stringify(result) };
};

Step Functions

For long-running tasks (>30s Lambda timeout), use Step Functions:

{
  "StartAt": "Generate",
  "States": {
    "Generate": {
      "Type": "Task",
      "Resource": "arn:aws:lambda:...:function:ai-generate",
      "Next": "CheckTools"
    },
    "CheckTools": {
      "Type": "Choice",
      "Choices": [
        { "Variable": "$.hasTools", "BooleanEquals": true, "Next": "ExecuteTools" }
      ],
      "Default": "Finalize"
    },
    "ExecuteTools": {
      "Type": "Task",
      "Resource": "arn:aws:lambda:...:function:ai-execute",
      "Next": "Generate"
    },
    "Finalize": {
      "Type": "Task",
      "Resource": "arn:aws:lambda:...:function:ai-finalize",
      "End": true
    }
  }
}

WebSocket Transport (API Gateway)

class APIGatewayTransportAdapter implements ChatTransportAdapter {
  readonly provider = "aws-api-gateway";
 
  async publishEvents(runId: string, events: AnyChatEvent[]) {
    const connections = await getConnectionsByRunId(runId);
    for (const conn of connections) {
      await apiGateway.postToConnection({
        ConnectionId: conn.connectionId,
        Data: JSON.stringify({ events }),
      }).promise().catch(() => {});
    }
  }
 
  getConnectionUrl(runId: string): string {
    return `${process.env.WS_ENDPOINT}?runId=${runId}`;
  }
}

On this page