# Customize agents with Agent SDK An Agent SDK definition combines a model, a system prompt, and tools. The SDK uses these to respond to messages in a durable [session](../../aip/agent-stack/index.md#sessions). Follow the [getting started guide](../getting-started/index.md) to create and publish an agent before adding the features to your agent: * [System prompt](#system-prompt) * [Model](#model) * [Tools](#tools) * [Ontology interaction](#ontology-interaction) * [Agent state and creation arguments](#agent-state-and-creation-arguments) ## System prompt The `systemPrompt` option tells the agent how it should respond. Provide a function that returns text parts with `SystemPromptRenderResult.ready`. ```typescript import { SystemPromptRenderResult } from "@palantir/agents"; // Inside defineAgent({ ... }) systemPrompt: () => SystemPromptRenderResult.ready([ { type: "text", text: "You are a helpful agent..." }, ]), ``` For more system prompt customization options, see the [advanced customization guide](../advanced-customization/index.md#system-prompt). ## Model The `model` option determines which language model answers each request. Depending on what model was chosen at bootstrapping time, your template will have the corresponding model pre-filled. ```typescript import { Aliases } from "@osdk/functions"; import { anthropic } from "@palantir/agents"; // Inside defineAgent({ ... }): model: anthropic({ modelRid: Aliases.model("model").rid, modelSettings: { max_tokens: 4096 }, }), ``` The package also provides `openAi`, `openAiChat`, `google`, and `xAi` constructors. To update the model, import the desired model from the **Resource imports** sidebar and use the corresponding constructor. ![The resource imports panel shows the Models option under Add.](../../../assets/b7e7a8cf4470b5a02c29c53f2c440c70be22a755bf47836d6029581925ca727a.webp) After importing the model, you can use it in code through the alias it was imported with. For custom model implementations, state-based model selection, and provider settings, see the guide to [advanced model customization](../advanced-customization/index.md#model). ## Tools Tools let the model request information or actions during a session. Each tool has a name, description, and argument schema that the SDK presents to the model. When the model calls a tool, the SDK runs its `execute` function. Tools in the Agent SDK return context items. The context items will be rendered as that tool call's result for the next model request. For example, a weather tool can return a string context item. The item renders its `text` field for the model: ```typescript import { Message, RenderResult, UserMessagePart, zodContextItem, zodTool } from "@palantir/agents"; import { z } from "zod"; const StringContextItem = zodContextItem({ type: "string-result", dataSchema: z.object({ text: z.string() }), createArgsSchema: z.object({ text: z.string() }), create: args => ({ data: args }), render: ({ text }) => RenderResult.ready([ Message.user(UserMessagePart.text(text)) ]), }); const WeatherTool = zodTool({ name: "get_weather", description: "Get the weather for a city", argumentSchema: z.object({ city: z.string() }), execute: async ({ city }) => ({ contextItems: [{ contextItemType: StringContextItem.type, createArgs: { text: `Weather in ${city} is sunny.` }, }] }), }); // Inside defineAgent({ ... }): contextItemDefinitions: [StringContextItem], tools: () => [WeatherTool], ``` If an error is thrown during the execution of a tool, the failure will be rendered to the model on the next turn. See [advanced concepts](../advanced-customization/index.md#tools) for examples of tool results, long-running lookups, dynamic tool lists, and user interaction. ## Ontology interaction Use the [TypeScript OSDK](../../ontology-sdk/typescript-osdk/index.md) to read objects, apply actions, and execute functions from an agent. :::callout{theme="warning"} To use Ontology resources in your agent, you *must* import them from the **Resource imports** sidebar. Failure to do so will result in permissioning errors. ::: ### Apply an action An action lets the agent make an Ontology edit. To enable calling actions, **scoped mode** must be enabled for your agent. Navigate to the **Resource imports** sidebar and select **Scope settings**. ![The Resource imports sidebar shows the Scope settings control.](../../../assets/dbba97a4ad1c755f758ddc479ab1f1a31b381c117d9bacfd816953448ba1d44a.webp) Once there, turn on **Enable scoped mode**. ![The Scope settings panel shows Enable scoped mode turned on.](../../../assets/0b1c6a7a52943b315677da136328afe5969e5aeb6e9864730dbc4614295688c2.webp) Now, write a tool that calls an action when it executes: ```typescript import { assignTicket } from "@ontology/sdk"; import { getClient } from "@palantir/agents-core"; const AssignTicket = zodTool({ name: "assign_ticket", description: "Assign a support ticket to a user", argumentSchema: z.object({ ticketId: z.string(), assigneeId: z.string() }), execute: async ({ ticketId, assigneeId }) => { const client = getClient(); await client(assignTicket).applyAction({ ticketId, assigneeId }); return { contextItems: [ { contextItemType: StringContextItem.type, createArgs: { text: "Ticket assigned." }, }, ], events: [], }; }, }); ``` ### Call a function A function can compute a result without editing the Ontology. Return the result as a context item so that the model can see it: ```typescript import { getTicketSummary } from "@ontology/sdk"; import { getClient } from "@palantir/agents-core"; const SummarizeTicket = zodTool({ name: "summarize_ticket", description: "Summarize a support ticket", argumentSchema: z.object({ ticketId: z.string() }), execute: async ({ ticketId }) => { const client = getClient(); const summary = await client(getTicketSummary).executeFunction({ ticketId, }); return { contextItems: [ { contextItemType: StringContextItem.type, createArgs: { text: summary }, }, ], events: [], }; }, }); ``` ### Load object data into context Fetch an object through the OSDK and return its relevant properties in a context item. The SDK renders the item in the tool result for the next model request: ```typescript import { SupportTicket } from "@ontology/sdk"; import { getClient } from "@palantir/agents-core"; const GetTicket = zodTool({ name: "get_ticket", description: "Load a support ticket", argumentSchema: z.object({ ticketId: z.string() }), execute: async ({ ticketId }) => { const ticket = await getClient()(SupportTicket).fetchOne(ticketId); return { contextItems: [ { contextItemType: StringContextItem.type, createArgs: { text: `Ticket ${ticket.$primaryKey}: ${ticket.title} (${ticket.status})`, }, }, ], events: [], }; }, }); ``` For long-running object loads, use a [custom context item](../advanced-customization/index.md#custom-tool-loading-ui) to show progress while the tool waits. Replace these illustrative resource names and parameters with those generated for your Ontology. ## Agent state and creation arguments Each agent has its own agent state. Agent state is strongly typed and can be used to: * Render something about your agent and its current state in a UI * Hold values that are used in your tool calls * Dynamically derive the model, system prompt, or tools * Track agent progress and status Agents additionally can take in arguments when they are created. Set `createSessionArgsSchema` to declare your argument types. Arguments can be stored in agent state, which can then expose them to tools or your system prompt later on. ```typescript import { z } from "zod"; // Inside defineAgent({ ... }): agentStateSchema: z.object({ audience: z.string() }), createSessionArgsSchema: z.object({ audience: z.string() }), createSession: args => ({ agentState: { audience: args.audience } }), ``` To modify your agent state as your agent runs, see the guide to [custom events](../advanced-customization/index.md#custom-events).