Ploy
Ploy
Agent SDK

createAgent()

Configure and create an AI agent with a single function call.

createAgent()

createAgent(config) is the main entry point of the Agent SDK. It takes an AgentConfig and returns a Ploy<PloyEnv> export that handles fetch requests, timer events, and the durable agent workflow.

AgentConfig

import { createAgent } from "@meetploy/agent-sdk";

export default createAgent({
	// Required
	systemPrompt: "You are a helpful assistant.",
	handle: myHandler,

	// Optional
	model: "auto",
	features: { memory: true, artifacts: true, scheduling: true, mcp: true },
	tools: [myTool],
	hooks: {
		onRunComplete(ctx, response) {
			/* ... */
		},
	},
	maxSteps: 30,
});

systemPrompt

The system prompt sent to the AI on every turn. Can be a static string or a function that returns a per-user prompt:

// Static
systemPrompt: "You are a helpful assistant.";

// Dynamic per-user
systemPrompt: async (userId) => {
	const prefs = await loadPreferences(userId);
	return `You are a helpful assistant. Language: ${prefs.language}.`;
};

The SDK automatically appends the user's stored memories to the system prompt.

handle

Your custom request handler. This is where you parse incoming requests (HTTP, webhooks, etc.), call agent.handleMessage(), and return a response:

async function handle(req: Request, env: PloyEnv, agent: AgentContext) {
	const body = (await req.json()) as {
		userId: string;
		chatId: string;
		text: string;
	};

	const messenger = new MyMessenger();

	await agent.handleMessage({
		userId: body.userId,
		chatId: body.chatId,
		platform: "http",
		text: body.text,
		messenger,
	});

	return Response.json({ ok: true });
}

The AgentContext passed to your handler provides:

PropertyTypeDescription
handleMessage(params) => Promise<void>Enqueue a user message for processing
commandsAgentCommandsBuilt-in commands (reset, debug, tools, MCP)
stateStateManagerDirect access to the state binding
envPloyEnvThe full Ploy environment bindings

model

The model name passed to the AI gateway. Defaults to "auto".

model: "gpt-4o";

features

Toggle built-in tool categories. All default to true:

features: {
  memory: true,      // memory_set, memory_get, memory_delete, memory_list
  artifacts: true,   // artifact_create
  scheduling: true,  // schedule_task
  mcp: true,         // mcp_call_tool (when MCP servers are installed)
}

tools

Array of custom tool definitions. Use defineTool() for type-safe args:

import { defineTool } from "@meetploy/agent-sdk";

const myTool = defineTool({
	name: "lookup_user",
	description: "Look up a user by ID",
	parameters: {
		type: "object",
		properties: { userId: { type: "string" } },
		required: ["userId"],
	},
	async execute(args, ctx) {
		// args.userId is typed as string
		const data = await ctx.state.get(`user:${args.userId}`);
		return data ?? "User not found";
	},
});

See Tools for full documentation.

hooks

Lifecycle hooks that fire during agent execution. Every hook receives a HookContext with access to env, state, and an execute() function for calling tools:

hooks: {
  async onRunComplete(ctx, response) {
    await ctx.state.set(`last_response:${ctx.userId}`, response);
  },
  async onRunError(ctx, error) {
    console.error(`Agent error for ${ctx.userId}: ${error.message}`);
  },
}

See Hooks for the full list.

maxSteps

Maximum iterations of the AI-call-then-tool-execution loop per run. Prevents runaway tool loops. Defaults to 30.

maxSteps: 50;

Messenger Interface

The Messenger you pass to handleMessage() defines how the agent sends responses back to the user. Implement it for your platform:

import type { Messenger } from "@meetploy/agent-sdk";

class TelegramMessenger implements Messenger {
	sendMessage(chatId: string, text: string) {
		return fetch(`https://api.telegram.org/bot${token}/sendMessage`, {
			method: "POST",
			body: JSON.stringify({ chat_id: chatId, text }),
		}).then(() => undefined);
	}

	sendDocument(chatId: string, filename: string, content: string | Uint8Array) {
		// Upload file to Telegram
	}

	sendTypingIndicator(chatId: string) {
		return fetch(`https://api.telegram.org/bot${token}/sendChatAction`, {
			method: "POST",
			body: JSON.stringify({ chat_id: chatId, action: "typing" }),
		}).then(() => undefined);
	}
}

Return Value

createAgent() returns a Ploy<PloyEnv> object with:

  • fetch -- Handles HTTP requests (health check + delegates to your handle function)
  • timer -- Handles scheduled task triggers
  • workflows.agent_run -- The durable agent tick loop

The SDK owns the timer and workflows handlers. You do not need to define these yourself -- only implement the handle function.

Next Steps

How is this guide?

Last updated on