Skip to content

Progressive Adoption Examples

See each adoption level in action with complete, runnable examples.

Level 1: Just Compilation

The minimal starting point. Use JSX for context, keep your existing code.

tsx
import { System, User, Assistant, Section } from 'aidk-ai-sdk';

export function SimpleAgent() {
  return (
    <>
      <System>You are a helpful math tutor.</System>

      <User>What is 2 + 2?</User>

      <Section audience="model">
        Show your work step by step.
      </Section>
    </>
  );
}
tsx
import { compile } from 'aidk-ai-sdk';
import { generateText } from 'ai';
import { openai } from '@ai-sdk/openai';
import { SimpleAgent } from './agent';

async function main() {
  // Compile JSX to AI SDK format
  const compiled = await compile(<SimpleAgent />);

  // Use your existing generateText code
  const result = await generateText({
    model: compiled.model ?? openai('gpt-5.2'),
    messages: compiled.messages,
    tools: compiled.tools,
    system: compiled.system,
  });

  console.log(result.text);
}

main();

Key Points:

  • No changes to your generateText call
  • JSX provides cleaner context building
  • You control everything about model execution

Level 2: Executor Pattern

Add multi-tick execution while keeping control of model calls.

tsx
import { Component, comState, Timeline, Message } from 'aidk';
import { Model, Tool } from 'aidk-ai-sdk';
import { openai } from '@ai-sdk/openai';
import { calculatorTool } from './tools';

export class MathAgent extends Component {
  private timeline = comState<any[]>('timeline', []);

  onTickStart(com, state) {
    if (state.current?.timeline) {
      this.timeline.update(t => [...t, ...state.current.timeline]);
    }
  }

  render() {
    return (
      <>
        <Model model={openai('gpt-5.2-mini')} />

        <Timeline>
          {this.timeline().map((entry, i) => (
            <Message key={i} {...entry.message} />
          ))}
        </Timeline>

        <Tool definition={calculatorTool} />
      </>
    );
  }
}
tsx
import { createCompiler } from 'aidk-ai-sdk';
import { streamText } from 'ai';
import { MathAgent } from './agent';

async function main() {
  const compiler = createCompiler();

  // You provide the executor
  const result = await compiler.stream(
    <MathAgent />,
    [{ role: 'user', content: 'What is 15 * 23?' }],
    async (input) => {
      console.log(`Tick ${input.tick}: Calling model...`);

      return await streamText({
        model: input.model ?? openai('gpt-5.2'),
        messages: input.messages,
        tools: input.tools,
        system: input.system,
      });
    }
  );

  for await (const chunk of result.fullStream) {
    process.stdout.write(chunk.textDelta ?? '');
  }
}

main();
tsx
import { createTool } from 'aidk';
import { z } from 'zod';

export const calculatorTool = createTool({
  name: 'calculate',
  description: 'Perform mathematical calculations',
  input: z.object({
    expression: z.string(),
  }),
  handler: async ({ expression }) => {
    const result = Function(`"use strict"; return (${expression})`)();
    return { result };
  },
});

Key Points:

  • AIDK handles multi-tick loop
  • Tools automatically executed
  • You control each model call
  • Add logging, caching, retries in your executor

Level 3: Managed Execution

Let AIDK handle everything.

tsx
import { Component, comState, Timeline, Message, Section } from 'aidk';
import { Model, Tool } from 'aidk-ai-sdk';
import { openai } from '@ai-sdk/openai';

export class TaskAgent extends Component {
  private timeline = comState<any[]>('timeline', []);
  private taskCount = comState<number>('tasks', 0);

  onTickStart(com, state) {
    if (state.current?.timeline) {
      this.timeline.update(t => [...t, ...state.current.timeline]);
    }
  }

  render(com, state) {
    return (
      <>
        <Model
          model={openai('gpt-5.2-mini')}
          temperature={0.7}
        />

        <Timeline>
          {this.timeline().map((entry, i) => (
            <Message key={i} {...entry.message} />
          ))}
        </Timeline>

        <Section audience="model">
          <H2>Task Management</H2>
          <Paragraph>Total tasks: {this.taskCount()}</Paragraph>
        </Section>
      </>
    );
  }
}
tsx
import { createCompiler } from 'aidk-ai-sdk';
import { openai } from '@ai-sdk/openai';
import { TaskAgent } from './agent';

async function main() {
  const compiler = createCompiler({
    model: openai('gpt-5.2-mini'),
    temperature: 0.7,
  });

  // No executor needed
  const result = await compiler.run(
    <TaskAgent />,
    [{ role: 'user', content: 'Add a task: Buy groceries' }]
  );

  console.log(result.text);
}

main();

Key Points:

  • Minimal boilerplate
  • Model configured once
  • Components can override model per-tick
  • Great for new projects

Level 4: Drop-in Replacement

Simplest API - mirrors AI SDK exactly.

tsx
import { generateText, streamText } from 'aidk-ai-sdk';
import { openai } from '@ai-sdk/openai';

// Just like ai.generateText(), but with JSX
const result = await generateText(
  <>
    <System>You are helpful.</System>
    <User>Hello!</User>
    <Model model={openai('gpt-5.2')} temperature={0.8} />
  </>
);

console.log(result.text);

// Streaming works the same way
const { fullStream } = streamText(
  <>
    <System>You are helpful.</System>
    <User>Tell me a story.</User>
  </>,
  {
    model: openai('gpt-5.2'), // override or explicit options
  }
);

for await (const chunk of fullStream) {
  process.stdout.write(chunk.textDelta ?? '');
}

Key Points:

  • Exact same API as AI SDK
  • JSX is just the first argument
  • Works with all AI SDK options
  • Perfect for simple use cases

Level 5: Full Engine with Express

Production-ready backend with full features.

tsx
import { Component, comState, Context } from 'aidk';
import { Model, Tool } from 'aidk-ai-sdk';
import { openai } from '@ai-sdk/openai';

export class CustomerAgent extends Component {
  private timeline = comState<any[]>('timeline', []);
  private customer = comState<any>('customer', null);

  async onMount(com) {
    const ctx = Context.get();
    const customer = await db.customers.findById(ctx.user.id);
    this.customer.set(customer);
  }

  onTickStart(com, state) {
    if (state.current?.timeline) {
      this.timeline.update(t => [...t, ...state.current.timeline]);
    }
  }

  render() {
    const ctx = Context.get();
    const customer = this.customer();

    return (
      <>
        <Model model={openai('gpt-5.2')} />

        <Section audience="model">
          <H2>Customer Context</H2>
          <Paragraph>Name: {customer?.name}</Paragraph>
          <Paragraph>Tier: {customer?.tier}</Paragraph>
          <Paragraph>Support level: {ctx.metadata.support_tier}</Paragraph>
        </Section>

        <Timeline>
          {this.timeline().map((entry, i) => (
            <Message key={i} {...entry.message} />
          ))}
        </Timeline>

        {customer?.tier === 'premium' && <RefundTool />}
        <SearchOrdersTool />
      </>
    );
  }
}
tsx
import express from 'express';
import { createEngine } from 'aidk';
import { createSSEHandler } from 'aidk-express';
import { CustomerAgent } from './agents/customer';
import { loggingMiddleware, authMiddleware } from './middleware';

const app = express();

const engine = createEngine({
  middleware: {
    execute: [loggingMiddleware, authMiddleware],
    model: [tokenCountingMiddleware],
    tool: [auditMiddleware],
  },
});

app.post('/api/agent/stream', createSSEHandler({
  engine,
  getAgent: () => <CustomerAgent />,
  getContext: (req) => ({
    user: req.user,
    metadata: {
      tenantId: req.user.tenantId,
      support_tier: req.user.supportTier,
      sessionId: req.sessionID,
    },
  }),
}));

app.listen(3000);
tsx
import { Context } from 'aidk';

export const loggingMiddleware = async (args, envelope, next) => {
  const ctx = Context.get();
  console.log(`[${ctx.user.id}] Execution starting`);

  const start = Date.now();
  const result = await next();
  const duration = Date.now() - start;

  console.log(`[${ctx.user.id}] Completed in ${duration}ms`);
  return result;
};

export const tokenCountingMiddleware = async (args, envelope, next) => {
  const result = await next();

  await db.metrics.create({
    userId: Context.get().user.id,
    inputTokens: result.usage.promptTokens,
    outputTokens: result.usage.completionTokens,
  });

  return result;
};

Key Points:

  • Full production features
  • Middleware at every level
  • Context available everywhere
  • Real-time streaming to clients
  • Persistence and recovery
  • OpenTelemetry support

Choosing Your Level

LevelUse WhenComplexityFeatures
1: compile()Trying it out, minimal changesJSX only
2: run() + executorNeed control + multi-tick⭐⭐+ State, tools
3: run() managedBuilding from scratch⭐⭐+ Auto-execution
4: generateText()Want simplest APIDrop-in replacement
5: Full EngineProduction apps⭐⭐⭐⭐Everything

Next Steps

Released under the MIT License.