The agent library
@nx/agent is a standard library: NX source the
compiler carries. It declares the types for an AI agent, the reference documents it reads and the
tools it can call. Import it by name:
import "@nx/agent"
let assistant = <Agent name="support">Be brief.</Agent>The library holds types only. It has no functions and runs nothing: what a tool does, how its schemas are derived and how a run proceeds are up to the host that reads these values.
An agent
Section titled “An agent”An Agent is a record written as an element. Its body is its instructions, the system prompt:
import "@nx/agent"
let root() = { <Agent:markdown name="support" model="balanced" limits={ <AgentLimits maxSteps=6 /> }> You are the support assistant. Answer briefly. </Agent>}<Agent instructions="You are the support assistant. Answer briefly." limits=<AgentLimits maxSteps=6 /> model="balanced" name="support"/>| Type | Fields | Notes |
|---|---|---|
Agent |
name, description?, model?, documents?: Document+, tools?: Tool+, limits?: AgentLimits, content instructions |
instructions is required. NX does not interpret model; the host resolves it. |
Document |
title, content text |
Reference text sent to the model on every run, after the instructions. |
AgentLimits |
maxSteps?, maxToolCalls? |
A host applies its own caps too, and the lower value wins. |
Tool is abstract. Each concrete tool type says what a call does, and every tool takes an optional
model-facing name and description.
| Type | Fields | Notes |
|---|---|---|
Tool (abstract) |
name?, description? |
A host library extends it to add tool types of its own. |
FunctionTool |
function |
Exposes an NX function. Its parameters are the tool’s input and its result the output. |
WebSearchTool |
allowedDomains?: string+ |
Web search run by the model provider. |
HttpTool |
connection, method, path, arguments, maxCallsPerConversation? |
One operation on a connection. |
ToolContext (abstract) |
callId |
Values the host supplies to a tool’s function. |
FunctionTool.function is typed <function ... />: object*, so it takes any function and nothing
else. A string naming a function is rejected, and so is a record that only looks like a function
value:
import "@nx/agent"
let findPlans(teamSize:int): string* = { "Team" }let tool = <FunctionTool function="findPlans" />A function parameter typed ToolContext, or a type that extends it, is filled in by the host. It is
left out of the tool’s input, so the model never supplies it.
HTTP tools
Section titled “HTTP tools”An HttpTool is a fixed method and path on a connection. Only the arguments vary per call, and an
NX function computes them:
| Type | Fields | Notes |
|---|---|---|
Connection (abstract) |
name, description? |
An external service a tool can reach. |
HttpConnection |
baseUrl |
A service reached over HTTPS. The model never sees the address. |
HttpMethod |
get, post, put, patch, delete |
get makes the tool read-only. |
HttpParam |
name, value |
One named value. The host encodes it. |
HttpArguments |
pathParams?: HttpParam+, query?: HttpParam+, body?: object |
What an arguments function returns. |
HttpTool.arguments is typed <function ... />: HttpArguments: any parameters, but the function
must return HttpArguments. A function with another result is a compile error. body is object,
so it holds one value of any type, usually a record you declare. To send a list, wrap it in a
record.
A worked example
Section titled “A worked example”import "@nx/agent"
type Plan = { name:string seats:int monthlyPrice:int }type NewTicket = { subject:string priority:int }
let companyName = "Example"
/// Finds the plans that fit a team.let findPlans( /// Number of people who need a seat. teamSize: int, /// Upper price limit per month, in dollars. maxMonthlyPrice?: int): Plan* = { <Plan name="Team" seats={teamSize} monthlyPrice=20 /> }
let refundPolicy = <Document:markdown title="Refund policy"> Refunds are available within 30 days of purchase. </Document>
let shop = <HttpConnection name="shop" baseUrl="https://api.example.com" />
/// Looks up one order and returns its status.let lookupOrder( /// The order number from the customer's confirmation email. orderId: string): HttpArguments = <HttpArguments pathParams={ <HttpParam name="orderId" value={orderId} /> } />
/// Opens a support ticket for the customer.let openTicket( /// A one-line summary of the problem. subject: string): HttpArguments = <HttpArguments body={ <NewTicket subject={subject} priority=2 /> } />
let supportTools: Tool+ = { <WebSearchTool allowedDomains={ "docs.example.com" } /> <FunctionTool function={findPlans} /> <HttpTool connection={shop} method={HttpMethod.get} path="/orders/{orderId}" arguments={lookupOrder} /> <HttpTool connection={shop} method={HttpMethod.post} path="/tickets" arguments={openTicket} maxCallsPerConversation=1 />}
let supportAgent = <Agent:markdown name="support" model="balanced" documents={ refundPolicy } tools={supportTools} limits={ <AgentLimits maxSteps=6 /> }> You are the support assistant for @{companyName}. Answer from the documents and the documentation site. Offer a call when you cannot help. </Agent>
let root(): Agent = { supportAgent }Evaluated, root is a plain record. Each function field is a function value, which a host can
call by name with arguments it has checked against the function’s parameters.
Extending the library
Section titled “Extending the library”Tool, ToolContext and Connection are abstract so that a host library can extend them. A host
library imports @nx/agent like any module, and its subtypes are accepted wherever the base type
is expected:
import "@nx/agent"
export type RecordSearchTool extends Tool = { recordKind: string maxResults: int = 5}
export type ChatToolContext extends ToolContext = { conversationId: string contactEmail?: string}
export abstract external component <FlowStep id:string />export external component <AgentStep extends FlowStep agent?: Agent content prompt: string/>nxlang typegen @nx/agent --language typescript --output <dir> generates the library’s types.
Generated code for a library that references them imports from the package @nx-lang/agent
(TypeScript) or qualifies them with the namespace NxLang.Agent (C#).
What the host decides
Section titled “What the host decides”The library says what an agent is, not how it runs. A host decides:
- which models
modelmay name, and what an omittedmodelmeans; - each tool’s default
nameanddescription, and its input and output schemas; - how tool calls are validated, executed, retried and limited;
- how a
ToolContextis filled in, and how anHttpConnectionis authenticated.
A JavaScript host does not have to write the common part of that itself. The npm package
@nx-lang/agent, which is unstable as this library is, derives each tool’s name, description and
schemas, runs a tool’s function under a budget and builds an HTTP tool’s request. See
Running an agent in a host.
The library source
Section titled “The library source”// The NX agent library: product-neutral types for declaring an AI agent, its reference documents// and its tools. Import it with `import "@nx/agent"`.//// UNSTABLE. These declarations may change incompatibly in any NX release, including a patch// release. See https://nxlang.org/reference/libraries/agent.//// The library holds types only. What a tool does, how its schemas are derived and how a run// proceeds are the host's business.
/// Limits on one run of an agent. A host applies its own caps as well, and the lower value wins.export type AgentLimits = { maxSteps?: int /// The most model calls one run may make. maxToolCalls?: int /// The most tool calls one run may make.}
/// Reference text sent to the model on every run, kept separate from the agent's instructions.export type Document = { title: string /// Names the document in traces and citations. Unique among one agent's documents. content text: string /// The document's text, written as the element body.}
/// Something the model can call during a run. Each concrete tool type says what the call does.export abstract type Tool = { name?: string /// The model-facing name, in snake_case. Each tool type has a default. description?: string /// The model-facing description. Each tool type has a default.}
/// A reusable definition of an agent: who answers, with what reference text and which tools.export type Agent = { name: string /// A stable identifier for the agent, shown in traces. description?: string /// What the agent is for. Shown to operators and not sent to the model. model?: string /// The model to run. NX does not interpret it; the host resolves it and may restrict /// it. documents?: Document+ /// Reference text sent to the model on every run, after the instructions. tools?: Tool+ /// The tools the model may call. limits?: AgentLimits /// Limits on one run. content instructions: string /// How the agent behaves: the system prompt, written as the element body.}
/// Exposes an NX function to the model. The tool's input schema comes from the function's/// parameters and its output schema from the function's result type.export type FunctionTool extends Tool = { function: <function ... />: object* /// The function the tool calls. Its name and doc comment are the tool's default /// name and description.}
/// Web search run by the model provider. The default name is `web_search`.export type WebSearchTool extends Tool = { allowedDomains?: string+ /// The only domains the search may draw on. Without it the search is unrestricted.}
/// Values the host supplies to a tool's function. A function parameter of this type, or of a type/// that extends it, is filled in by the host and left out of the tool's input schema, so the model/// never supplies it. A host extends this type with the values it provides.export abstract type ToolContext = { callId: string /// Identifies this tool call and stays the same when the call is retried, so it can serve as an /// idempotency key.}
/// The method of an HTTP request.export type HttpMethod = get | post | put | patch | delete
/// An external service a tool can reach. The model never sees a connection's address.export abstract type Connection = { name: string /// Identifies the connection in traces. description?: string /// What the service is. Shown to operators and not sent to the model.}
/// A service reached over HTTPS.export type HttpConnection extends Connection = { baseUrl: string /// The URL every request to the service starts with. It must use `https`.}
/// One named value of an HTTP request. The host encodes the value.export type HttpParam = { name: string /// The parameter's name. value: string /// The parameter's value, not encoded.}
/// The variable parts of one HTTP call, returned by an [HttpTool]'s `arguments` function.export type HttpArguments = { pathParams?: HttpParam+ /// Values for the `{name}` placeholders in the tool's path. query?: HttpParam+ /// Query string parameters, in order. body?: object /// The request body, which the host sends as JSON. Usually a record the program declares.}
/// One operation on a connection: a fixed method and path. Only the arguments vary per call.export type HttpTool extends Tool = { connection: HttpConnection /// The service the tool calls. method: HttpMethod /// The request method. `get` makes the tool read-only; any other method is a write. path: string /// The path under the connection's base URL. It may hold `{name}` placeholders.
/// A function that returns the call's [HttpArguments]. Its parameters are the tool's input /// schema, and its name and doc comment are the tool's default name and description. arguments: <function ... />: HttpArguments maxCallsPerConversation?: int /// Maximum calls to this tool per conversation. A host may impose a lower cap.}See also
Section titled “See also”- Reference: Modules
- Reference: Function types