Skip to main content
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, etc.) into provider-specific input formats (like OpenAI chat completions, Google PaLM input, etc). It uses the raw prompt configuration (TextConfig, ObjectConfig, etc.) and combines it with:
  • Model configuration (e.g., name, temperature, max tokens)
  • Tool definitions (functions to be called during inference)
  • Optional telemetry or metadata

Requirements

To create an adapter, you need to implement Adapter class from @agentmark-ai/prompt-core that defines the following methods:

Required Methods

  • adaptText(input, options, metadata)
  • adaptObject(input, options, metadata)
  • adaptImage(input, options)
  • adaptSpeech(input, options)
These methods are called by AgentMark when formatting a prompt. Here’s a basic example of a MyCustomAdapter:
import {
  Adapter,
  TextConfig,
  ImageConfig,
  ObjectConfig,
  PromptShape,
  SpeechConfig,
  AdaptOptions,
  PromptMetadata
} from "@agentmark-ai/prompt-core";

export class MyCustomAdapter<T extends PromptShape<T>> implements Adapter<T> {
  declare readonly __dict: T;

  adaptText(input: TextConfig, options: AdaptOptions, metadata: PromptMetadata): CustomReturnTypeText {
    // Your custom logic here
    // Return a value of type CustomReturnTypeText
    return "customTextOutput";
  }

  adaptObject<K extends KeysWithKind<T, "object"> & string>(input: ObjectConfig, options: AdaptOptions, metadata: PromptMetadata): CustomReturnTypeObject<T[K]["output"]> {
    // Your custom logic here
    // Return a value of type CustomReturnTypeObject<T[K]>
    return "customObjectOutput";
  }

  adaptImage(input: ImageConfig, options: AdaptOptions, metadata: PromptMetadata): CustomReturnTypeImage {
    // Your custom logic here
    // Return a value of type CustomReturnTypeImage
    return "customImageOutput";
  }

  adaptSpeech(input: SpeechConfig, options: AdaptOptions, metadata: PromptMetadata): CustomReturnTypeSpeech {
    // Your custom logic here
    // Return a value of type CustomReturnTypeSpeech
    return "customSpeechOutput";
  }
}
Each method must transform the AgentMark prompt config into the correct shape for your target provider.
The Adapter interface is defined as follows:
import { KeysWithKind, PromptMetadata, AdaptOptions } from "@agentmark-ai/prompt-core";

export interface Adapter<D extends PromptShape<D>> {
  readonly __dict: D;

  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,
    metadata: PromptMetadata
  ): any;

  adaptSpeech<K extends KeysWithKind<D, "speech"> & string>(
    input: SpeechConfig,
    options: AdaptOptions,
    metadata: PromptMetadata
  ): any;
}
Here D is the AgentMark type and K is the path of the prompt. You can then create a custom AgentMark client using your adapter:
import {
  AgentMark,
  KeysWithKind,
  Loader,
  ObjectPrompt,
  PromptFormatParams,
  PromptShape,
} from "@agentmark-ai/prompt-core";

// Required for type safety of object
export interface CustomObjectPrompt<
  T extends PromptShape<T>,
  A extends MyCustomAdapter<T>,
  K extends KeysWithKind<T, "object"> & string
> extends ObjectPrompt<T, A, K> {
  format({
    params
  }: PromptFormatParams<T[K]["input"]>): Promise<CustomReturnTypeObject<T[K]["output"]>>;
}

// Required for type safety
export interface CustomAgentmark<T extends PromptShape<T>>
  extends AgentMark<T, MyCustomAdapter<T>> {
  loadObjectPrompt<K extends KeysWithKind<T, "object"> & string>(
    pathOrPreloaded: K,
    options?: any
  ): Promise<CustomObjectPrompt<T, MyCustomAdapter<T>, K>>;
}

export function createCustomAgentMarkClient<D extends PromptShape<D>>(opts: {
  loader?: Loader<D>;
}): CustomAgentmark<D> {
  const adapter = new MyCustomAdapter<D>();

  return new AgentMark<D, MyCustomAdapter<D>>({
    loader: opts.loader,
    adapter,
  });
}

PromptShape is a type that represents the shape of a prompt object in AgentMark types. KeysWithKind is a type that represents the keys of a prompt object in AgentMark types with a specific kind (eg. "text", "object", "image", "speech"). For more information on AgentMark types, see the AgentMark types documentation.

Model Registry

A Model Registry allows you to define and manage different AI models that your adapter can use. This is useful for swapping models, configuring model-specific parameters, or routing prompts to different models based on certain criteria.

Creating a Model Registry

Here’s an example of how you might define a model registry and register a model:
class CustomModelRegistry {
  private models: Record<string, ModelFunctionCreator> = {};

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

  getModelFunction(name: string): ModelFunctionCreator {
    const fn = this.models[name];
    if (!fn) throw new Error("Model not found");
    return fn;
  }
}
Your adapter can then use this registry to look up model configurations when processing prompts.

Tools

Adapters accept native SDK tool objects directly as a Record<string, Tool>, a plain object that maps tool names to tool implementations. You pass this tools record when creating your AgentMark client:
import { createCustomAgentMarkClient } from "./my-custom-adapter";
import { mySearchTool, myCalculatorTool } from "./tools";

const client = createCustomAgentMarkClient({
  loader: myLoader,
  tools: {
    search: mySearchTool,
    calculator: myCalculatorTool,
  },
});
Your adapter should accept a tools parameter and implement a resolveTools() method that takes a list of tool name strings from the prompt frontmatter and looks them up in the provided tools record. In AgentMark prompt files, the tools frontmatter field is a string array of tool names:
---
tools:
  - search
  - calculator
---
When the adapter processes a prompt, it resolves each tool name against the tools record. See the AI SDK adapter source for a reference implementation of resolveTools().

Have Questions?

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