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.
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: