Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.agentmark.co/llms.txt

Use this file to discover all available pages before exploring further.

AgentMark uses adapters to convert its normalized prompt configuration (PromptShape) into model-specific input formats. This guide walks you through how to build a custom adapter, using the AI SDK adapter as a reference implementation.

What is an adapter?

An adapter implements methods to transform AgentMark prompt types (text, object, image, speech) into provider-specific input formats (OpenAI chat completions, Claude messages, etc.). It takes the raw prompt configuration (TextConfig, ObjectConfig, ImageConfig, SpeechConfig) and combines it with:
  • Model configuration (name, temperature, max tokens, etc.)
  • Tool definitions (functions to be called during inference)
  • Optional telemetry or metadata

Requirements

To create an adapter, implement the Adapter interface from @agentmark-ai/prompt-core:
export interface Adapter<D extends PromptShape<D>> {
  readonly __dict: D;
  readonly __name: string;

  adaptText<_K extends KeysWithKind<D, "text"> & string>(
    input: TextConfig,
    options: AdaptOptions,
    metadata: PromptMetadata
  ): any;

  adaptObject<_K extends KeysWithKind<D, "object"> & string>(
    input: ObjectConfig,
    options: AdaptOptions,
    metadata: PromptMetadata
  ): any;

  adaptImage<_K extends KeysWithKind<D, "image"> & string>(
    input: ImageConfig,
    options: AdaptOptions
  ): any;

  adaptSpeech<_K extends KeysWithKind<D, "speech"> & string>(
    input: SpeechConfig,
    options: AdaptOptions
  ): any;

  // Optional — adapters that support dev mode provide this.
  getDevServerFactory?(): (options: { port: number; client: any }) => Promise<any>;
}
Note the asymmetry: adaptText and adaptObject receive a third metadata: PromptMetadata argument; adaptImage and adaptSpeech do not.

Minimal adapter skeleton

import {
  Adapter,
  AdaptOptions,
  ImageConfig,
  KeysWithKind,
  ObjectConfig,
  PromptMetadata,
  PromptShape,
  SpeechConfig,
  TextConfig,
} from "@agentmark-ai/prompt-core";

export class MyCustomAdapter<T extends PromptShape<T>> implements Adapter<T> {
  declare readonly __dict: T;
  readonly __name = "my-custom-adapter";

  adaptText<_K extends KeysWithKind<T, "text"> & string>(
    input: TextConfig,
    options: AdaptOptions,
    metadata: PromptMetadata
  ) {
    // Transform AgentMark config into your provider's request shape.
    return { /* ... */ };
  }

  adaptObject<_K extends KeysWithKind<T, "object"> & string>(
    input: ObjectConfig,
    options: AdaptOptions,
    metadata: PromptMetadata
  ) {
    return { /* ... */ };
  }

  adaptImage<_K extends KeysWithKind<T, "image"> & string>(
    input: ImageConfig,
    options: AdaptOptions
  ) {
    return { /* ... */ };
  }

  adaptSpeech<_K extends KeysWithKind<T, "speech"> & string>(
    input: SpeechConfig,
    options: AdaptOptions
  ) {
    return { /* ... */ };
  }
}
Each method must transform the AgentMark prompt config into the correct shape for your target provider.

Creating a custom client

You can wrap AgentMark directly, or expose a factory that wires up your adapter:
import { AgentMark, Loader, PromptShape } from "@agentmark-ai/prompt-core";
import { MyCustomAdapter } from "./my-custom-adapter";

export function createCustomAgentMarkClient<D extends PromptShape<D>>(opts: {
  loader?: Loader<D>;
}) {
  return new AgentMark<D, MyCustomAdapter<D>>({
    loader: opts.loader,
    adapter: new MyCustomAdapter<D>(),
  });
}
PromptShape<D> describes the shape of your prompts (generated by npx agentmark build as agentmark.types.ts). KeysWithKind<D, "object"> extracts the keys whose prompt kind is object. See Type safety for details.

Model registry

A model registry lets you register AI model constructors and look them up by name during adaptText / adaptObject / etc. It’s useful for swapping providers or configuring per-model parameters.
class CustomModelRegistry {
  private models: Record<string, (name: string) => unknown> = {};

  register(modelName: string, creator: (name: string) => unknown) {
    this.models[modelName] = creator;
  }

  getModelFunction(name: string): (name: string) => unknown {
    const fn = this.models[name];
    if (!fn) throw new Error(`Model not registered: ${name}`);
    return fn;
  }
}
Your adapter’s constructor can accept this registry and look up model instances when processing prompts. See the AI SDK adapter source for a reference implementation.

Tools

Adapters accept native SDK tool objects as a Record<string, Tool> passed to createAgentMarkClient. Your adapter should implement a resolveTools() helper that takes the tool name strings from prompt frontmatter and looks them up in the provided tools record.
import { createCustomAgentMarkClient } from "./my-custom-adapter";
import { mySearchTool, myCalculatorTool } from "./tools";

const client = createCustomAgentMarkClient({
  loader,
  // If your adapter supports tools, accept them here and thread to the adapter.
});
AgentMark prompt files reference tools by name:
---
tools:
  - search
  - calculator
---
The adapter’s resolveTools() maps each name to its implementation before dispatching the LLM call. See the AI SDK adapter source for a reference implementation.

Have Questions?

We’re here to help! Choose the best way to reach us: