Skip to content

Getting Started ​

This guide walks you through creating your first AIDK application.

Prerequisites ​

  • Node.js 24+
  • pnpm (recommended) or npm

Installation ​

bash
# Create a new project
mkdir my-agent && cd my-agent
pnpm init

# Install core packages
pnpm add aidk aidk-express express

# Install an AI adapter (choose one)
pnpm add aidk-ai-sdk ai @ai-sdk/openai
# or: pnpm add aidk-openai
# or: pnpm add aidk-google

# Install dev dependencies
pnpm add -D typescript @types/node @types/express tsx

Project Setup ​

TypeScript Configuration ​

Create tsconfig.json:

json
{
  "compilerOptions": {
    "target": "ES2022",
    "module": "NodeNext",
    "moduleResolution": "NodeNext",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "jsx": "react-jsx",
    "jsxImportSource": "aidk"
  },
  "include": ["src"]
}

Package Configuration ​

Update package.json:

json
{
  "type": "module",
  "scripts": {
    "dev": "tsx watch src/server.ts",
    "build": "tsc",
    "start": "node dist/server.js"
  }
}

Create Your First Agent ​

1. Define the Agent ​

Create src/agents/assistant.tsx:

tsx
import {
  EngineComponent,
  COM,
  TickState,
  Section,
  Message,
  Timeline,
  comState,
  type JSX,
  type COMTimelineEntry,
} from 'aidk';
import { AiSdkModel } from 'aidk-ai-sdk';
import { openai } from '@ai-sdk/openai';

export class AssistantAgent extends Component {
  // Use comState for timeline - shared across components, persisted across ticks
  private timeline = comState<COMTimelineEntry[]>('timeline', []);

  onTickStart(com: COM, state: TickState) {
    // Append new entries from the model response
    if (state.current?.timeline?.length) {
      this.timeline.update(t => [...t, ...state.current!.timeline]);
    }
  }

  render(com: COM, state: TickState): JSX.Element {
    return (
      <>
        {/* Configure the AI model */}
        <AiSdkModel
          model={openai('gpt-5.2-mini')}
          providerOptions={{
            apiKey: process.env.OPENAI_API_KEY,
          }}
        />

        {/* Conversation history - read from signal */}
        <Timeline>
          {this.timeline().map((entry, index) => (
            <Message
              key={index}
              role={entry.message?.role || 'user'}
              content={entry.message?.content}
            />
          ))}
        </Timeline>

        {/* System instructions - automatically formatted for the model */}
        <Section id="instructions" audience="model">
          You are a helpful assistant. Be concise and friendly.
        </Section>
      </>
    );
  }
}

// Functional wrapper
export function Assistant(): JSX.Element {
  return <AssistantAgent />;
}

Note: We use comState() for the timeline because it persists across ticks and is automatically cleaned up. See State Management for more details.

Tip: Your JSX content is automatically formatted in the optimal format for each model. OpenAI models get Markdown, Claude gets XML, etc. See Renderers for details.

2. Create the Server ​

Create src/server.ts:

tsx
import 'dotenv/config';
import express from 'express';
import cors from 'cors';
import { createEngine } from 'aidk';
import { createSSEHandler } from 'aidk-express';
import { Assistant } from './agents/assistant';

const app = express();
app.use(cors());
app.use(express.json());

// Create the engine
const engine = createEngine();

// Agent streaming endpoint
app.post('/api/agent/stream', createSSEHandler({
  engine,
  getAgent: () => <Assistant />,
}));

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
  console.log(`Server running on http://localhost:${PORT}`);
});

3. Run the Server ​

bash
# Set your API key
export OPENAI_API_KEY=sk-...

# Start the server
pnpm dev

4. Test with curl ​

bash
curl -X POST http://localhost:3000/api/agent/stream \
  -H "Content-Type: application/json" \
  -d '{"timeline": [{"kind": "message", "message": {"role": "user", "content": [{"type": "text", "text": "Hello!"}]}}]}'

Adding Tools ​

Create src/tools/calculator.ts:

tsx
import { createTool } from 'aidk';
import { z } from 'zod';

export const calculatorTool = createTool({
  name: 'calculator',
  description: 'Evaluate mathematical expressions',
  input: z.object({
    expression: z.string().describe('The math expression to evaluate'),
  }),
  execute: async ({ expression }) => {
    try {
      // In production, use a proper math parser
      const result = Function(`"use strict"; return (${expression})`)();
      return { success: true, result };
    } catch (error) {
      return { success: false, error: 'Invalid expression' };
    }
  },
});

Add the tool to your agent:

tsx
import { calculatorTool } from '../tools/calculator';

// In your render method:
<>
  <AiSdkModel model={openai('gpt-5.2-mini')} />
  <Timeline>{/* ... */}</Timeline>
  <Section id="instructions" audience="model">
    You are a helpful assistant with access to a calculator.
  </Section>
  <Tool definition={calculatorTool} />
</>

Using NestJS Instead ​

If you prefer NestJS over Express, you can use aidk-nestjs:

Installation ​

bash
pnpm add aidk aidk-nestjs @nestjs/common @nestjs/core @nestjs/platform-express rxjs express
pnpm add -D @nestjs/cli typescript

Setup ​

tsx
// app.module.ts
import { Module } from '@nestjs/common';
import { EngineModule } from 'aidk-nestjs';
import { createEngine } from 'aidk';
import { AgentController } from './agent.controller';

@Module({
  imports: [
    EngineModule.forRoot({
      engine: createEngine(),
    }),
  ],
  controllers: [AgentController],
})
export class AppModule {}

Controller ​

tsx
// agent.controller.ts
import { Controller, Post, Body, Res, UseInterceptors } from '@nestjs/common';
import { Response } from 'express';
import { Stream, EngineContextInterceptor } from 'aidk-nestjs';
import { EngineInput } from 'aidk';
import { Assistant } from './agents/assistant';

@Controller('api/agent')
@UseInterceptors(EngineContextInterceptor)
export class AgentController {
  @Post('stream')
  @Stream(<Assistant />)
  async stream(@Body() input: EngineInput, @Res() res: Response) {
    return input;
  }
}

See the NestJS API Documentation for more details.

Adding a Frontend ​

See the React Integration or Angular Integration guides.

Next Steps ​

Released under the MIT License.